feat: Revamp @formbricks/js package (#2299)

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Shubham Palriwala
2024-03-28 16:02:08 +05:30
committed by GitHub
parent a9e45c0086
commit 0f95f1c98c
49 changed files with 507 additions and 372 deletions

View File

@@ -47,7 +47,6 @@ export default function AppPage({}) {
userId,
attributes,
});
window.formbricks = formbricks;
}
// Connect next.js router to Formbricks

View File

@@ -1,4 +1,3 @@
import jsPackageJson from "@/../../packages/js/package.json";
import clsx from "clsx";
import { useState } from "react";
import { IoLogoHtml5, IoLogoNpm } from "react-icons/io5";
@@ -68,7 +67,7 @@ if (typeof window !== "undefined") {
var t = document.createElement("script");
t.type = "text/javascript";
t.async = true;
t.src = "https://unpkg.com/@formbricks/js@^${jsPackageJson.version}/dist/index.umd.js";
t.src = "https://unpkg.com/@formbricks/js@^1.6.5/dist/index.umd.js";
var e = document.getElementsByTagName("script")[0];
e.parentNode.insertBefore(t, e);
setTimeout(function(){

View File

@@ -1,6 +1,5 @@
"use client";
import jsPackageJson from "@/../../packages/js/package.json";
import packageJson from "@/package.json";
import Link from "next/link";
import "prismjs/themes/prism.css";
@@ -109,7 +108,7 @@ if (typeof window !== "undefined") {
</p>
<CodeBlock language="js">{`<!-- START Formbricks Surveys -->
<script type="text/javascript">
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://unpkg.com/@formbricks/js@^${jsPackageJson.version}/dist/index.umd.js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: "${environmentId}", apiHost: "${window.location.protocol}//${window.location.host}"})},500)}();
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://unpkg.com/@formbricks/js@^1.6.5/dist/index.umd.js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: "${environmentId}", apiHost: "${window.location.protocol}//${window.location.host}"})},500)}();
</script>
<!-- END Formbricks Surveys -->`}</CodeBlock>
<p className="text-lg font-semibold text-slate-800">You&apos;re done 🎉</p>

View File

@@ -23,12 +23,11 @@ interface SetupInstructionsOnboardingProps {
export default function SetupInstructionsOnboarding({
environmentId,
webAppUrl,
jsPackageVersion,
}: SetupInstructionsOnboardingProps) {
const [activeTab, setActiveId] = useState(tabs[0].id);
const htmlSnippet = `<!-- START Formbricks Surveys -->
<script type="text/javascript">
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://unpkg.com/@formbricks/js@^${jsPackageVersion}/dist/index.umd.js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: "${environmentId}", apiHost: "${window.location.protocol}//${window.location.host}"})},500)}();
!function(){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://unpkg.com/@formbricks/js@^1.6.5/dist/index.umd.js";var e=document.getElementsByTagName("script")[0];e.parentNode.insertBefore(t,e),setTimeout(function(){window.formbricks.init({environmentId: "${environmentId}", apiHost: "${window.location.protocol}//${window.location.host}"})},500)}();
</script>
<!-- END Formbricks Surveys -->`;

View File

@@ -1,78 +1,22 @@
// DEPRECATED - This file is deprecated and will be removed in the future
// Deprecated since 22-03-2024
// This endpoint has been deprecated. Please use the new endpoint /api/packages/js instead.
import { responses } from "@/app/lib/api/response";
import fs from "fs/promises";
import { NextRequest, NextResponse } from "next/server";
import { WEBAPP_URL } from "@formbricks/lib/constants";
import { getEnvironment } from "@formbricks/lib/environment/service";
import { TEnvironment } from "@formbricks/types/environment";
export async function GET(req: NextRequest) {
let path: string;
let append = "";
switch (req.nextUrl.searchParams.get("module")) {
case "surveys":
path = `../../packages/surveys/dist/index.umd.js`;
break;
case "question-date":
path = `../../packages/surveys/dist/question-date.umd.js`;
break;
case "js":
case null:
const format = ["umd", "iife"].includes(req.nextUrl.searchParams.get("format")!)
? req.nextUrl.searchParams.get("format")!
: "umd";
path = `../../packages/js/dist/index.${format}.js`;
try {
append = await handleInit(req);
} catch (error) {
return responses.badRequestResponse(error.message);
}
break;
default:
return responses.badRequestResponse(
"unknown module requested. module must be of type 'js' (default), 'surveys' or 'question-date'"
);
}
export async function GET() {
try {
const jsCode = await loadAndAppendCode(path, append);
return new NextResponse(jsCode, {
headers: {
"Content-Type": "application/javascript",
"Cache-Control": "public, s-maxage=600, max-age=1800, stale-while-revalidate=600, stale-if-error=600",
"Access-Control-Allow-Origin": "*",
return responses.goneResponse(
"This endpoint has been deprecated. Please use the new endpoint /api/packages/<package-name>",
{
"x-deprecated": "true",
"x-deprecated-date": "22-03-2024",
"x-deprecated-redirect": `${WEBAPP_URL}/api/packages/js`,
},
});
true
);
} catch (error) {
return responses.internalServerErrorResponse("file not found");
return responses.internalServerErrorResponse("this endpoint is not available");
}
}
async function handleInit(req: NextRequest) {
const environmentId = req.nextUrl.searchParams.get("environmentId");
if (environmentId) {
let environment: TEnvironment | null;
try {
environment = await getEnvironment(environmentId);
} catch (error) {
throw new Error(`error fetching environment: ${error.message}`);
}
if (!environment) {
throw new Error("environment not found");
}
if (environment) {
return `formbricks.init({environmentId: "${environmentId}", apiHost: "${WEBAPP_URL}"});`;
}
}
return "";
}
async function loadAndAppendCode(path: string, append: string): Promise<string> {
let jsCode = await fs.readFile(path, "utf-8");
return jsCode + append;
}

View File

@@ -0,0 +1,42 @@
import { responses } from "@/app/lib/api/response";
import fs from "fs/promises";
import { NextRequest } from "next/server";
export async function GET(_: NextRequest, { params }: { params: { slug: string } }) {
let path: string;
const packageRequested = params["package"];
switch (packageRequested) {
case "js-core":
path = `../../packages/js-core/dist/index.umd.cjs`;
break;
case "surveys":
path = `../../packages/surveys/dist/index.umd.cjs`;
break;
default:
return responses.notFoundResponse(
"package",
packageRequested,
true,
"public, s-maxage=600, max-age=1800, stale-while-revalidate=600, stale-if-error=600"
);
}
try {
const packageSrcCode = await fs.readFile(path, "utf-8");
return new Response(packageSrcCode, {
headers: {
"Content-Type": "application/javascript",
"Cache-Control": "public, s-maxage=600, max-age=1800, stale-while-revalidate=600, stale-if-error=600",
"Access-Control-Allow-Origin": "*",
},
});
} catch (error) {
console.error("Error reading file:", error);
return responses.internalServerErrorResponse(
"file not found:",
true,
"public, s-maxage=600, max-age=1800, stale-while-revalidate=600, stale-if-error=600"
);
}
}

View File

@@ -9,6 +9,7 @@ export interface ApiSuccessResponse<T = { [key: string]: any }> {
export interface ApiErrorResponse {
code:
| "not_found"
| "gone"
| "bad_request"
| "internal_server_error"
| "unauthorized"
@@ -28,6 +29,19 @@ const corsHeaders = {
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
const goneResponse = (message: string, details?: { [key: string]: string }, cors: boolean = false) =>
Response.json(
{
code: "gone",
message,
details: details || {},
} as ApiErrorResponse,
{
status: 410,
...(cors && { headers: corsHeaders }),
}
);
const badRequestResponse = (message: string, details?: { [key: string]: string }, cors: boolean = false) =>
Response.json(
{
@@ -69,8 +83,18 @@ const methodNotAllowedResponse = (
}
);
const notFoundResponse = (resourceType: string, resourceId: string, cors: boolean = false) =>
Response.json(
const notFoundResponse = (
resourceType: string,
resourceId: string,
cors: boolean = false,
cache: string = "private, no-store"
) => {
const headers = {
...(cors && corsHeaders),
"Cache-Control": cache,
};
return Response.json(
{
code: "not_found",
message: `${resourceType} not found`,
@@ -81,9 +105,10 @@ const notFoundResponse = (resourceType: string, resourceId: string, cors: boolea
} as ApiErrorResponse,
{
status: 404,
...(cors && { headers: corsHeaders }),
headers,
}
);
};
const notAuthenticatedResponse = (cors: boolean = false) =>
Response.json(
@@ -177,6 +202,7 @@ const tooManyRequestsResponse = (
};
export const responses = {
goneResponse,
badRequestResponse,
internalServerErrorResponse,
missingFieldResponse,

View File

@@ -3,6 +3,7 @@ export const loginRoute = (url: string) => url === "/api/auth/callback/credentia
export const signupRoute = (url: string) => url === "/api/v1/users";
export const clientSideApiRoute = (url: string): boolean => {
if (url.includes("/api/packages/")) return true;
if (url.includes("/api/v1/js/actions")) return true;
if (url.includes("/api/v1/client/storage")) return true;
const regex = /^\/api\/v\d+\/client\//;

View File

@@ -80,5 +80,6 @@ export const config = {
"/environments/:path*",
"/api/auth/signout",
"/auth/login",
"/api/packages/:path*",
],
};

View File

@@ -21,7 +21,11 @@ const nextConfig = {
serverComponentsExternalPackages: ["@aws-sdk"],
instrumentationHook: true,
outputFileTracingIncludes: {
"app/api/js": ["../../packages/**/*"],
"app/api/packages/": [
"../../packages/js/dist/*",
"../../packages/js-core/dist/*",
"../../packages/surveys/dist/*",
],
},
},
transpilePackages: ["@formbricks/database", "@formbricks/ee", "@formbricks/ui", "@formbricks/lib"],

View File

@@ -1,6 +1,6 @@
{
"name": "@formbricks/web",
"version": "1.6.1",
"version": "1.7.0",
"private": true,
"scripts": {
"clean": "rimraf .turbo node_modules .next",

View File

@@ -13,14 +13,16 @@
"files": [
"dist"
],
"source": "./src/index.ts",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"type": "module",
"source": "src/index.ts",
"main": "dist/index.umd.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.umd.js"
"import": "./dist/index.js",
"require": "./dist/index.umd.cjs",
"types": "./dist/index.d.ts"
}
},
"scripts": {

View File

@@ -11,7 +11,7 @@ export default defineConfig({
// Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, "src/index.ts"),
name: "formbricks-api",
formats: ["cjs", "es", "umd"],
formats: ["es", "umd"],
// the proper extensions will be added
fileName: "index",
},

View File

@@ -0,0 +1,3 @@
module.exports = {
extends: ["turbo", "prettier"],
};

4
packages/js-core/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules
.vscode
build
dist

9
packages/js-core/LICENSE Normal file
View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) 2023 Formbricks GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,36 @@
# Formbricks Browser JS Library
[![npm package](https://img.shields.io/npm/v/@formbricks/js?style=flat-square)](https://www.npmjs.com/package/@formbricks/js)
[![MIT License](https://img.shields.io/badge/License-MIT-red.svg?style=flat-square)](https://opensource.org/licenses/MIT)
Please see [Formbricks Docs](https://formbricks.com/docs).
Specifically, [Quickstart/Implementation details](https://formbricks.com/docs/getting-started/quickstart-in-app-survey).
## What is Formbricks
Formbricks is your go-to solution for in-product micro-surveys that will supercharge your product experience! 🚀 For more information please check out [formbricks.com](https://formbricks.com).
## How to use this library
1. Install the Formbricks package inside your project using npm:
```bash
npm install -s @formbricks/js
```
2. Import Formbricks and initialize the widget in your main component (e.g., App.tsx or App.js):
```javascript
import formbricks from "@formbricks/js";
if (typeof window !== "undefined") {
formbricks.init({
environmentId: "your-environment-id",
apiHost: "https://app.formbricks.com",
});
}
```
Replace your-environment-id with your actual environment ID. You can find your environment ID in the **Setup Checklist** in the Formbricks settings.
For more detailed guides for different frameworks, check out our [Framework Guides](https://formbricks.com/docs/getting-started/framework-guides).

View File

@@ -2,12 +2,12 @@
<script type="text/javascript">
!(function () {
var t = document.createElement("script");
(t.type = "text/javascript"), (t.async = !0), (t.src = "./dist/index.umd.js");
(t.type = "text/javascript"), (t.async = !0), (t.src = "http://localhost:3000/api/packages/js-core");
var e = document.getElementsByTagName("script")[0];
e.parentNode.insertBefore(t, e),
setTimeout(function () {
window.formbricks.init({
environmentId: "cltflogdl000aiw7m8esl9kjc",
formbricks.init({
environmentId: "clu9xfvdn0009vhyg9b6858gc",
apiHost: "http://localhost:3000",
});
}, 500);

View File

@@ -0,0 +1,57 @@
{
"name": "@formbricks/js-core",
"private": true,
"type": "module",
"license": "MIT",
"version": "1.0.0",
"description": "Js core for Formbricks that contains the logic for executing the @formbricks/js library and is loaded asynchronously over the Formbricks API.",
"homepage": "https://formbricks.com",
"repository": {
"type": "git",
"url": "https://github.com/formbricks/formbricks"
},
"keywords": [
"Formbricks",
"surveys",
"experience management"
],
"sideEffects": false,
"files": [
"dist"
],
"source": "src/index.ts",
"main": "dist/index.umd.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.umd.cjs",
"types": "./dist/index.d.ts"
}
},
"scripts": {
"dev": "vite build --watch --mode dev",
"build": "tsc && vite build",
"build:dev": "tsc && vite build --mode dev",
"go": "vite build --watch --mode dev",
"lint": "eslint ./src --fix",
"clean": "rimraf .turbo node_modules dist coverage"
},
"author": "Formbricks <hola@formbricks.com>",
"devDependencies": {
"@babel/preset-env": "^7.24.0",
"@babel/preset-typescript": "^7.23.3",
"@formbricks/api": "workspace:*",
"@formbricks/lib": "workspace:*",
"@formbricks/tsconfig": "workspace:*",
"@formbricks/types": "workspace:*",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"eslint-config-prettier": "^9.1.0",
"eslint-config-turbo": "1.10.12",
"terser": "^5.29.1",
"vite": "^5.1.6",
"vite-plugin-dts": "^3.7.3"
}
}

View File

@@ -0,0 +1,82 @@
import { SurveyInlineProps, SurveyModalProps } from "@formbricks/types/formbricksSurveys";
import { TJsConfigInput } from "@formbricks/types/js";
import { trackAction } from "./lib/actions";
import { getApi } from "./lib/api";
import { CommandQueue } from "./lib/commandQueue";
import { ErrorHandler } from "./lib/errors";
import { initialize } from "./lib/initialize";
import { Logger } from "./lib/logger";
import { checkPageUrl } from "./lib/noCodeActions";
import { logoutPerson, resetPerson, setPersonAttribute, setPersonUserId } from "./lib/person";
declare global {
interface Window {
formbricksSurveys: {
renderSurveyInline: (props: SurveyInlineProps) => void;
renderSurveyModal: (props: SurveyModalProps) => void;
};
}
}
const logger = Logger.getInstance();
logger.debug("Create command queue");
const queue = new CommandQueue();
const init = async (initConfig: TJsConfigInput) => {
console.log("init in formbricks-js-core");
ErrorHandler.init(initConfig.errorHandler);
queue.add(false, initialize, initConfig);
await queue.wait();
};
const setUserId = async (): Promise<void> => {
queue.add(true, setPersonUserId);
await queue.wait();
};
const setEmail = async (email: string): Promise<void> => {
setAttribute("email", email);
await queue.wait();
};
const setAttribute = async (key: string, value: any): Promise<void> => {
queue.add(true, setPersonAttribute, key, value);
await queue.wait();
};
const logout = async (): Promise<void> => {
queue.add(true, logoutPerson);
await queue.wait();
};
const reset = async (): Promise<void> => {
queue.add(true, resetPerson);
await queue.wait();
};
const track = async (name: string, properties: any = {}): Promise<void> => {
queue.add<any>(true, trackAction, name, properties);
await queue.wait();
};
const registerRouteChange = async (): Promise<void> => {
queue.add(true, checkPageUrl);
await queue.wait();
};
const formbricks = {
init,
setUserId,
setEmail,
setAttribute,
track,
logout,
reset,
registerRouteChange,
getApi,
};
export type FormbricksType = typeof formbricks;
export default formbricks as FormbricksType;

View File

@@ -38,8 +38,8 @@ export const triggerSurvey = async (survey: TSurvey): Promise<void> => {
logger.debug("Survey display skipped based on displayPercentage.");
return; // skip displaying the survey
}
await renderWidget(survey);
}
await renderWidget(survey);
};
const renderWidget = async (survey: TSurvey) => {
@@ -266,14 +266,12 @@ export const removeWidgetContainer = (): void => {
};
const loadFormbricksSurveysExternally = (): Promise<typeof window.formbricksSurveys> => {
const formbricksSurveysScriptSrc = import.meta.env.FORMBRICKS_SURVEYS_SCRIPT_SRC;
return new Promise((resolve, reject) => {
if (window.formbricksSurveys) {
resolve(window.formbricksSurveys);
} else {
const script = document.createElement("script");
script.src = formbricksSurveysScriptSrc;
script.src = `${config.get().apiHost}/api/packages/surveys`;
script.async = true;
script.onload = () => resolve(window.formbricksSurveys);
script.onerror = (error) => {

1
packages/js-core/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@@ -0,0 +1,10 @@
{
"extends": "@formbricks/tsconfig/js-library.json",
"include": ["src", "package.json"],
"compilerOptions": {
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
}
}

View File

@@ -0,0 +1,29 @@
import { resolve } from "path";
import { defineConfig } from "vite";
import dts from "vite-plugin-dts";
import webPackageJson from "../../apps/web/package.json";
const config = () => {
return defineConfig({
define: {
"import.meta.env.VERSION": JSON.stringify(webPackageJson.version),
},
build: {
emptyOutDir: false, // keep the dist folder to avoid errors with pnpm go when folder is empty during build
minify: "terser",
sourcemap: true,
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, "src/index.ts"),
name: "formbricks",
formats: ["es", "umd"],
// the proper extensions will be added
fileName: "index",
},
},
plugins: [dts({ rollupTypes: true })],
});
};
export default config;

View File

@@ -1,7 +1,7 @@
{
"name": "@formbricks/js",
"license": "MIT",
"version": "1.7.2",
"version": "1.7.3",
"description": "Formbricks-js allows you to connect your app to Formbricks, display surveys and trigger events.",
"homepage": "https://formbricks.com",
"repository": {
@@ -17,15 +17,15 @@
"files": [
"dist"
],
"type": "module",
"source": "src/index.ts",
"main": "dist/index.js",
"module": "dist/index.mjs",
"main": "dist/index.umd.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"unpkg": "./dist/index.umd.js",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.umd.js",
"import": "./dist/index.js",
"require": "./dist/index.umd.cjs",
"types": "./dist/index.d.ts"
}
},
@@ -39,20 +39,7 @@
},
"author": "Formbricks <hola@formbricks.com>",
"devDependencies": {
"@babel/core": "^7.24.0",
"@babel/preset-env": "^7.24.0",
"@babel/preset-typescript": "^7.23.3",
"@formbricks/api": "workspace:*",
"@formbricks/lib": "workspace:*",
"@formbricks/surveys": "workspace:*",
"@formbricks/tsconfig": "workspace:*",
"@formbricks/types": "workspace:*",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"cross-env": "^7.0.3",
"eslint-config-prettier": "^9.1.0",
"eslint-config-turbo": "1.10.12",
"isomorphic-fetch": "^3.0.0",
"terser": "^5.29.1",
"vite": "^5.1.6",
"vite-plugin-dts": "^3.7.3"

View File

@@ -1,81 +1,77 @@
import { SurveyInlineProps, SurveyModalProps } from "@formbricks/types/formbricksSurveys";
import { TJsConfigInput } from "@formbricks/types/js";
import { trackAction } from "./lib/actions";
import { getApi } from "./lib/api";
import { CommandQueue } from "./lib/commandQueue";
import { ErrorHandler } from "./lib/errors";
import { initialize } from "./lib/initialize";
import { Logger } from "./lib/logger";
import { checkPageUrl } from "./lib/noCodeActions";
import { logoutPerson, resetPerson, setPersonAttribute, setPersonUserId } from "./lib/person";
declare global {
interface Window {
formbricksSurveys: {
renderSurveyInline: (props: SurveyInlineProps) => void;
renderSurveyModal: (props: SurveyModalProps) => void;
};
formbricks: any;
}
}
const logger = Logger.getInstance();
let sdkLoadingPromise: Promise<void> | null = null;
let isErrorLoadingSdk = false;
logger.debug("Create command queue");
const queue = new CommandQueue();
async function loadSDK(apiHost: string) {
if (!window.formbricks) {
const res = await fetch(`${apiHost}/api/packages/js-core`);
if (!res.ok) throw new Error("Failed to load Formbricks SDK");
const sdkScript = await res.text();
const scriptTag = document.createElement("script");
scriptTag.innerHTML = sdkScript;
document.head.appendChild(scriptTag);
const init = async (initConfig: TJsConfigInput) => {
ErrorHandler.init(initConfig.errorHandler);
queue.add(false, initialize, initConfig);
await queue.wait();
return new Promise<void>((resolve, reject) => {
const checkInterval = setInterval(() => {
if (window.formbricks) {
clearInterval(checkInterval);
resolve();
}
}, 100);
setTimeout(() => {
clearInterval(checkInterval);
reject(new Error("Formbricks SDK loading timed out"));
}, 10000);
});
}
}
const formbricksProxyHandler: ProxyHandler<any> = {
get(_target, prop, _receiver) {
return async (...args: any[]) => {
if (!window.formbricks && !sdkLoadingPromise && !isErrorLoadingSdk) {
const { apiHost } = args[0];
sdkLoadingPromise = loadSDK(apiHost).catch((error) => {
console.error(`🧱 Formbricks - Error loading SDK: ${error}`);
sdkLoadingPromise = null;
isErrorLoadingSdk = true;
return;
});
}
if (isErrorLoadingSdk) {
return;
}
if (sdkLoadingPromise) {
await sdkLoadingPromise;
}
if (!window.formbricks) {
throw new Error("Formbricks SDK is not available");
}
if (typeof window.formbricks[prop] !== "function") {
console.error(`🧱 Formbricks - SDK does not support method ${String(prop)}`);
return;
}
try {
return window.formbricks[prop](...args);
return;
} catch (error) {
console.error(error);
throw error;
}
};
},
};
const setUserId = async (): Promise<void> => {
queue.add(true, setPersonUserId);
await queue.wait();
};
const formbricks = new Proxy({}, formbricksProxyHandler);
const setEmail = async (email: string): Promise<void> => {
setAttribute("email", email);
await queue.wait();
};
const setAttribute = async (key: string, value: any): Promise<void> => {
queue.add(true, setPersonAttribute, key, value);
await queue.wait();
};
const logout = async (): Promise<void> => {
queue.add(true, logoutPerson);
await queue.wait();
};
const reset = async (): Promise<void> => {
queue.add(true, resetPerson);
await queue.wait();
};
const track = async (name: string, properties: any = {}): Promise<void> => {
queue.add<any>(true, trackAction, name, properties);
await queue.wait();
};
const registerRouteChange = async (): Promise<void> => {
queue.add(true, checkPageUrl);
await queue.wait();
};
const formbricks = {
init,
setUserId,
setEmail,
setAttribute,
track,
logout,
reset,
registerRouteChange,
getApi,
};
export type FormbricksType = typeof formbricks;
export default formbricks as FormbricksType;
export default formbricks;

View File

@@ -2,6 +2,8 @@
"extends": "@formbricks/tsconfig/js-library.json",
"include": ["src", "package.json"],
"compilerOptions": {
"module": "ESNext",
"declaration": true,
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,

View File

@@ -2,20 +2,8 @@ import { resolve } from "path";
import { defineConfig } from "vite";
import dts from "vite-plugin-dts";
import surveysPackageJson from "../surveys/package.json";
import packageJson from "./package.json";
const config = ({ mode }) => {
const isDevelopment = mode === "dev";
const formbricksSurveysScriptSrc = isDevelopment
? "http://localhost:3003/index.umd.js"
: `https://unpkg.com/@formbricks/surveys@~${surveysPackageJson.version}/dist/index.umd.js`;
const config = () => {
return defineConfig({
define: {
"import.meta.env.FORMBRICKS_SURVEYS_SCRIPT_SRC": JSON.stringify(formbricksSurveysScriptSrc),
"import.meta.env.VERSION": JSON.stringify(packageJson.version),
},
build: {
emptyOutDir: false, // keep the dist folder to avoid errors with pnpm go when folder is empty during build
minify: "terser",
@@ -23,8 +11,8 @@ const config = ({ mode }) => {
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(__dirname, "src/index.ts"),
name: "formbricks",
formats: ["cjs", "es", "umd", "iife"],
name: "formbricksJsWrapper",
formats: ["es", "umd"],
// the proper extensions will be added
fileName: "index",
},

View File

@@ -1,37 +1,36 @@
{
"name": "@formbricks/surveys",
"license": "MIT",
"version": "1.7.2",
"description": "Formbricks-surveys is a helper library to embed surveys into your application",
"version": "1.0.0",
"private": true,
"type": "module",
"description": "Formbricks-surveys is a helper library to embed surveys into your application.",
"homepage": "https://formbricks.com",
"repository": {
"type": "git",
"url": "https://github.com/formbricks/formbricks"
},
"sideEffects": false,
"source": "./src/index.ts",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"source": "src/index.ts",
"main": "dist/index.umd.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.umd.js"
"import": "./dist/index.js",
"require": "./dist/index.umd.cjs",
"types": "./dist/index.d.ts"
}
},
"scripts": {
"dev": "vite build --watch --mode dev",
"serve": "serve dist -p 3003",
"build": "pnpm run build:surveys && pnpm run build:question-date",
"build:dev": "pnpm run build:surveys:dev && pnpm run build:question-date:dev",
"build:surveys": "tsc && SURVEYS_PACKAGE_BUILD=surveys vite build",
"build:surveys:dev": "tsc && SURVEYS_PACKAGE_BUILD=surveys vite build --mode dev",
"build:question-date": "tsc && SURVEYS_PACKAGE_BUILD=question-date vite build",
"build:question-date:dev": "tsc && SURVEYS_PACKAGE_BUILD=question-date vite build --mode dev",
"go": "concurrently \"pnpm dev\" \"pnpm serve\"",
"build": "tsc && vite build",
"build:dev": "tsc && vite build --mode dev",
"go": "vite build --watch --mode dev",
"lint": "eslint . --ext .ts,.js,.tsx,.jsx",
"preview": "vite preview",
"clean": "rimraf .turbo node_modules dist"

View File

@@ -11,6 +11,8 @@ import { getLocalizedValue } from "@formbricks/lib/i18n/utils";
import { TResponseData, TResponseTtc } from "@formbricks/types/responses";
import type { TSurveyDateQuestion } from "@formbricks/types/surveys";
import { initDatePicker } from "../../sideload/question-date/index";
interface DateQuestionProps {
question: TSurveyDateQuestion;
value: string | number | string[];
@@ -45,43 +47,11 @@ export default function DateQuestion({
useTtc(question.id, ttc, setTtc, startTime, setStartTime);
const defaultDate = value ? new Date(value as string) : undefined;
const datePickerScriptSrc = import.meta.env.DATE_PICKER_SCRIPT_SRC;
useEffect(() => {
// Check if the DatePicker has already been loaded
if (!window.initDatePicker) {
const script = document.createElement("script");
script.src = datePickerScriptSrc;
script.async = true;
document.body.appendChild(script);
script.onload = () => {
// Initialize the DatePicker once the script is loaded
window.initDatePicker(document.getElementById("date-picker-root")!, defaultDate, question.format);
setLoading(false);
};
return () => {
document.body.removeChild(script);
};
} else {
// If already loaded, remove the date picker and re-initialize it
setLoading(false);
const datePickerContainer = document.getElementById("datePickerContainer");
if (datePickerContainer) {
datePickerContainer.remove();
}
window.initDatePicker(document.getElementById("date-picker-root")!, defaultDate, question.format);
}
initDatePicker(document.getElementById("date-picker-root")!, defaultDate, question.format);
setLoading(false);
return () => {};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [question.format, question.id]);

View File

@@ -21,12 +21,10 @@ const addStylesToDom = () => {
}
};
const init = (element: HTMLElement, selectedDate?: Date, format?: string) => {
export const initDatePicker = (element: HTMLElement, selectedDate?: Date, format?: string) => {
addStylesToDom();
const container = document.createElement("div");
container.id = "datePickerContainer";
element.appendChild(container);
render(<Question defaultDate={selectedDate} format={format} />, container);
};
window.initDatePicker = init;

View File

@@ -9,8 +9,8 @@
/* 2 */
border-color: theme("borderColor.DEFAULT", currentColor);
/* 2 */
font-family: inherit, Arial, Helvetica, sans-serif;
font-family: Arial, Helvetica, sans-serif;
font-size: 1em;
}
#fbjs ::before,

View File

@@ -4,36 +4,27 @@ import { defineConfig, loadEnv } from "vite";
import dts from "vite-plugin-dts";
import tsconfigPaths from "vite-tsconfig-paths";
import packageJson from "./package.json";
const buildPackage = process.env.SURVEYS_PACKAGE_BUILD || "surveys";
const entryPoint = buildPackage === "surveys" ? "src/index.ts" : "src/sideload/question-date/index.tsx";
const name = buildPackage === "surveys" ? "formbricks-surveys" : "formbricks-question-date";
const fileName = buildPackage === "surveys" ? "index" : "question-date";
const config = ({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
const isDevelopment = mode === "dev";
const datePickerScriptSrc = isDevelopment
? "http://localhost:3003/question-date.umd.js"
: `https://app.formbricks.com/api/js?module=question-date`; // HOTFIX: Need to be changed to a better solution that is versioned
return defineConfig({
define: {
"process.env": env,
"import.meta.env.DATE_PICKER_SCRIPT_SRC": JSON.stringify(datePickerScriptSrc),
},
build: {
emptyOutDir: false,
minify: "terser",
sourcemap: true,
rollupOptions: {
output: {
inlineDynamicImports: true,
},
},
lib: {
entry: resolve(__dirname, entryPoint),
name,
formats: ["cjs", "es", "umd"],
fileName,
entry: resolve(__dirname, "src/index.ts"),
name: "formbricksSurveys",
formats: ["es", "umd"],
fileName: "index",
},
},
plugins: [preact(), dts({ rollupTypes: true }), tsconfigPaths()],

159
pnpm-lock.yaml generated
View File

@@ -576,9 +576,21 @@ importers:
packages/js:
devDependencies:
'@babel/core':
specifier: ^7.24.0
version: 7.24.0
'@formbricks/tsconfig':
specifier: workspace:*
version: link:../tsconfig
terser:
specifier: ^5.29.1
version: 5.29.1
vite:
specifier: ^5.1.6
version: 5.1.6(terser@5.29.1)
vite-plugin-dts:
specifier: ^3.7.3
version: 3.7.3(typescript@5.3.3)(vite@5.1.6)
packages/js-core:
devDependencies:
'@babel/preset-env':
specifier: ^7.24.0
version: 7.24.0(@babel/core@7.24.0)
@@ -591,9 +603,6 @@ importers:
'@formbricks/lib':
specifier: workspace:*
version: link:../lib
'@formbricks/surveys':
specifier: workspace:*
version: link:../surveys
'@formbricks/tsconfig':
specifier: workspace:*
version: link:../tsconfig
@@ -606,18 +615,12 @@ importers:
'@typescript-eslint/parser':
specifier: ^7.2.0
version: 7.2.0(eslint@8.57.0)(typescript@5.3.3)
cross-env:
specifier: ^7.0.3
version: 7.0.3
eslint-config-prettier:
specifier: ^9.1.0
version: 9.1.0(eslint@8.57.0)
eslint-config-turbo:
specifier: 1.10.12
version: 1.10.12(eslint@8.57.0)
isomorphic-fetch:
specifier: ^3.0.0
version: 3.0.0
terser:
specifier: ^5.29.1
version: 5.29.1
@@ -1876,7 +1879,7 @@ packages:
resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.17.0
'@babel/types': 7.24.0
jsesc: 2.5.2
source-map: 0.5.7
dev: true
@@ -1885,7 +1888,7 @@ packages:
resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.9
'@babel/types': 7.24.0
'@jridgewell/gen-mapping': 0.3.3
'@jridgewell/trace-mapping': 0.3.20
jsesc: 2.5.2
@@ -1895,14 +1898,14 @@ packages:
resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/helper-builder-binary-assignment-operator-visitor@7.22.15:
resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.9
'@babel/types': 7.24.0
dev: true
/@babel/helper-compilation-targets@7.23.6:
@@ -1911,7 +1914,7 @@ packages:
dependencies:
'@babel/compat-data': 7.23.5
'@babel/helper-validator-option': 7.23.5
browserslist: 4.22.2
browserslist: 4.23.0
lru-cache: 5.1.1
semver: 6.3.1
dev: true
@@ -1970,29 +1973,29 @@ packages:
resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/template': 7.22.15
'@babel/types': 7.23.6
'@babel/template': 7.24.0
'@babel/types': 7.24.0
dev: true
/@babel/helper-hoist-variables@7.22.5:
resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/helper-member-expression-to-functions@7.23.0:
resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/helper-module-imports@7.22.15:
resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/helper-module-transforms@7.23.3(@babel/core@7.23.6):
@@ -2027,7 +2030,7 @@ packages:
resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/helper-plugin-utils@7.22.5:
@@ -2068,21 +2071,21 @@ packages:
resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/helper-skip-transparent-expression-wrappers@7.22.5:
resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/helper-split-export-declaration@7.22.6:
resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/helper-string-parser@7.23.4:
@@ -2104,17 +2107,17 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-function-name': 7.23.0
'@babel/template': 7.23.9
'@babel/types': 7.23.9
'@babel/template': 7.24.0
'@babel/types': 7.24.0
dev: true
/@babel/helpers@7.23.6:
resolution: {integrity: sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/template': 7.22.15
'@babel/traverse': 7.23.6
'@babel/types': 7.23.6
'@babel/template': 7.24.0
'@babel/traverse': 7.24.0
'@babel/types': 7.24.0
transitivePeerDependencies:
- supports-color
dev: true
@@ -2143,15 +2146,7 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.23.6
dev: true
/@babel/parser@7.23.9:
resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.23.9
'@babel/types': 7.24.0
dev: true
/@babel/parser@7.24.0:
@@ -2295,7 +2290,7 @@ packages:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.24.0
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-plugin-utils': 7.24.0
dev: true
/@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0):
@@ -2379,7 +2374,7 @@ packages:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.24.0
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-plugin-utils': 7.24.0
dev: true
/@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.0):
@@ -2496,7 +2491,7 @@ packages:
dependencies:
'@babel/core': 7.24.0
'@babel/helper-plugin-utils': 7.24.0
'@babel/template': 7.23.9
'@babel/template': 7.24.0
dev: true
/@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.24.0):
@@ -2647,7 +2642,7 @@ packages:
dependencies:
'@babel/core': 7.24.0
'@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0)
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-plugin-utils': 7.24.0
'@babel/helper-simple-access': 7.22.5
dev: true
@@ -2849,9 +2844,9 @@ packages:
'@babel/core': 7.24.0
'@babel/helper-annotate-as-pure': 7.22.5
'@babel/helper-module-imports': 7.22.15
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-plugin-utils': 7.24.0
'@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0)
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0):
@@ -2935,7 +2930,7 @@ packages:
'@babel/core': 7.24.0
'@babel/helper-annotate-as-pure': 7.22.5
'@babel/helper-create-class-features-plugin': 7.23.6(@babel/core@7.24.0)
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-plugin-utils': 7.24.0
'@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0)
dev: true
@@ -3080,7 +3075,7 @@ packages:
dependencies:
'@babel/core': 7.24.0
'@babel/helper-plugin-utils': 7.24.0
'@babel/types': 7.23.9
'@babel/types': 7.24.0
esutils: 2.0.3
dev: true
@@ -3091,7 +3086,7 @@ packages:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.24.0
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-plugin-utils': 7.24.0
'@babel/helper-validator-option': 7.23.5
'@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0)
'@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0)
@@ -3120,17 +3115,8 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.23.5
'@babel/parser': 7.23.6
'@babel/types': 7.23.6
dev: true
/@babel/template@7.23.9:
resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/code-frame': 7.23.5
'@babel/parser': 7.23.9
'@babel/types': 7.23.9
'@babel/parser': 7.24.0
'@babel/types': 7.24.0
dev: true
/@babel/template@7.24.0:
@@ -3152,8 +3138,8 @@ packages:
'@babel/helper-function-name': 7.23.0
'@babel/helper-hoist-variables': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/parser': 7.23.6
'@babel/types': 7.23.6
'@babel/parser': 7.24.0
'@babel/types': 7.24.0
debug: 4.3.4
globals: 11.12.0
transitivePeerDependencies:
@@ -3170,8 +3156,8 @@ packages:
'@babel/helper-function-name': 7.23.0
'@babel/helper-hoist-variables': 7.22.5
'@babel/helper-split-export-declaration': 7.22.6
'@babel/parser': 7.23.6
'@babel/types': 7.23.6
'@babel/parser': 7.24.0
'@babel/types': 7.24.0
debug: 4.3.4
globals: 11.12.0
transitivePeerDependencies:
@@ -3213,15 +3199,6 @@ packages:
to-fast-properties: 2.0.0
dev: true
/@babel/types@7.23.9:
resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-string-parser': 7.23.4
'@babel/helper-validator-identifier': 7.22.20
to-fast-properties: 2.0.0
dev: true
/@babel/types@7.24.0:
resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
engines: {node: '>=6.9.0'}
@@ -9227,20 +9204,20 @@ packages:
/@types/babel__generator@7.6.8:
resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
dependencies:
'@babel/types': 7.23.6
'@babel/types': 7.24.0
dev: true
/@types/babel__template@7.4.4:
resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
dependencies:
'@babel/parser': 7.23.6
'@babel/types': 7.23.6
'@babel/parser': 7.24.0
'@babel/types': 7.24.0
dev: true
/@types/babel__traverse@7.20.4:
resolution: {integrity: sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==}
dependencies:
'@babel/types': 7.23.9
'@babel/types': 7.24.0
dev: true
/@types/bcryptjs@2.4.6:
@@ -10141,7 +10118,7 @@ packages:
/@vue/compiler-core@3.3.13:
resolution: {integrity: sha512-bwi9HShGu7uaZLOErZgsH2+ojsEdsjerbf2cMXPwmvcgZfVPZ2BVZzCVnwZBxTAYd6Mzbmf6izcUNDkWnBBQ6A==}
dependencies:
'@babel/parser': 7.23.6
'@babel/parser': 7.24.0
'@vue/shared': 3.3.13
estree-walker: 2.0.2
source-map-js: 1.0.2
@@ -11004,6 +10981,7 @@ packages:
electron-to-chromium: 1.4.615
node-releases: 2.0.14
update-browserslist-db: 1.0.13(browserslist@4.22.2)
dev: false
/browserslist@4.23.0:
resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
@@ -11608,7 +11586,7 @@ packages:
/core-js-compat@3.34.0:
resolution: {integrity: sha512-4ZIyeNbW/Cn1wkMMDy+mvrRUxrwFNjKwbhCfQpDd+eLgYipDqp8oGFGtLmhh18EDPKA0g3VUBYOxQGGwvWLVpA==}
dependencies:
browserslist: 4.22.2
browserslist: 4.23.0
dev: true
/core-util-is@1.0.3:
@@ -11639,14 +11617,6 @@ packages:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
dev: true
/cross-env@7.0.3:
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
hasBin: true
dependencies:
cross-spawn: 7.0.3
dev: true
/cross-spawn@5.1.0:
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
dependencies:
@@ -12116,6 +12086,7 @@ packages:
/electron-to-chromium@1.4.615:
resolution: {integrity: sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==}
dev: false
/electron-to-chromium@1.4.690:
resolution: {integrity: sha512-+2OAGjUx68xElQhydpcbqH50hE8Vs2K6TkAeLhICYfndb67CVH0UsZaijmRUE3rHlIxU1u0jxwhgVe6fK3YANA==}
@@ -14291,15 +14262,6 @@ packages:
- utf-8-validate
dev: true
/isomorphic-fetch@3.0.0:
resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==}
dependencies:
node-fetch: 2.7.0(encoding@0.1.13)
whatwg-fetch: 3.6.20
transitivePeerDependencies:
- encoding
dev: true
/isomorphic-ws@4.0.1(ws@8.16.0):
resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==}
peerDependencies:
@@ -19747,6 +19709,7 @@ packages:
browserslist: 4.22.2
escalade: 3.1.1
picocolors: 1.0.0
dev: false
/update-browserslist-db@1.0.13(browserslist@4.23.0):
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
@@ -20265,10 +20228,6 @@ packages:
iconv-lite: 0.6.3
dev: true
/whatwg-fetch@3.6.20:
resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
dev: true
/whatwg-mimetype@4.0.0:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}