@hexclave/shared 1.0.2 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/unified-prompts/reminders.js +4 -3
- package/dist/ai/unified-prompts/reminders.js.map +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.d.ts +3 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.d.ts.map +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js +217 -30
- package/dist/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js.map +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-index.d.ts.map +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-index.js +1 -0
- package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-index.js.map +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.d.ts +18 -6
- package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.js +23 -8
- package/dist/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.js.map +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.js +1 -1
- package/dist/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.js.map +1 -1
- package/dist/config/schema.d.ts +63 -63
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +5 -5
- package/dist/config/schema.js.map +1 -1
- package/dist/config-authoring.d.ts +4 -4
- package/dist/config-authoring.d.ts.map +1 -1
- package/dist/config-authoring.js +2 -2
- package/dist/config-authoring.js.map +1 -1
- package/dist/config-rendering.d.ts +4 -4
- package/dist/config-rendering.d.ts.map +1 -1
- package/dist/config-rendering.js +19 -18
- package/dist/config-rendering.js.map +1 -1
- package/dist/esm/ai/unified-prompts/reminders.js +4 -3
- package/dist/esm/ai/unified-prompts/reminders.js.map +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.d.ts +3 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.d.ts.map +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js +216 -31
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.js.map +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-index.d.ts.map +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-index.js +1 -0
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-index.js.map +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.d.ts +18 -6
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.js +23 -8
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.js.map +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.js +1 -1
- package/dist/esm/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.js.map +1 -1
- package/dist/esm/config/schema.d.ts +63 -63
- package/dist/esm/config/schema.d.ts.map +1 -1
- package/dist/esm/config/schema.js +5 -5
- package/dist/esm/config/schema.js.map +1 -1
- package/dist/esm/config-authoring.d.ts +4 -4
- package/dist/esm/config-authoring.d.ts.map +1 -1
- package/dist/esm/config-authoring.js +2 -2
- package/dist/esm/config-authoring.js.map +1 -1
- package/dist/esm/config-rendering.d.ts +4 -4
- package/dist/esm/config-rendering.d.ts.map +1 -1
- package/dist/esm/config-rendering.js +15 -14
- package/dist/esm/config-rendering.js.map +1 -1
- package/dist/esm/helpers/vault/client-side.d.ts.map +1 -1
- package/dist/esm/helpers/vault/client-side.js.map +1 -1
- package/dist/esm/helpers/vault/server-side.d.ts.map +1 -1
- package/dist/esm/helpers/vault/server-side.js.map +1 -1
- package/dist/esm/hexclave-config-file.d.ts +15 -0
- package/dist/esm/hexclave-config-file.d.ts.map +1 -0
- package/dist/esm/{stack-config-file.js → hexclave-config-file.js} +7 -7
- package/dist/esm/hexclave-config-file.js.map +1 -0
- package/dist/esm/hooks/use-async-callback.js +1 -1
- package/dist/esm/hooks/use-async-external-store.js +1 -1
- package/dist/esm/hooks/use-strict-memo.js +1 -1
- package/dist/esm/interface/admin-metrics.d.ts +8 -8
- package/dist/esm/interface/admin-metrics.js.map +1 -1
- package/dist/esm/interface/client-interface.js +2 -2
- package/dist/esm/interface/client-interface.js.map +1 -1
- package/dist/esm/interface/conversations.d.ts +32 -32
- package/dist/esm/interface/crud/current-user.d.ts +9 -9
- package/dist/esm/interface/crud/email-outbox.d.ts +200 -200
- package/dist/esm/interface/crud/products.d.ts +13 -13
- package/dist/esm/interface/crud/products.d.ts.map +1 -1
- package/dist/esm/interface/crud/project-api-keys.d.ts +4 -4
- package/dist/esm/interface/crud/project-permissions.js +5 -5
- package/dist/esm/interface/crud/project-permissions.js.map +1 -1
- package/dist/esm/interface/crud/projects.d.ts +36 -36
- package/dist/esm/interface/crud/team-member-profiles.d.ts +18 -18
- package/dist/esm/interface/crud/team-permissions.js +5 -5
- package/dist/esm/interface/crud/team-permissions.js.map +1 -1
- package/dist/esm/interface/crud/transactions.d.ts +6 -6
- package/dist/esm/interface/crud/transactions.d.ts.map +1 -1
- package/dist/esm/interface/crud/users.d.ts +12 -12
- package/dist/esm/interface/page-component-versions.js +107 -107
- package/dist/esm/interface/page-component-versions.js.map +1 -1
- package/dist/esm/interface/webhooks.d.ts +2 -2
- package/dist/esm/known-errors.d.ts +2 -2
- package/dist/esm/known-errors.js +4 -4
- package/dist/esm/known-errors.js.map +1 -1
- package/dist/esm/schema-fields.d.ts +17 -7
- package/dist/esm/schema-fields.d.ts.map +1 -1
- package/dist/esm/schema-fields.js +26 -16
- package/dist/esm/schema-fields.js.map +1 -1
- package/dist/esm/sessions.d.ts +7 -7
- package/dist/esm/utils/crypto.d.ts.map +1 -1
- package/dist/esm/utils/crypto.js.map +1 -1
- package/dist/esm/utils/currency-constants.d.ts +6 -0
- package/dist/esm/utils/currency-constants.d.ts.map +1 -1
- package/dist/esm/utils/currency-constants.js.map +1 -1
- package/dist/esm/utils/dev-env-state-path.d.ts +3 -3
- package/dist/esm/utils/dev-env-state-path.d.ts.map +1 -1
- package/dist/esm/utils/dev-env-state-path.js +4 -4
- package/dist/esm/utils/dev-env-state-path.js.map +1 -1
- package/dist/esm/utils/errors.js +2 -2
- package/dist/esm/utils/errors.js.map +1 -1
- package/dist/esm/utils/esbuild.d.ts.map +1 -1
- package/dist/esm/utils/esbuild.js +0 -1
- package/dist/esm/utils/esbuild.js.map +1 -1
- package/dist/esm/utils/featurebase.d.ts +3 -3
- package/dist/esm/utils/featurebase.d.ts.map +1 -1
- package/dist/esm/utils/featurebase.js +15 -15
- package/dist/esm/utils/featurebase.js.map +1 -1
- package/dist/esm/utils/fs.js +6 -6
- package/dist/esm/utils/fs.js.map +1 -1
- package/dist/esm/utils/globals.d.ts.map +1 -1
- package/dist/esm/utils/globals.js +10 -10
- package/dist/esm/utils/globals.js.map +1 -1
- package/dist/esm/utils/jwt.d.ts.map +1 -1
- package/dist/esm/utils/jwt.js +3 -3
- package/dist/esm/utils/jwt.js.map +1 -1
- package/dist/esm/utils/redirect-urls.d.ts +3 -3
- package/dist/esm/utils/redirect-urls.d.ts.map +1 -1
- package/dist/esm/utils/redirect-urls.js +5 -5
- package/dist/esm/utils/redirect-urls.js.map +1 -1
- package/dist/esm/utils/urls.js.map +1 -1
- package/dist/helpers/vault/client-side.d.ts.map +1 -1
- package/dist/helpers/vault/client-side.js.map +1 -1
- package/dist/helpers/vault/server-side.d.ts.map +1 -1
- package/dist/helpers/vault/server-side.js.map +1 -1
- package/dist/hexclave-config-file.d.ts +15 -0
- package/dist/hexclave-config-file.d.ts.map +1 -0
- package/dist/{stack-config-file.js → hexclave-config-file.js} +8 -8
- package/dist/hexclave-config-file.js.map +1 -0
- package/dist/hooks/use-async-callback.js +1 -1
- package/dist/hooks/use-async-external-store.js +1 -1
- package/dist/hooks/use-strict-memo.js +1 -1
- package/dist/interface/admin-metrics.d.ts +8 -8
- package/dist/interface/admin-metrics.js.map +1 -1
- package/dist/interface/client-interface.js +2 -2
- package/dist/interface/client-interface.js.map +1 -1
- package/dist/interface/conversations.d.ts +32 -32
- package/dist/interface/crud/current-user.d.ts +9 -9
- package/dist/interface/crud/email-outbox.d.ts +200 -200
- package/dist/interface/crud/products.d.ts +13 -13
- package/dist/interface/crud/products.d.ts.map +1 -1
- package/dist/interface/crud/project-api-keys.d.ts +4 -4
- package/dist/interface/crud/project-permissions.js +5 -5
- package/dist/interface/crud/project-permissions.js.map +1 -1
- package/dist/interface/crud/projects.d.ts +36 -36
- package/dist/interface/crud/team-member-profiles.d.ts +18 -18
- package/dist/interface/crud/team-permissions.js +5 -5
- package/dist/interface/crud/team-permissions.js.map +1 -1
- package/dist/interface/crud/transactions.d.ts +6 -6
- package/dist/interface/crud/transactions.d.ts.map +1 -1
- package/dist/interface/crud/users.d.ts +12 -12
- package/dist/interface/page-component-versions.js +107 -107
- package/dist/interface/page-component-versions.js.map +1 -1
- package/dist/interface/webhooks.d.ts +2 -2
- package/dist/known-errors.d.ts +2 -2
- package/dist/known-errors.js +4 -4
- package/dist/known-errors.js.map +1 -1
- package/dist/schema-fields.d.ts +17 -7
- package/dist/schema-fields.d.ts.map +1 -1
- package/dist/schema-fields.js +26 -16
- package/dist/schema-fields.js.map +1 -1
- package/dist/sessions.d.ts +7 -7
- package/dist/utils/crypto.d.ts.map +1 -1
- package/dist/utils/crypto.js.map +1 -1
- package/dist/utils/currency-constants.d.ts +6 -0
- package/dist/utils/currency-constants.d.ts.map +1 -1
- package/dist/utils/currency-constants.js.map +1 -1
- package/dist/utils/dev-env-state-path.d.ts +3 -3
- package/dist/utils/dev-env-state-path.d.ts.map +1 -1
- package/dist/utils/dev-env-state-path.js +5 -5
- package/dist/utils/dev-env-state-path.js.map +1 -1
- package/dist/utils/errors.js +2 -2
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/esbuild.d.ts.map +1 -1
- package/dist/utils/esbuild.js +0 -1
- package/dist/utils/esbuild.js.map +1 -1
- package/dist/utils/featurebase.d.ts +3 -3
- package/dist/utils/featurebase.d.ts.map +1 -1
- package/dist/utils/featurebase.js +15 -15
- package/dist/utils/featurebase.js.map +1 -1
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/globals.d.ts.map +1 -1
- package/dist/utils/globals.js +10 -10
- package/dist/utils/globals.js.map +1 -1
- package/dist/utils/jwt.d.ts.map +1 -1
- package/dist/utils/jwt.js +3 -3
- package/dist/utils/jwt.js.map +1 -1
- package/dist/utils/redirect-urls.d.ts +3 -3
- package/dist/utils/redirect-urls.d.ts.map +1 -1
- package/dist/utils/redirect-urls.js +5 -5
- package/dist/utils/redirect-urls.js.map +1 -1
- package/dist/utils/urls.js.map +1 -1
- package/package.json +2 -1
- package/src/ai/image-limits.ts +62 -0
- package/src/ai/llms/llms.ts +36 -0
- package/src/ai/unified-prompts/reminders.ts +27 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/ai-setup-prompt.ts +1047 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/brain.ts +5 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/cli-help.ts +5 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/config-docs.ts +5 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/custom-components-instructions.ts +5 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/dashboard-instructions.ts +5 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/docs-index.ts +80 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/docs-json.generated.ts +322 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/openapi-specs.ts +5 -0
- package/src/ai/unified-prompts/skill-site-prompt-parts/sdk-interface-source.ts +5 -0
- package/src/ai/unified-prompts/skill-site-prompt.ts +72 -0
- package/src/apps/apps-config.ts +177 -0
- package/src/apps/apps-ui.tsx +112 -0
- package/src/config/README.md +154 -0
- package/src/config/db-sync-mappings.ts +2293 -0
- package/src/config/format.ts +388 -0
- package/src/config/migrate-catalogs-to-product-lines.ts +475 -0
- package/src/config/schema-fuzzer.test.ts +377 -0
- package/src/config/schema.ts +1507 -0
- package/src/config-authoring.test.ts +52 -0
- package/src/config-authoring.ts +37 -0
- package/src/config-rendering.ts +142 -0
- package/src/crud.tsx +275 -0
- package/src/global.d.ts +1 -0
- package/src/helpers/emails.ts +250 -0
- package/src/helpers/init-prompt.ts +39 -0
- package/src/helpers/password.ts +16 -0
- package/src/helpers/production-mode.ts +58 -0
- package/src/helpers/support-sla.test.ts +124 -0
- package/src/helpers/support-sla.ts +93 -0
- package/src/helpers/vault/client-side.ts +92 -0
- package/src/helpers/vault/server-side.ts +153 -0
- package/src/hexclave-config-file.ts +120 -0
- package/src/hooks/use-async-callback.tsx +43 -0
- package/src/hooks/use-async-external-store.tsx +24 -0
- package/src/hooks/use-hash.tsx +14 -0
- package/src/hooks/use-hover.tsx +88 -0
- package/src/hooks/use-strict-memo.tsx +157 -0
- package/src/index.ts +17 -0
- package/src/interface/admin-interface.ts +1043 -0
- package/src/interface/admin-metrics.ts +214 -0
- package/src/interface/client-interface.test.ts +765 -0
- package/src/interface/client-interface.ts +2586 -0
- package/src/interface/conversations.ts +109 -0
- package/src/interface/crud/analytics.ts +11 -0
- package/src/interface/crud/connected-accounts.ts +52 -0
- package/src/interface/crud/contact-channels.ts +74 -0
- package/src/interface/crud/current-user.ts +72 -0
- package/src/interface/crud/email-outbox.ts +263 -0
- package/src/interface/crud/email-templates.ts +50 -0
- package/src/interface/crud/emails.ts +22 -0
- package/src/interface/crud/internal-api-keys.ts +69 -0
- package/src/interface/crud/invoices.ts +36 -0
- package/src/interface/crud/items.ts +24 -0
- package/src/interface/crud/notification-preferences.ts +33 -0
- package/src/interface/crud/oauth-providers.ts +91 -0
- package/src/interface/crud/products.ts +42 -0
- package/src/interface/crud/project-api-keys.ts +100 -0
- package/src/interface/crud/project-permissions.ts +118 -0
- package/src/interface/crud/projects.ts +229 -0
- package/src/interface/crud/session-replays.ts +85 -0
- package/src/interface/crud/sessions.ts +66 -0
- package/src/interface/crud/sign-up-rules.ts +12 -0
- package/src/interface/crud/svix-token.ts +20 -0
- package/src/interface/crud/team-invitation-details.ts +22 -0
- package/src/interface/crud/team-invitation.ts +35 -0
- package/src/interface/crud/team-member-profiles.ts +61 -0
- package/src/interface/crud/team-memberships.ts +56 -0
- package/src/interface/crud/team-permissions.ts +119 -0
- package/src/interface/crud/teams.ts +142 -0
- package/src/interface/crud/transactions.ts +131 -0
- package/src/interface/crud/users.ts +185 -0
- package/src/interface/handler-urls.ts +74 -0
- package/src/interface/page-component-versions.ts +1702 -0
- package/src/interface/server-interface.ts +1146 -0
- package/src/interface/webhooks.ts +28 -0
- package/src/known-errors.tsx +2031 -0
- package/src/local-emulator.ts +5 -0
- package/src/payments/payment-methods.ts +167 -0
- package/src/payments/stripe-limits.ts +18 -0
- package/src/plans.ts +107 -0
- package/src/schema-fields.ts +944 -0
- package/src/sessions.ts +310 -0
- package/src/utils/api-keys.tsx +122 -0
- package/src/utils/arrays.tsx +248 -0
- package/src/utils/auth-methods.ts +8 -0
- package/src/utils/base64.tsx +24 -0
- package/src/utils/booleans.tsx +34 -0
- package/src/utils/browser-compat.tsx +17 -0
- package/src/utils/bytes.tsx +280 -0
- package/src/utils/caches.tsx +280 -0
- package/src/utils/cel-fields.ts +92 -0
- package/src/utils/cloud-hosts.tsx +92 -0
- package/src/utils/compile-time.tsx +11 -0
- package/src/utils/country-codes.ts +39 -0
- package/src/utils/crypto.tsx +174 -0
- package/src/utils/currencies.tsx +53 -0
- package/src/utils/currency-constants.tsx +51 -0
- package/src/utils/dates.tsx +246 -0
- package/src/utils/dev-env-state-path.ts +14 -0
- package/src/utils/dom.tsx +7 -0
- package/src/utils/env.tsx +117 -0
- package/src/utils/errors.tsx +284 -0
- package/src/utils/esbuild.tsx +235 -0
- package/src/utils/featurebase.tsx +247 -0
- package/src/utils/fs.tsx +33 -0
- package/src/utils/functions.tsx +22 -0
- package/src/utils/geo.tsx +16 -0
- package/src/utils/globals.tsx +48 -0
- package/src/utils/hashes.tsx +52 -0
- package/src/utils/html.tsx +60 -0
- package/src/utils/http.tsx +91 -0
- package/src/utils/ips.tsx +47 -0
- package/src/utils/json.tsx +200 -0
- package/src/utils/jsx-editable-transpiler.test.ts +156 -0
- package/src/utils/jsx-editable-transpiler.tsx +401 -0
- package/src/utils/jwt.tsx +170 -0
- package/src/utils/locks.tsx +71 -0
- package/src/utils/maps.tsx +407 -0
- package/src/utils/math.tsx +18 -0
- package/src/utils/monkey-patch.tsx +29 -0
- package/src/utils/node-http.tsx +47 -0
- package/src/utils/numbers.tsx +82 -0
- package/src/utils/oauth.tsx +9 -0
- package/src/utils/objects.tsx +581 -0
- package/src/utils/paginated-lists.test.ts +1039 -0
- package/src/utils/paginated-lists.tsx +479 -0
- package/src/utils/passkey.tsx +1 -0
- package/src/utils/promises.tsx +540 -0
- package/src/utils/proxies.tsx +212 -0
- package/src/utils/react.tsx +308 -0
- package/src/utils/redirect-urls.tsx +299 -0
- package/src/utils/regex.tsx +10 -0
- package/src/utils/results.tsx +411 -0
- package/src/utils/sentry.tsx +20 -0
- package/src/utils/stores.tsx +238 -0
- package/src/utils/strings.nicify.test.ts +253 -0
- package/src/utils/strings.tsx +723 -0
- package/src/utils/telemetry.tsx +37 -0
- package/src/utils/turnstile-browser.ts +106 -0
- package/src/utils/turnstile-flow.test.ts +101 -0
- package/src/utils/turnstile-flow.ts +266 -0
- package/src/utils/turnstile.ts +34 -0
- package/src/utils/typed-arrays.tsx +17 -0
- package/src/utils/types.tsx +208 -0
- package/src/utils/unicode.tsx +24 -0
- package/src/utils/urls.tsx +411 -0
- package/src/utils/uuids.tsx +47 -0
- package/dist/esm/stack-config-file.d.ts +0 -15
- package/dist/esm/stack-config-file.d.ts.map +0 -1
- package/dist/esm/stack-config-file.js.map +0 -1
- package/dist/stack-config-file.d.ts +0 -15
- package/dist/stack-config-file.d.ts.map +0 -1
- package/dist/stack-config-file.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import {
|
|
3
|
+
import { parseHexclaveConfigFileContent, renderConfigFileContent } from "./hexclave-config-file.js";
|
|
4
4
|
|
|
5
5
|
//#region src/config-rendering.ts
|
|
6
6
|
/**
|
|
7
|
-
* Packages that export the `
|
|
7
|
+
* Packages that export the `HexclaveConfig` type, in priority order.
|
|
8
8
|
* The first match found in a project's dependencies wins. Hexclave-branded
|
|
9
9
|
* packages come first (canonical); the legacy `@stackframe/*` names remain
|
|
10
10
|
* so projects pinned to the last legacy release still render a config file
|
|
@@ -14,6 +14,7 @@ const CONFIG_IMPORT_PACKAGES = [
|
|
|
14
14
|
"@hexclave/next",
|
|
15
15
|
"@hexclave/react",
|
|
16
16
|
"@hexclave/js",
|
|
17
|
+
"@hexclave/template",
|
|
17
18
|
"@stackframe/stack",
|
|
18
19
|
"@stackframe/react",
|
|
19
20
|
"@stackframe/js",
|
|
@@ -21,7 +22,7 @@ const CONFIG_IMPORT_PACKAGES = [
|
|
|
21
22
|
];
|
|
22
23
|
/**
|
|
23
24
|
* Given a list of dependency names (from package.json), returns the SDK
|
|
24
|
-
* package that should be used for the `
|
|
25
|
+
* package that should be used for the `HexclaveConfig` import, or `undefined`
|
|
25
26
|
* if none of the known packages are installed.
|
|
26
27
|
*/
|
|
27
28
|
function detectConfigImportPackage(dependencies) {
|
|
@@ -29,7 +30,7 @@ function detectConfigImportPackage(dependencies) {
|
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
31
32
|
* Walks up from `dir` to find the nearest `package.json` and returns the
|
|
32
|
-
* best SDK package to use for the `
|
|
33
|
+
* best SDK package to use for the `HexclaveConfig` type import.
|
|
33
34
|
*/
|
|
34
35
|
function detectImportPackageFromDir(dir) {
|
|
35
36
|
let current = dir;
|
|
@@ -50,7 +51,7 @@ function detectImportPackageFromDir(dir) {
|
|
|
50
51
|
expect(renderConfigFileContent({
|
|
51
52
|
"payments.items.todos.displayName": "Todo Slots",
|
|
52
53
|
"payments.items.todos.customerType": "user"
|
|
53
|
-
})).toContain(`export const config:
|
|
54
|
+
})).toContain(`export const config: HexclaveConfig = {
|
|
54
55
|
"payments": {
|
|
55
56
|
"items": {
|
|
56
57
|
"todos": {
|
|
@@ -61,8 +62,8 @@ function detectImportPackageFromDir(dir) {
|
|
|
61
62
|
}
|
|
62
63
|
};`);
|
|
63
64
|
});
|
|
64
|
-
(void 0)?.test("
|
|
65
|
-
expect(
|
|
65
|
+
(void 0)?.test("parseHexclaveConfigFileContent parses static config exports", ({ expect }) => {
|
|
66
|
+
expect(parseHexclaveConfigFileContent(`
|
|
66
67
|
import type { StackConfig } from "@hexclave/js";
|
|
67
68
|
export const config: StackConfig = {
|
|
68
69
|
auth: { allowSignUp: true },
|
|
@@ -79,11 +80,11 @@ function detectImportPackageFromDir(dir) {
|
|
|
79
80
|
}
|
|
80
81
|
`);
|
|
81
82
|
});
|
|
82
|
-
(void 0)?.test("
|
|
83
|
-
expect(
|
|
83
|
+
(void 0)?.test("parseHexclaveConfigFileContent parses show-onboarding", ({ expect }) => {
|
|
84
|
+
expect(parseHexclaveConfigFileContent("export const config = \"show-onboarding\";", "stack.config.ts")).toBe("show-onboarding");
|
|
84
85
|
});
|
|
85
|
-
(void 0)?.test("
|
|
86
|
-
expect(() =>
|
|
86
|
+
(void 0)?.test("parseHexclaveConfigFileContent rejects dynamic config exports", ({ expect }) => {
|
|
87
|
+
expect(() => parseHexclaveConfigFileContent("export const config = makeConfig();", "stack.config.ts")).toThrow(/Unsupported config expression/);
|
|
87
88
|
});
|
|
88
89
|
(void 0)?.test("renderConfigFileContent rejects conflicting dotted keys", ({ expect }) => {
|
|
89
90
|
expect(() => renderConfigFileContent({
|
|
@@ -95,10 +96,10 @@ function detectImportPackageFromDir(dir) {
|
|
|
95
96
|
expect(() => renderConfigFileContent(null)).toThrowErrorMatchingInlineSnapshot(`[Error: Invalid config: expected a plain object.]`);
|
|
96
97
|
});
|
|
97
98
|
(void 0)?.test("renderConfigFileContent uses custom import package", ({ expect }) => {
|
|
98
|
-
expect(renderConfigFileContent({}, "@hexclave/next")).toContain("import type {
|
|
99
|
+
expect(renderConfigFileContent({}, "@hexclave/next")).toContain("import type { HexclaveConfig } from \"@hexclave/next\";");
|
|
99
100
|
});
|
|
100
101
|
(void 0)?.test("renderConfigFileContent defaults to @hexclave/js", ({ expect }) => {
|
|
101
|
-
expect(renderConfigFileContent({})).toContain("import type {
|
|
102
|
+
expect(renderConfigFileContent({})).toContain("import type { HexclaveConfig } from \"@hexclave/js\";");
|
|
102
103
|
});
|
|
103
104
|
(void 0)?.test("detectConfigImportPackage picks first matching package by priority", ({ expect }) => {
|
|
104
105
|
expect(detectConfigImportPackage(["@hexclave/next", "@hexclave/js"])).toBe("@hexclave/next");
|
|
@@ -112,5 +113,5 @@ function detectImportPackageFromDir(dir) {
|
|
|
112
113
|
});
|
|
113
114
|
|
|
114
115
|
//#endregion
|
|
115
|
-
export { detectConfigImportPackage, detectImportPackageFromDir,
|
|
116
|
+
export { detectConfigImportPackage, detectImportPackageFromDir, parseHexclaveConfigFileContent, renderConfigFileContent };
|
|
116
117
|
//# sourceMappingURL=config-rendering.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-rendering.js","names":[],"sources":["../../src/config-rendering.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport path from \"path\";\nimport {
|
|
1
|
+
{"version":3,"file":"config-rendering.js","names":[],"sources":["../../src/config-rendering.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport path from \"path\";\nimport { parseHexclaveConfigFileContent, renderConfigFileContent } from \"./hexclave-config-file\";\nexport { parseHexclaveConfigFileContent, renderConfigFileContent };\n\n/**\n * Packages that export the `HexclaveConfig` type, in priority order.\n * The first match found in a project's dependencies wins. Hexclave-branded\n * packages come first (canonical); the legacy `@stackframe/*` names remain\n * so projects pinned to the last legacy release still render a config file\n * that compiles against their installed SDK.\n */\nconst CONFIG_IMPORT_PACKAGES = [\n \"@hexclave/next\",\n \"@hexclave/react\",\n \"@hexclave/js\",\n \"@hexclave/template\",\n \"@stackframe/stack\",\n \"@stackframe/react\",\n \"@stackframe/js\",\n \"@stackframe/template\",\n] as const;\n\n/**\n * Given a list of dependency names (from package.json), returns the SDK\n * package that should be used for the `HexclaveConfig` import, or `undefined`\n * if none of the known packages are installed.\n */\nexport function detectConfigImportPackage(dependencies: string[]): string | undefined {\n for (const pkg of CONFIG_IMPORT_PACKAGES) {\n if (dependencies.includes(pkg)) {\n return pkg;\n }\n }\n return undefined;\n}\n\n/**\n * Walks up from `dir` to find the nearest `package.json` and returns the\n * best SDK package to use for the `HexclaveConfig` type import.\n */\nexport function detectImportPackageFromDir(dir: string): string | undefined {\n let current = dir;\n while (true) {\n const pkgPath = path.join(current, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n const deps = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n return detectConfigImportPackage(deps);\n } catch {\n return undefined;\n }\n }\n const parent = path.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return undefined;\n}\n\nimport.meta.vitest?.test(\"renderConfigFileContent normalizes config exports\", ({ expect }) => {\n expect(renderConfigFileContent({\n \"payments.items.todos.displayName\": \"Todo Slots\",\n \"payments.items.todos.customerType\": \"user\",\n })).toContain(`export const config: HexclaveConfig = {\n \"payments\": {\n \"items\": {\n \"todos\": {\n \"displayName\": \"Todo Slots\",\n \"customerType\": \"user\"\n }\n }\n }\n};`);\n});\n\nimport.meta.vitest?.test(\"parseHexclaveConfigFileContent parses static config exports\", ({ expect }) => {\n expect(parseHexclaveConfigFileContent(`\n import type { StackConfig } from \"@hexclave/js\";\n export const config: StackConfig = {\n auth: { allowSignUp: true },\n payments: { testMode: false },\n };\n `, \"stack.config.ts\")).toMatchInlineSnapshot(`\n {\n \"auth\": {\n \"allowSignUp\": true,\n },\n \"payments\": {\n \"testMode\": false,\n },\n }\n `);\n});\n\nimport.meta.vitest?.test(\"parseHexclaveConfigFileContent parses show-onboarding\", ({ expect }) => {\n expect(parseHexclaveConfigFileContent('export const config = \"show-onboarding\";', \"stack.config.ts\")).toBe(\"show-onboarding\");\n});\n\nimport.meta.vitest?.test(\"parseHexclaveConfigFileContent rejects dynamic config exports\", ({ expect }) => {\n expect(() => parseHexclaveConfigFileContent(\"export const config = makeConfig();\", \"stack.config.ts\")).toThrow(/Unsupported config expression/);\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent rejects conflicting dotted keys\", ({ expect }) => {\n expect(() => renderConfigFileContent({\n \"a.b\": 1,\n \"a.b.c\": 2,\n })).toThrowError(/conflicting keys.*\"a\\.b\\.c\"/);\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent rejects invalid config exports\", ({ expect }) => {\n expect(() => renderConfigFileContent(null)).toThrowErrorMatchingInlineSnapshot(\n `[Error: Invalid config: expected a plain object.]`,\n );\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent uses custom import package\", ({ expect }) => {\n const content = renderConfigFileContent({}, \"@hexclave/next\");\n expect(content).toContain('import type { HexclaveConfig } from \"@hexclave/next\";');\n});\n\nimport.meta.vitest?.test(\"renderConfigFileContent defaults to @hexclave/js\", ({ expect }) => {\n const content = renderConfigFileContent({});\n expect(content).toContain('import type { HexclaveConfig } from \"@hexclave/js\";');\n});\n\nimport.meta.vitest?.test(\"detectConfigImportPackage picks first matching package by priority\", ({ expect }) => {\n expect(detectConfigImportPackage([\"@hexclave/next\", \"@hexclave/js\"])).toBe(\"@hexclave/next\");\n expect(detectConfigImportPackage([\"@hexclave/react\", \"@hexclave/js\"])).toBe(\"@hexclave/react\");\n expect(detectConfigImportPackage([\"@hexclave/js\"])).toBe(\"@hexclave/js\");\n // Hexclave names take priority over legacy stackframe names when both appear.\n expect(detectConfigImportPackage([\"@stackframe/stack\", \"@hexclave/next\"])).toBe(\"@hexclave/next\");\n // Legacy fallback still works for projects pinned to the last @stackframe/* release.\n expect(detectConfigImportPackage([\"@stackframe/stack\"])).toBe(\"@stackframe/stack\");\n expect(detectConfigImportPackage([\"@stackframe/template\"])).toBe(\"@stackframe/template\");\n expect(detectConfigImportPackage([\"lodash\", \"express\"])).toBeUndefined();\n expect(detectConfigImportPackage([])).toBeUndefined();\n});\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;AAOD,SAAgB,0BAA0B,cAA4C;AACpF,MAAK,MAAM,OAAO,uBAChB,KAAI,aAAa,SAAS,IAAI,CAC5B,QAAO;;;;;;AAUb,SAAgB,2BAA2B,KAAiC;CAC1E,IAAI,UAAU;AACd,QAAO,MAAM;EACX,MAAM,UAAU,KAAK,KAAK,SAAS,eAAe;AAClD,MAAI,WAAW,QAAQ,CACrB,KAAI;GACF,MAAM,MAAM,KAAK,MAAM,aAAa,SAAS,QAAQ,CAAC;AAKtD,UAAO,0BAJM,CACX,GAAG,OAAO,KAAK,IAAI,gBAAgB,EAAE,CAAC,EACtC,GAAG,OAAO,KAAK,IAAI,mBAAmB,EAAE,CAAC,CAC1C,CACqC;UAChC;AACN;;EAGJ,MAAM,SAAS,KAAK,QAAQ,QAAQ;AACpC,MAAI,WAAW,QAAS;AACxB,YAAU;;;CAKd,SAAW,KAAC,sDAAwD,EAAA,aAAa;AAC/E,QAAO,wBAAwB;EAC7B,oCAAoC;EACpC,qCAAqC;EACtC,CAAC,CAAC,CAAC,UAAU;;;;;;;;;IASZ;EACF;CAEF,SAAW,KAAC,gEAAkE,EAAA,aAAa;AACzF,QAAO,+BAA+B;;;;;;KAMnC,kBAAkB,CAAC,CAAC,sBAAsB;;;;;;;;;IAS3C;EACF;CAEF,SAAW,KAAC,0DAAyD,EAAA,aAAgB;AACnF,QAAO,+BAA+B,8CAA4C,kBAAkB,CAAC,CAAC,KAAK,kBAAkB;EAC7H;CAEF,SAAW,KAAC,kEAAoE,EAAA,aAAa;AAC3F,cAAa,+BAA+B,uCAAuC,kBAAkB,CAAC,CAAC,QAAQ,gCAAgC;EAC/I;CAEF,SAAW,KAAC,4DAAgE,EAAC,aAAU;AACrF,cAAa,wBAAwB;EACnC,OAAO;EACP,SAAS;EACV,CAAC,CAAC,CAAC,aAAa,8BAA8B;EAC/C;CAEF,SAAW,KAAC,2DAA6D,EAAA,aAAa;AACpF,cAAa,wBAAwB,KAAK,CAAC,CAAC,mCAC1C,oDACD;EACD;CAEF,SAAW,KAAC,uDAAyD,EAAA,aAAa;AAEhF,QADgB,wBAAwB,EAAE,EAAE,iBAAiB,CAC9C,CAAC,UAAU,0DAAwD;EAClF;CAEF,SAAW,KAAC,qDAAmD,EAAQ,aAAS;AAE9E,QADgB,wBAAwB,EAAE,CAAC,CAC5B,CAAC,UAAU,wDAAsD;EAChF;CAEF,SAAW,KAAC,uEAAwE,EAAA,aAAc;AAChG,QAAO,0BAA0B,CAAC,kBAAkB,eAAe,CAAC,CAAC,CAAC,KAAK,iBAAiB;AAC5F,QAAO,0BAA0B,CAAC,mBAAmB,eAAe,CAAC,CAAC,CAAC,KAAK,kBAAkB;AAC9F,QAAO,0BAA0B,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,eAAe;AAExE,QAAO,0BAA0B,CAAC,qBAAqB,iBAAiB,CAAC,CAAC,CAAC,KAAK,iBAAiB;AAEjG,QAAO,0BAA0B,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,oBAAoB;AAClF,QAAO,0BAA0B,CAAC,uBAAuB,CAAC,CAAC,CAAC,KAAK,uBAAuB;AACxF,QAAO,0BAA0B,CAAC,UAAU,UAAU,CAAC,CAAC,CAAC,eAAe;AACxE,QAAO,0BAA0B,EAAE,CAAC,CAAC,CAAC,eAAe;EACrD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-side.d.ts","names":[],"sources":["../../../../src/helpers/vault/client-side.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"client-side.d.ts","names":[],"sources":["../../../../src/helpers/vault/client-side.ts"],"mappings":";;AAuBA;;iBAAsB,OAAA,CAAQ,MAAA,UAAgB,GAAA,WAAW,OAAA;;;;iBAWnC,YAAA,CAAa,MAAA,UAAgB,GAAA,UAAa,KAAA,WAAa,OAAA;;;AAA7E;iBAcsB,YAAA,CAAa,MAAA,UAAgB,GAAA,UAAa,cAAA,WAAsB,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-side.js","names":[],"sources":["../../../../src/helpers/vault/client-side.ts"],"sourcesContent":["import { decodeBase64, encodeBase64 } from \"../../utils/bytes\";\nimport { decrypt, encrypt, hash, iteratedHash } from \"../../utils/crypto\";\n\nconst hashPurpose = \"stack-data-vault-client-side-encryption-key-hash\";\nconst encryptionSecretPurpose = \"stack-data-vault-client-side-encryption-value-encryption-key-hash\";\nconst encryptionValuePurpose = \"stack-data-vault-client-side-encryption-value-encryption-value-encryption\";\n\n\nasync function getDerivedKey(secret: string, key: string) {\n return await iteratedHash({\n purpose: encryptionSecretPurpose,\n extra: secret,\n value: key,\n iterations: 100_000,\n });\n}\n\n/**\n * Use to hash the key so the server cannot infer it.\n */\nexport async function hashKey(secret: string, key: string) {\n return encodeBase64(await hash({\n purpose: hashPurpose,\n extra: secret,\n value: await getDerivedKey(secret, key),\n }));\n}\n\n/**\n * Use to encrypt the value so that the server cannot read the value without knowing the key.\n */\nexport async function encryptValue(secret: string, key: string, value: string) {\n const valueEncryptionDerivedKey = await getDerivedKey(secret, key);\n\n const bytes = await encrypt({\n purpose: encryptionValuePurpose,\n secret: valueEncryptionDerivedKey,\n value: new TextEncoder().encode(value)\n });\n return encodeBase64(bytes);\n}\n\n/**\n * Use to decrypt the value. See encryptValue.\n */\nexport async function decryptValue(secret: string, key: string, encryptedValue: string) {\n const valueEncryptionDerivedKey = await getDerivedKey(secret, key);\n\n const bytesResult = await decrypt({\n purpose: encryptionValuePurpose,\n secret: valueEncryptionDerivedKey,\n cipher: decodeBase64(encryptedValue),\n });\n if (bytesResult.status === \"error\") throw new Error(\"Data vault client-side decryption failed. Are you sure you're using the correct secret?\", { cause: bytesResult.error });\n return new TextDecoder().decode(bytesResult.data);\n}\n\n\nimport.meta.vitest?.describe(\"encryptValue & decryptValue\", () => {\n import.meta.vitest?.it(\"should encrypt and decrypt a value\", async ({ expect }) => {\n const secret = \"test-secret\";\n const value = \"test-value\";\n const encrypted = await encryptValue(secret, \"key\", value);\n const decrypted = await decryptValue(secret, \"key\", encrypted);\n expect(decrypted).toEqual(value);\n });\n\n import.meta.vitest?.it(\"should not decrypt a value with a different secret\", async ({ expect }) => {\n const secret = \"test-secret\";\n const value = \"test-value\";\n const encrypted = await encryptValue(secret, \"key\", value);\n await expect(decryptValue(\"different-secret\", \"key\", encrypted)).rejects.toThrow();\n });\n\n import.meta.vitest?.it(\"should not decrypt a value with a different key\", async ({ expect }) => {\n const secret = \"test-secret\";\n const value = \"test-value\";\n const encrypted = await encryptValue(secret, \"key\", value);\n await expect(decryptValue(secret, \"different-key\", encrypted)).rejects.toThrow();\n });\n\n import.meta.vitest?.it(\"should not decrypt a value if the cipher was tampered with\", async ({ expect }) => {\n const secret = \"test-secret\";\n const value = \"test-value\";\n const encrypted = await encryptValue(secret, \"key\", value);\n const tampered = encrypted + \"7\";\n await expect(decryptValue(secret, \"key\", tampered)).rejects.toThrow();\n });\n});\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"client-side.js","names":[],"sources":["../../../../src/helpers/vault/client-side.ts"],"sourcesContent":["import { decodeBase64, encodeBase64 } from \"../../utils/bytes\";\nimport { decrypt, encrypt, hash, iteratedHash } from \"../../utils/crypto\";\n\n// NOTE (Hexclave rebrand): do NOT rename these \"stack-*\" purpose tags. They are mixed into the\n// vault's key derivation and value encryption; renaming any of them would make every\n// previously-stored vault value undecryptable. Internal constants, never user-visible.\nconst hashPurpose = \"stack-data-vault-client-side-encryption-key-hash\";\nconst encryptionSecretPurpose = \"stack-data-vault-client-side-encryption-value-encryption-key-hash\";\nconst encryptionValuePurpose = \"stack-data-vault-client-side-encryption-value-encryption-value-encryption\";\n\n\nasync function getDerivedKey(secret: string, key: string) {\n return await iteratedHash({\n purpose: encryptionSecretPurpose,\n extra: secret,\n value: key,\n iterations: 100_000,\n });\n}\n\n/**\n * Use to hash the key so the server cannot infer it.\n */\nexport async function hashKey(secret: string, key: string) {\n return encodeBase64(await hash({\n purpose: hashPurpose,\n extra: secret,\n value: await getDerivedKey(secret, key),\n }));\n}\n\n/**\n * Use to encrypt the value so that the server cannot read the value without knowing the key.\n */\nexport async function encryptValue(secret: string, key: string, value: string) {\n const valueEncryptionDerivedKey = await getDerivedKey(secret, key);\n\n const bytes = await encrypt({\n purpose: encryptionValuePurpose,\n secret: valueEncryptionDerivedKey,\n value: new TextEncoder().encode(value)\n });\n return encodeBase64(bytes);\n}\n\n/**\n * Use to decrypt the value. See encryptValue.\n */\nexport async function decryptValue(secret: string, key: string, encryptedValue: string) {\n const valueEncryptionDerivedKey = await getDerivedKey(secret, key);\n\n const bytesResult = await decrypt({\n purpose: encryptionValuePurpose,\n secret: valueEncryptionDerivedKey,\n cipher: decodeBase64(encryptedValue),\n });\n if (bytesResult.status === \"error\") throw new Error(\"Data vault client-side decryption failed. Are you sure you're using the correct secret?\", { cause: bytesResult.error });\n return new TextDecoder().decode(bytesResult.data);\n}\n\n\nimport.meta.vitest?.describe(\"encryptValue & decryptValue\", () => {\n import.meta.vitest?.it(\"should encrypt and decrypt a value\", async ({ expect }) => {\n const secret = \"test-secret\";\n const value = \"test-value\";\n const encrypted = await encryptValue(secret, \"key\", value);\n const decrypted = await decryptValue(secret, \"key\", encrypted);\n expect(decrypted).toEqual(value);\n });\n\n import.meta.vitest?.it(\"should not decrypt a value with a different secret\", async ({ expect }) => {\n const secret = \"test-secret\";\n const value = \"test-value\";\n const encrypted = await encryptValue(secret, \"key\", value);\n await expect(decryptValue(\"different-secret\", \"key\", encrypted)).rejects.toThrow();\n });\n\n import.meta.vitest?.it(\"should not decrypt a value with a different key\", async ({ expect }) => {\n const secret = \"test-secret\";\n const value = \"test-value\";\n const encrypted = await encryptValue(secret, \"key\", value);\n await expect(decryptValue(secret, \"different-key\", encrypted)).rejects.toThrow();\n });\n\n import.meta.vitest?.it(\"should not decrypt a value if the cipher was tampered with\", async ({ expect }) => {\n const secret = \"test-secret\";\n const value = \"test-value\";\n const encrypted = await encryptValue(secret, \"key\", value);\n const tampered = encrypted + \"7\";\n await expect(decryptValue(secret, \"key\", tampered)).rejects.toThrow();\n });\n});\n"],"mappings":";;;;AAMA,MAAM,cAAc;AACpB,MAAM,0BAA0B;AAChC,MAAM,yBAAyB;AAG/B,eAAe,cAAc,QAAgB,KAAa;AACxD,QAAO,MAAM,aAAa;EACxB,SAAS;EACT,OAAO;EACP,OAAO;EACP,YAAY;EACb,CAAC;;;;;AAMJ,eAAsB,QAAQ,QAAgB,KAAa;AACzD,QAAO,aAAa,MAAM,KAAK;EAC7B,SAAS;EACT,OAAO;EACP,OAAO,MAAM,cAAc,QAAQ,IAAI;EACxC,CAAC,CAAC;;;;;AAML,eAAsB,aAAa,QAAgB,KAAa,OAAe;AAQ7E,QAAO,aALO,MAAM,QAAQ;EAC1B,SAAS;EACT,QAJgC,MAAM,cAAc,QAAQ,IAAI;EAKhE,OAAO,IAAI,aAAa,CAAC,OAAO,MAAK;EACtC,CAAC,CACwB;;;;;AAM5B,eAAsB,aAAa,QAAgB,KAAa,gBAAwB;CAGtF,MAAM,cAAc,MAAM,QAAQ;EAChC,SAAS;EACT,QAJgC,MAAM,cAAc,QAAQ,IAAI;EAKhE,QAAQ,aAAa,eAAe;EACrC,CAAC;AACF,KAAI,YAAY,WAAW,QAAS,OAAM,IAAI,MAAM,2FAA2F,EAAE,OAAO,YAAY,OAAO,CAAC;AAC5K,QAAO,IAAI,aAAa,CAAC,OAAO,YAAY,KAAK;;CAInD,SAAW,SAAS,qCAAqC;AACvD,WAAW,GAAC,sCAAwC,OAAO,EAAE,aAAS;EACpE,MAAM,SAAS;EACf,MAAM,QAAQ;AAGd,SADkB,MAAM,aAAa,QAAQ,OAD3B,MAAM,aAAa,QAAQ,OAAO,MAAM,CACI,CAC7C,CAAC,QAAQ,MAAM;GAChC;AAEF,WAAW,GAAC,sDAAwD,OAAO,EAAE,aAAS;AAIpF,QAAM,OAAO,aAAa,oBAAoB,OAD5B,MAAM,aAFT,eAE8B,OAD/B,aAC4C,CACK,CAAC,CAAC,QAAQ,SAAS;GAClF;AAEF,WAAW,GAAC,mDAA8C,OAAc,EAAE,aAAS;EACjF,MAAM,SAAS;AAGf,QAAM,OAAO,aAAa,QAAQ,iBADhB,MAAM,aAAa,QAAQ,OAD/B,aAC4C,CACG,CAAC,CAAC,QAAQ,SAAS;GAChF;AAEF,WAAW,GAAC,8DAAyD,OAAc,EAAE,aAAS;EAC5F,MAAM,SAAS;AAIf,QAAM,OAAO,aAAa,QAAQ,OAFhB,MAAM,aAAa,QAAQ,OAD/B,aAC4C,GAC7B,IACqB,CAAC,CAAC,QAAQ,SAAS;GACrE;EACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-side.d.ts","names":[],"sources":["../../../../src/helpers/vault/server-side.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"server-side.d.ts","names":[],"sources":["../../../../src/helpers/vault/server-side.ts"],"mappings":";iBA4HsB,cAAA,CAAe,KAAA,WAAa,OAAA;;;;iBAgB5B,cAAA,CAAe,SAAA,EAAW,OAAA,CAAQ,UAAA,QAAkB,cAAA,KAAgB,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-side.js","names":[],"sources":["../../../../src/helpers/vault/server-side.ts"],"sourcesContent":["import {\n CreateAliasCommand,\n CreateKeyCommand,\n DecryptCommand,\n DescribeKeyCommand,\n GenerateDataKeyCommand,\n KMSClient\n} from \"@aws-sdk/client-kms\";\nimport { decodeBase64, encodeBase64 } from \"../../utils/bytes\";\nimport { decrypt, encrypt } from \"../../utils/crypto\";\nimport { getEnvVariable } from \"../../utils/env\";\nimport { Result } from \"../../utils/results\";\n\n\nasync function getAwsCredentials() {\n // 1. Vercel OIDC: Vercel injects an OIDC token that can be exchanged for AWS credentials\n const vercelRoleArn = getEnvVariable(\"STACK_AWS_VERCEL_OIDC_ROLE_ARN\", \"\");\n if (vercelRoleArn) {\n const { awsCredentialsProvider } = await import(\"@vercel/functions/oidc\");\n return awsCredentialsProvider({ roleArn: vercelRoleArn });\n }\n\n // 2. GCP Workload Identity Federation: Cloud Run gets a GCP ID token from the metadata server,\n // then exchanges it for temporary AWS credentials via STS AssumeRoleWithWebIdentity.\n // Requires:\n // - An OIDC identity provider in AWS IAM (issuer: https://accounts.google.com)\n // - An IAM role with a trust policy allowing the GCP service account\n // - STACK_AWS_GCP_WIF_ROLE_ARN set to that role's ARN\n // - STACK_AWS_GCP_WIF_AUDIENCE set to the audience configured in the AWS OIDC provider\n const gcpWifRoleArn = getEnvVariable(\"STACK_AWS_GCP_WIF_ROLE_ARN\", \"\");\n if (gcpWifRoleArn) {\n const { fromWebToken } = await import(\"@aws-sdk/credential-provider-web-identity\");\n const audience = getEnvVariable(\"STACK_AWS_GCP_WIF_AUDIENCE\", \"sts.amazonaws.com\");\n // Return a provider that fetches a fresh GCP ID token on each invocation.\n // GCP metadata tokens expire after ~1h, so we can't bake a single token into the closure.\n return async () => {\n return await fromWebToken({\n roleArn: gcpWifRoleArn,\n roleSessionName: \"stack-backend-cloudrun\",\n webIdentityToken: await fetchGcpIdToken(audience),\n })();\n };\n }\n\n // 3. Static credentials: fallback for self-hosted / local development\n return {\n accessKeyId: getEnvVariable(\"STACK_AWS_ACCESS_KEY_ID\"),\n secretAccessKey: getEnvVariable(\"STACK_AWS_SECRET_ACCESS_KEY\"),\n };\n}\n\n/**\n * Fetches a GCP ID token from the metadata server (available on Cloud Run, GCE, GKE).\n * The token is a Google-signed JWT with the specified audience, suitable for\n * AWS STS AssumeRoleWithWebIdentity.\n */\nasync function fetchGcpIdToken(audience: string): Promise<string> {\n const metadataUrl = `http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=${encodeURIComponent(audience)}`;\n const response = await fetch(metadataUrl, {\n headers: { \"Metadata-Flavor\": \"Google\" },\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch GCP ID token: ${response.status} ${await response.text()}`);\n }\n return await response.text();\n}\n\nlet kmsClientCache: KMSClient | undefined;\n\nasync function getKmsClient() {\n if (!kmsClientCache) {\n kmsClientCache = new KMSClient({\n region: getEnvVariable(\"STACK_AWS_REGION\"),\n endpoint: getEnvVariable(\"STACK_AWS_KMS_ENDPOINT\"),\n credentials: await getAwsCredentials(),\n });\n }\n return kmsClientCache;\n}\n\nasync function getOrCreateKekId(): Promise<string> {\n const id = \"alias/stack-data-vault-server-side-kek\";\n const kms = await getKmsClient();\n try {\n const describeResult = await kms.send(new DescribeKeyCommand({ KeyId: id }));\n if (describeResult.KeyMetadata?.KeyId) return describeResult.KeyMetadata.KeyId;\n } catch (e) {\n if (e instanceof Error && e.name !== \"NotFoundException\") {\n throw e;\n }\n }\n const { KeyMetadata } = await kms.send(new CreateKeyCommand({\n KeyUsage: \"ENCRYPT_DECRYPT\",\n Description: \"DataVault KEK\"\n }));\n await kms.send(new CreateAliasCommand({ AliasName: id, TargetKeyId: KeyMetadata!.KeyId! }));\n return id;\n}\n\nasync function genDEK() {\n const kekId = await getOrCreateKekId();\n const kms = await getKmsClient();\n const out = await kms.send(new GenerateDataKeyCommand({ KeyId: kekId, KeySpec: \"AES_256\" }));\n if (!out.Plaintext || !out.CiphertextBlob) throw new Error(\"GenerateDataKey failed\");\n return {\n dekBytes: out.Plaintext,\n edkBytes: out.CiphertextBlob,\n };\n}\n\nasync function unwrapDEK(edk_b64: string) {\n const edkBytes = decodeBase64(edk_b64);\n const kms = await getKmsClient();\n const out = await kms.send(new DecryptCommand({ CiphertextBlob: edkBytes }));\n if (!out.Plaintext) throw new Error(\"KMS Decrypt failed\");\n return {\n dekBytes: out.Plaintext,\n edkBytes,\n };\n}\n\nexport async function encryptWithKms(value: string) {\n const { dekBytes, edkBytes } = await genDEK();\n try {\n const ciphertext = await encrypt({\n purpose: \"stack-data-vault-server-side-encryption\",\n secret: dekBytes,\n value: new TextEncoder().encode(value),\n });\n return { edkBase64: encodeBase64(edkBytes), ciphertextBase64: encodeBase64(ciphertext) };\n } finally {\n dekBytes.fill(0);\n }\n}\n\nexport async function decryptWithKms(encrypted: Awaited<ReturnType<typeof encryptWithKms>>) {\n const { dekBytes } = await unwrapDEK(encrypted.edkBase64);\n try {\n const value = Result.orThrow(await decrypt({\n purpose: \"stack-data-vault-server-side-encryption\",\n secret: dekBytes,\n cipher: decodeBase64(encrypted.ciphertextBase64),\n }));\n return new TextDecoder().decode(value);\n } finally {\n dekBytes.fill(0);\n }\n}\n"],"mappings":";;;;;;;AAcA,eAAe,oBAAoB;CAEjC,MAAM,gBAAgB,eAAe,kCAAkC,GAAG;AAC1E,KAAI,eAAe;EACjB,MAAM,EAAE,2BAA2B,MAAM,OAAO;AAChD,SAAO,uBAAuB,EAAE,SAAS,eAAe,CAAC;;CAU3D,MAAM,gBAAgB,eAAe,8BAA8B,GAAG;AACtE,KAAI,eAAe;EACjB,MAAM,EAAE,iBAAiB,MAAM,OAAO;EACtC,MAAM,WAAW,eAAe,8BAA8B,oBAAoB;AAGlF,SAAO,YAAY;AACjB,UAAO,MAAM,aAAa;IACxB,SAAS;IACT,iBAAiB;IACjB,kBAAkB,MAAM,gBAAgB,SAAS;IAClD,CAAC,EAAE;;;AAKR,QAAO;EACL,aAAa,eAAe,0BAA0B;EACtD,iBAAiB,eAAe,8BAA8B;EAC/D;;;;;;;AAQH,eAAe,gBAAgB,UAAmC;CAChE,MAAM,cAAc,0GAA0G,mBAAmB,SAAS;CAC1J,MAAM,WAAW,MAAM,MAAM,aAAa,EACxC,SAAS,EAAE,mBAAmB,UAAU,EACzC,CAAC;AACF,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,iCAAiC,SAAS,OAAO,GAAG,MAAM,SAAS,MAAM,GAAG;AAE9F,QAAO,MAAM,SAAS,MAAM;;AAG9B,IAAI;AAEJ,eAAe,eAAe;AAC5B,KAAI,CAAC,eACH,kBAAiB,IAAI,UAAU;EAC7B,QAAQ,eAAe,mBAAmB;EAC1C,UAAU,eAAe,yBAAyB;EAClD,aAAa,MAAM,mBAAmB;EACvC,CAAC;AAEJ,QAAO;;AAGT,eAAe,mBAAoC;
|
|
1
|
+
{"version":3,"file":"server-side.js","names":[],"sources":["../../../../src/helpers/vault/server-side.ts"],"sourcesContent":["import {\n CreateAliasCommand,\n CreateKeyCommand,\n DecryptCommand,\n DescribeKeyCommand,\n GenerateDataKeyCommand,\n KMSClient\n} from \"@aws-sdk/client-kms\";\nimport { decodeBase64, encodeBase64 } from \"../../utils/bytes\";\nimport { decrypt, encrypt } from \"../../utils/crypto\";\nimport { getEnvVariable } from \"../../utils/env\";\nimport { Result } from \"../../utils/results\";\n\n\nasync function getAwsCredentials() {\n // 1. Vercel OIDC: Vercel injects an OIDC token that can be exchanged for AWS credentials\n const vercelRoleArn = getEnvVariable(\"STACK_AWS_VERCEL_OIDC_ROLE_ARN\", \"\");\n if (vercelRoleArn) {\n const { awsCredentialsProvider } = await import(\"@vercel/functions/oidc\");\n return awsCredentialsProvider({ roleArn: vercelRoleArn });\n }\n\n // 2. GCP Workload Identity Federation: Cloud Run gets a GCP ID token from the metadata server,\n // then exchanges it for temporary AWS credentials via STS AssumeRoleWithWebIdentity.\n // Requires:\n // - An OIDC identity provider in AWS IAM (issuer: https://accounts.google.com)\n // - An IAM role with a trust policy allowing the GCP service account\n // - STACK_AWS_GCP_WIF_ROLE_ARN set to that role's ARN\n // - STACK_AWS_GCP_WIF_AUDIENCE set to the audience configured in the AWS OIDC provider\n const gcpWifRoleArn = getEnvVariable(\"STACK_AWS_GCP_WIF_ROLE_ARN\", \"\");\n if (gcpWifRoleArn) {\n const { fromWebToken } = await import(\"@aws-sdk/credential-provider-web-identity\");\n const audience = getEnvVariable(\"STACK_AWS_GCP_WIF_AUDIENCE\", \"sts.amazonaws.com\");\n // Return a provider that fetches a fresh GCP ID token on each invocation.\n // GCP metadata tokens expire after ~1h, so we can't bake a single token into the closure.\n return async () => {\n return await fromWebToken({\n roleArn: gcpWifRoleArn,\n roleSessionName: \"stack-backend-cloudrun\",\n webIdentityToken: await fetchGcpIdToken(audience),\n })();\n };\n }\n\n // 3. Static credentials: fallback for self-hosted / local development\n return {\n accessKeyId: getEnvVariable(\"STACK_AWS_ACCESS_KEY_ID\"),\n secretAccessKey: getEnvVariable(\"STACK_AWS_SECRET_ACCESS_KEY\"),\n };\n}\n\n/**\n * Fetches a GCP ID token from the metadata server (available on Cloud Run, GCE, GKE).\n * The token is a Google-signed JWT with the specified audience, suitable for\n * AWS STS AssumeRoleWithWebIdentity.\n */\nasync function fetchGcpIdToken(audience: string): Promise<string> {\n const metadataUrl = `http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=${encodeURIComponent(audience)}`;\n const response = await fetch(metadataUrl, {\n headers: { \"Metadata-Flavor\": \"Google\" },\n });\n if (!response.ok) {\n throw new Error(`Failed to fetch GCP ID token: ${response.status} ${await response.text()}`);\n }\n return await response.text();\n}\n\nlet kmsClientCache: KMSClient | undefined;\n\nasync function getKmsClient() {\n if (!kmsClientCache) {\n kmsClientCache = new KMSClient({\n region: getEnvVariable(\"STACK_AWS_REGION\"),\n endpoint: getEnvVariable(\"STACK_AWS_KMS_ENDPOINT\"),\n credentials: await getAwsCredentials(),\n });\n }\n return kmsClientCache;\n}\n\nasync function getOrCreateKekId(): Promise<string> {\n // NOTE (Hexclave rebrand): do NOT rename this \"stack-*\" alias. It is the AWS KMS key alias for\n // the existing key-encryption key; renaming it would point at a non-existent key and break\n // wrap/unwrap of all stored data keys. Internal infrastructure constant, never user-visible.\n const id = \"alias/stack-data-vault-server-side-kek\";\n const kms = await getKmsClient();\n try {\n const describeResult = await kms.send(new DescribeKeyCommand({ KeyId: id }));\n if (describeResult.KeyMetadata?.KeyId) return describeResult.KeyMetadata.KeyId;\n } catch (e) {\n if (e instanceof Error && e.name !== \"NotFoundException\") {\n throw e;\n }\n }\n const { KeyMetadata } = await kms.send(new CreateKeyCommand({\n KeyUsage: \"ENCRYPT_DECRYPT\",\n Description: \"DataVault KEK\"\n }));\n await kms.send(new CreateAliasCommand({ AliasName: id, TargetKeyId: KeyMetadata!.KeyId! }));\n return id;\n}\n\nasync function genDEK() {\n const kekId = await getOrCreateKekId();\n const kms = await getKmsClient();\n const out = await kms.send(new GenerateDataKeyCommand({ KeyId: kekId, KeySpec: \"AES_256\" }));\n if (!out.Plaintext || !out.CiphertextBlob) throw new Error(\"GenerateDataKey failed\");\n return {\n dekBytes: out.Plaintext,\n edkBytes: out.CiphertextBlob,\n };\n}\n\nasync function unwrapDEK(edk_b64: string) {\n const edkBytes = decodeBase64(edk_b64);\n const kms = await getKmsClient();\n const out = await kms.send(new DecryptCommand({ CiphertextBlob: edkBytes }));\n if (!out.Plaintext) throw new Error(\"KMS Decrypt failed\");\n return {\n dekBytes: out.Plaintext,\n edkBytes,\n };\n}\n\nexport async function encryptWithKms(value: string) {\n const { dekBytes, edkBytes } = await genDEK();\n try {\n const ciphertext = await encrypt({\n // NOTE (Hexclave rebrand): do NOT rename this \"stack-*\" purpose tag — it must match the one\n // used in decryptWithKms below, or already-encrypted values become undecryptable.\n purpose: \"stack-data-vault-server-side-encryption\",\n secret: dekBytes,\n value: new TextEncoder().encode(value),\n });\n return { edkBase64: encodeBase64(edkBytes), ciphertextBase64: encodeBase64(ciphertext) };\n } finally {\n dekBytes.fill(0);\n }\n}\n\nexport async function decryptWithKms(encrypted: Awaited<ReturnType<typeof encryptWithKms>>) {\n const { dekBytes } = await unwrapDEK(encrypted.edkBase64);\n try {\n const value = Result.orThrow(await decrypt({\n purpose: \"stack-data-vault-server-side-encryption\",\n secret: dekBytes,\n cipher: decodeBase64(encrypted.ciphertextBase64),\n }));\n return new TextDecoder().decode(value);\n } finally {\n dekBytes.fill(0);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/hexclave-config-file.d.ts
|
|
2
|
+
declare const showOnboardingHexclaveConfigValue = "show-onboarding";
|
|
3
|
+
/**
|
|
4
|
+
* Renders a config object into the source text of a `stack.config.ts` file.
|
|
5
|
+
*
|
|
6
|
+
* Browser-safe: kept here (next to `parseHexclaveConfigFileContent`) instead of in
|
|
7
|
+
* `config-rendering.ts` so dashboard client code can render config files
|
|
8
|
+
* without pulling in `fs` / `path`.
|
|
9
|
+
*/
|
|
10
|
+
declare function renderConfigFileContent(config: unknown, importPackage?: string): string;
|
|
11
|
+
type ParsedStackConfig = Record<string, unknown> | typeof showOnboardingHexclaveConfigValue;
|
|
12
|
+
declare function parseHexclaveConfigFileContent(content: string, filePath: string): ParsedStackConfig;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { parseHexclaveConfigFileContent, renderConfigFileContent, showOnboardingHexclaveConfigValue };
|
|
15
|
+
//# sourceMappingURL=hexclave-config-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hexclave-config-file.d.ts","names":[],"sources":["../../src/hexclave-config-file.ts"],"mappings":";cAIa,iCAAA;AAAb;;;;;AAWA;;AAXA,iBAWgB,uBAAA,CAAwB,MAAA,WAAiB,aAAA;AAAA,KAmBpD,iBAAA,GAAoB,MAAA,2BAAiC,iCAAA;AAAA,iBA8D1C,8BAAA,CAA+B,OAAA,UAAiB,QAAA,WAAmB,iBAAA"}
|
|
@@ -2,13 +2,13 @@ import * as parser from "@babel/parser";
|
|
|
2
2
|
import * as t from "@babel/types";
|
|
3
3
|
import { isValidConfig, normalize } from "./config/format.js";
|
|
4
4
|
|
|
5
|
-
//#region src/
|
|
6
|
-
const
|
|
5
|
+
//#region src/hexclave-config-file.ts
|
|
6
|
+
const showOnboardingHexclaveConfigValue = "show-onboarding";
|
|
7
7
|
const DEFAULT_CONFIG_IMPORT_PACKAGE = "@hexclave/js";
|
|
8
8
|
/**
|
|
9
9
|
* Renders a config object into the source text of a `stack.config.ts` file.
|
|
10
10
|
*
|
|
11
|
-
* Browser-safe: kept here (next to `
|
|
11
|
+
* Browser-safe: kept here (next to `parseHexclaveConfigFileContent`) instead of in
|
|
12
12
|
* `config-rendering.ts` so dashboard client code can render config files
|
|
13
13
|
* without pulling in `fs` / `path`.
|
|
14
14
|
*/
|
|
@@ -21,7 +21,7 @@ function renderConfigFileContent(config, importPackage) {
|
|
|
21
21
|
droppedKeys
|
|
22
22
|
});
|
|
23
23
|
if (droppedKeys.length > 0) throw new Error(`Config has conflicting keys that would be dropped during normalization: ${droppedKeys.map((k) => JSON.stringify(k)).join(", ")}`);
|
|
24
|
-
return `${`import type {
|
|
24
|
+
return `${`import type { HexclaveConfig } from "${importPackage ?? DEFAULT_CONFIG_IMPORT_PACKAGE}";`}\n\nexport const config: HexclaveConfig = ${JSON.stringify(normalizedConfig, null, 2)};\n`;
|
|
25
25
|
}
|
|
26
26
|
function unwrapStaticConfigExpression(expression) {
|
|
27
27
|
if (t.isTSAsExpression(expression) || t.isTSSatisfiesExpression(expression) || t.isTSTypeAssertion(expression) || t.isTSNonNullExpression(expression)) return unwrapStaticConfigExpression(expression.expression);
|
|
@@ -54,7 +54,7 @@ function evaluateStaticConfigExpression(expression) {
|
|
|
54
54
|
}
|
|
55
55
|
throw new Error(`Unsupported config expression: ${unwrapped.type}`);
|
|
56
56
|
}
|
|
57
|
-
function
|
|
57
|
+
function parseHexclaveConfigFileContent(content, filePath) {
|
|
58
58
|
if (content.trim() === "") return {};
|
|
59
59
|
const ast = parser.parse(content, {
|
|
60
60
|
sourceType: "module",
|
|
@@ -72,5 +72,5 @@ function parseStackConfigFileContent(content, filePath) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
//#endregion
|
|
75
|
-
export {
|
|
76
|
-
//# sourceMappingURL=
|
|
75
|
+
export { parseHexclaveConfigFileContent, renderConfigFileContent, showOnboardingHexclaveConfigValue };
|
|
76
|
+
//# sourceMappingURL=hexclave-config-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hexclave-config-file.js","names":[],"sources":["../../src/hexclave-config-file.ts"],"sourcesContent":["import * as parser from \"@babel/parser\";\nimport * as t from \"@babel/types\";\nimport { isValidConfig, normalize } from \"./config/format\";\n\nexport const showOnboardingHexclaveConfigValue = \"show-onboarding\";\n\nconst DEFAULT_CONFIG_IMPORT_PACKAGE = \"@hexclave/js\";\n\n/**\n * Renders a config object into the source text of a `stack.config.ts` file.\n *\n * Browser-safe: kept here (next to `parseHexclaveConfigFileContent`) instead of in\n * `config-rendering.ts` so dashboard client code can render config files\n * without pulling in `fs` / `path`.\n */\nexport function renderConfigFileContent(config: unknown, importPackage?: string): string {\n if (!isValidConfig(config)) {\n throw new Error(\"Invalid config: expected a plain object.\");\n }\n\n const droppedKeys: string[] = [];\n const normalizedConfig = normalize(config, {\n onDotIntoNonObject: \"ignore\",\n onDotIntoNull: \"empty-object\",\n droppedKeys,\n });\n if (droppedKeys.length > 0) {\n throw new Error(`Config has conflicting keys that would be dropped during normalization: ${droppedKeys.map(k => JSON.stringify(k)).join(\", \")}`);\n }\n const pkg = importPackage ?? DEFAULT_CONFIG_IMPORT_PACKAGE;\n const importLine = `import type { HexclaveConfig } from \"${pkg}\";`;\n return `${importLine}\\n\\nexport const config: HexclaveConfig = ${JSON.stringify(normalizedConfig, null, 2)};\\n`;\n}\n\ntype ParsedStackConfig = Record<string, unknown> | typeof showOnboardingHexclaveConfigValue;\n\nfunction unwrapStaticConfigExpression(expression: t.Expression): t.Expression {\n if (\n t.isTSAsExpression(expression)\n || t.isTSSatisfiesExpression(expression)\n || t.isTSTypeAssertion(expression)\n || t.isTSNonNullExpression(expression)\n ) {\n return unwrapStaticConfigExpression(expression.expression);\n }\n return expression;\n}\n\nfunction evaluateStaticConfigExpression(expression: t.Expression): unknown {\n const unwrapped = unwrapStaticConfigExpression(expression);\n if (t.isStringLiteral(unwrapped)) return unwrapped.value;\n if (t.isBooleanLiteral(unwrapped)) return unwrapped.value;\n if (t.isNumericLiteral(unwrapped)) return unwrapped.value;\n if (t.isNullLiteral(unwrapped)) return null;\n if (t.isIdentifier(unwrapped) && unwrapped.name === \"undefined\") return undefined;\n if (t.isUnaryExpression(unwrapped) && unwrapped.operator === \"-\" && t.isNumericLiteral(unwrapped.argument)) {\n return -unwrapped.argument.value;\n }\n if (t.isArrayExpression(unwrapped)) {\n return unwrapped.elements.map((element) => {\n if (element == null || t.isSpreadElement(element)) {\n throw new Error(\"Config arrays cannot contain holes or spreads.\");\n }\n return evaluateStaticConfigExpression(element);\n });\n }\n if (t.isObjectExpression(unwrapped)) {\n const result: Record<string, unknown> = {};\n for (const property of unwrapped.properties) {\n if (t.isSpreadElement(property)) {\n throw new Error(\"Config objects cannot contain spreads.\");\n }\n if (property.computed) {\n throw new Error(\"Config object keys cannot be computed.\");\n }\n const key = t.isIdentifier(property.key)\n ? property.key.name\n : t.isStringLiteral(property.key) || t.isNumericLiteral(property.key)\n ? String(property.key.value)\n : null;\n if (key == null) {\n throw new Error(\"Unsupported config object key.\");\n }\n if (t.isObjectMethod(property)) {\n throw new Error(\"Config objects cannot contain methods.\");\n }\n if (!t.isExpression(property.value)) {\n throw new Error(\"Unsupported config object value.\");\n }\n result[key] = evaluateStaticConfigExpression(property.value);\n }\n return result;\n }\n throw new Error(`Unsupported config expression: ${unwrapped.type}`);\n}\n\nexport function parseHexclaveConfigFileContent(content: string, filePath: string): ParsedStackConfig {\n if (content.trim() === \"\") return {};\n const ast = parser.parse(content, {\n sourceType: \"module\",\n plugins: [\"typescript\"],\n });\n\n for (const statement of ast.program.body) {\n if (!t.isExportNamedDeclaration(statement) || !t.isVariableDeclaration(statement.declaration)) {\n continue;\n }\n for (const declaration of statement.declaration.declarations) {\n if (!t.isIdentifier(declaration.id) || declaration.id.name !== \"config\") {\n continue;\n }\n if (declaration.init == null || !t.isExpression(declaration.init)) {\n throw new Error(`Config export in ${filePath} must have an initializer.`);\n }\n return evaluateStaticConfigExpression(declaration.init) as ParsedStackConfig;\n }\n }\n\n throw new Error(`Invalid config in ${filePath}. The file must export a plain \\`config\\` object or \"show-onboarding\".`);\n}\n"],"mappings":"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"}
|
|
@@ -150,15 +150,15 @@ declare const MetricsEmailOverviewSchema: yup.ObjectSchema<{
|
|
|
150
150
|
activity: number;
|
|
151
151
|
}[];
|
|
152
152
|
daily_emails_by_status: {
|
|
153
|
-
ok: number;
|
|
154
153
|
error: number;
|
|
155
154
|
date: string;
|
|
155
|
+
ok: number;
|
|
156
156
|
in_progress: number;
|
|
157
157
|
}[];
|
|
158
158
|
emails_sent: number;
|
|
159
159
|
recent_emails: {
|
|
160
|
-
id: string;
|
|
161
160
|
status: string;
|
|
161
|
+
id: string;
|
|
162
162
|
subject: string;
|
|
163
163
|
created_at_millis: number;
|
|
164
164
|
}[];
|
|
@@ -310,9 +310,9 @@ declare const UserActivityResponseBodySchema: yup.ObjectSchema<{
|
|
|
310
310
|
data_points: undefined;
|
|
311
311
|
}, "">;
|
|
312
312
|
declare const MetricsActiveUsersByCountrySchema: yup.MixedSchema<Record<string, {
|
|
313
|
+
primary_email: string | null;
|
|
313
314
|
id: string;
|
|
314
315
|
display_name: string | null;
|
|
315
|
-
primary_email: string | null;
|
|
316
316
|
profile_image_url: string | null;
|
|
317
317
|
signed_up_at_millis: number;
|
|
318
318
|
last_active_at_millis: number | null;
|
|
@@ -330,25 +330,25 @@ declare const MetricsResponseBodySchema: yup.ObjectSchema<{
|
|
|
330
330
|
}[];
|
|
331
331
|
users_by_country: Record<string, number>;
|
|
332
332
|
active_users_by_country: Record<string, {
|
|
333
|
+
primary_email: string | null;
|
|
333
334
|
id: string;
|
|
334
335
|
display_name: string | null;
|
|
335
|
-
primary_email: string | null;
|
|
336
336
|
profile_image_url: string | null;
|
|
337
337
|
signed_up_at_millis: number;
|
|
338
338
|
last_active_at_millis: number | null;
|
|
339
339
|
}[]>;
|
|
340
340
|
recently_registered: {
|
|
341
|
+
primary_email: string | null;
|
|
341
342
|
id: string;
|
|
342
343
|
display_name: string | null;
|
|
343
|
-
primary_email: string | null;
|
|
344
344
|
profile_image_url: string | null;
|
|
345
345
|
signed_up_at_millis: number;
|
|
346
346
|
last_active_at_millis: number | null;
|
|
347
347
|
}[];
|
|
348
348
|
recently_active: {
|
|
349
|
+
primary_email: string | null;
|
|
349
350
|
id: string;
|
|
350
351
|
display_name: string | null;
|
|
351
|
-
primary_email: string | null;
|
|
352
352
|
profile_image_url: string | null;
|
|
353
353
|
signed_up_at_millis: number;
|
|
354
354
|
last_active_at_millis: number | null;
|
|
@@ -422,15 +422,15 @@ declare const MetricsResponseBodySchema: yup.ObjectSchema<{
|
|
|
422
422
|
emails_by_status: Record<string, number>;
|
|
423
423
|
total_emails: number;
|
|
424
424
|
daily_emails_by_status: {
|
|
425
|
-
ok: number;
|
|
426
425
|
error: number;
|
|
427
426
|
date: string;
|
|
427
|
+
ok: number;
|
|
428
428
|
in_progress: number;
|
|
429
429
|
}[];
|
|
430
430
|
emails_sent: number;
|
|
431
431
|
recent_emails: {
|
|
432
|
-
id: string;
|
|
433
432
|
status: string;
|
|
433
|
+
id: string;
|
|
434
434
|
subject: string;
|
|
435
435
|
created_at_millis: number;
|
|
436
436
|
}[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-metrics.js","names":[],"sources":["../../../src/interface/admin-metrics.ts"],"sourcesContent":["import yup from \"yup\";\nimport { yupArray, yupMixed, yupNumber, yupObject, yupRecord, yupString } from \"../schema-fields\";\n\n// Single source of truth for the `/internal/metrics` endpoint shape.\n//\n// Both the backend route handler (`apps/backend/src/app/api/latest/internal/metrics/route.tsx`)\n// and the dashboard hook (`apps/dashboard/src/lib/stack-app-internals.ts`) import\n// these schemas. The runtime validation lives in the schemas; the static types\n// are derived via `yup.InferType` so we never have to keep parallel copies in\n// sync.\n\nexport const MetricsDataPointSchema = yupObject({\n date: yupString().defined(),\n activity: yupNumber().defined(),\n}).defined();\n\nexport const MetricsDataPointsSchema = yupArray(MetricsDataPointSchema).defined();\n\nexport const MetricsActivitySplitSchema = yupObject({\n total: MetricsDataPointsSchema,\n new: MetricsDataPointsSchema,\n retained: MetricsDataPointsSchema,\n reactivated: MetricsDataPointsSchema,\n}).defined();\n\nexport const MetricsAuthOverviewSchema = yupObject({\n verified_users: yupNumber().integer().defined(),\n unverified_users: yupNumber().integer().defined(),\n anonymous_users: yupNumber().integer().defined(),\n total_teams: yupNumber().integer().defined(),\n mau: yupNumber().integer().defined(),\n daily_active_users_split: MetricsActivitySplitSchema,\n daily_active_teams_split: MetricsActivitySplitSchema,\n total_users_filtered: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsPaymentsOverviewSchema = yupObject({\n subscriptions_by_status: yupRecord(yupString().defined(), yupNumber().defined()).defined(),\n active_subscription_count: yupNumber().integer().defined(),\n total_one_time_purchases: yupNumber().integer().defined(),\n daily_subscriptions: MetricsDataPointsSchema,\n revenue_cents: yupNumber().integer().defined(),\n mrr_cents: yupNumber().integer().defined(),\n total_orders: yupNumber().integer().defined(),\n checkout_conversion_rate: yupNumber().defined(),\n}).defined();\n\nexport const MetricsRecentEmailSchema = yupObject({\n id: yupString().defined(),\n status: yupString().defined(),\n subject: yupString().defined(),\n created_at_millis: yupNumber().defined(),\n}).defined();\n\nexport const MetricsDailyEmailStatusBreakdownSchema = yupObject({\n date: yupString().defined(),\n ok: yupNumber().integer().defined(),\n error: yupNumber().integer().defined(),\n in_progress: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsEmailOverviewSchema = yupObject({\n emails_by_status: yupRecord(yupString().defined(), yupNumber().defined()).defined(),\n total_emails: yupNumber().integer().defined(),\n daily_emails: MetricsDataPointsSchema,\n daily_emails_by_status: yupArray(MetricsDailyEmailStatusBreakdownSchema).defined(),\n emails_sent: yupNumber().integer().defined(),\n recent_emails: yupArray(MetricsRecentEmailSchema).defined(),\n deliverability_status: yupObject({\n delivered: yupNumber().integer().defined(),\n bounced: yupNumber().integer().defined(),\n error: yupNumber().integer().defined(),\n in_progress: yupNumber().integer().defined(),\n }).defined(),\n deliverability_rate: yupNumber().defined(),\n bounce_rate: yupNumber().defined(),\n click_rate: yupNumber().defined(),\n}).defined();\n\nexport const MetricsDailyRevenuePointSchema = yupObject({\n date: yupString().defined(),\n new_cents: yupNumber().integer().defined(),\n refund_cents: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsTopReferrerSchema = yupObject({\n referrer: yupString().defined(),\n visitors: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsTopRegionSchema = yupObject({\n country_code: yupString().nullable().defined(),\n region_code: yupString().nullable().defined(),\n count: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsAnalyticsOverviewSchema = yupObject({\n daily_page_views: MetricsDataPointsSchema,\n daily_clicks: MetricsDataPointsSchema,\n daily_visitors: MetricsDataPointsSchema,\n // Token-refresh-derived anonymous-visitor fallback. Populated only when the\n // analytics app isn't installed (no `$page-view` events) — counts DISTINCT\n // anonymous users per day from the events table. See\n // `loadAnonymousVisitorsFromTokenRefresh` in the backend metrics route.\n //\n // Optional for one release cycle so older clients/servers don't hard-fail\n // validation during a staged rollout. Tighten to `.defined()` after.\n daily_anonymous_visitors_fallback: yupArray(MetricsDataPointSchema).optional().default([]),\n daily_revenue: yupArray(MetricsDailyRevenuePointSchema).defined(),\n total_revenue_cents: yupNumber().integer().defined(),\n total_replays: yupNumber().integer().defined(),\n recent_replays: yupNumber().integer().defined(),\n visitors: yupNumber().integer().defined(),\n anonymous_visitors_fallback: yupNumber().integer().optional().default(0),\n avg_session_seconds: yupNumber().defined(),\n online_live: yupNumber().integer().defined(),\n revenue_per_visitor: yupNumber().defined(),\n top_referrers: yupArray(MetricsTopReferrerSchema).defined(),\n top_region: MetricsTopRegionSchema.nullable().defined(),\n // dev-fallback fields (only present in non-production environments)\n bounce_rate: yupNumber().optional(),\n conversion_rate: yupNumber().optional(),\n deltas: yupMixed().optional(),\n}).defined();\n\nexport const MetricsLoginMethodEntrySchema = yupObject({\n method: yupString().defined(),\n count: yupNumber().integer().defined(),\n}).defined();\n\n// Recent user summary — a slim projection of UsersCrud[\"Admin\"][\"Read\"] with\n// just the fields the overview list views actually read. Defined here so the\n// metrics response stays self-contained and doesn't pull in users-crud.\n//\n// `.noUnknown(false)` tells our strict object validator to allow the extra\n// fields that the backend returns as part of the full users-crud payload —\n// `is_anonymous`, `has_password`, `oauth_providers`, etc. — without rejecting\n// them. Only the keys explicitly listed here are validated; extras pass through.\nexport const MetricsRecentUserSchema = yupObject({\n id: yupString().defined(),\n display_name: yupString().nullable().defined(),\n primary_email: yupString().nullable().defined(),\n profile_image_url: yupString().nullable().defined(),\n signed_up_at_millis: yupNumber().defined(),\n last_active_at_millis: yupNumber().nullable().defined(),\n}).noUnknown(false).defined();\n\n// Per-user activity heatmap — a simple list of daily event counts for a single\n// user. Backed by ClickHouse `analytics_internal.events` filtered by user_id,\n// project_id, and branch_id. See `/internal/user-activity` on the backend.\nexport const UserActivityResponseBodySchema = yupObject({\n data_points: MetricsDataPointsSchema,\n}).defined();\n\n// Recent \"currently live\" users keyed by ISO country code. Populated by\n// joining a bounded ClickHouse selection from the live `$token-refresh` window\n// with the corresponding Prisma profile rows, so the overview globe can render\n// real avatars of real users from each country. Optional for one release cycle\n// so clients talking to older servers don't fail validation on the returned\n// body.\nexport const MetricsActiveUsersByCountrySchema = yupRecord(\n yupString().defined(),\n yupArray(MetricsRecentUserSchema).defined(),\n).optional().default({});\n\nexport const MetricsResponseBodySchema = yupObject({\n total_users: yupNumber().integer().defined(),\n // Count of distinct users seen refreshing a token in the last ~2 minutes —\n // the \"who's online right now\" number rendered on the overview globe. Derived\n // from the same `$token-refresh` window that powers `active_users_by_country`,\n // so it works for every project regardless of whether the analytics app\n // (page-view-based `analytics_overview.online_live`) is installed.\n //\n // Optional for one release cycle so older servers don't fail schema\n // validation on the returned body. Tighten to `.defined()` after.\n live_users: yupNumber().integer().optional().default(0),\n daily_users: MetricsDataPointsSchema,\n daily_active_users: MetricsDataPointsSchema,\n users_by_country: yupRecord(yupString().defined(), yupNumber().defined()).defined(),\n active_users_by_country: MetricsActiveUsersByCountrySchema,\n // recently_registered/active are CRUD User objects passed through from the\n // backend. The schema only validates the fields the dashboard actually\n // reads — extra fields from UsersCrud[\"Admin\"][\"Read\"] are allowed through.\n recently_registered: yupArray(MetricsRecentUserSchema).defined(),\n recently_active: yupArray(MetricsRecentUserSchema).defined(),\n login_methods: yupArray(MetricsLoginMethodEntrySchema).defined(),\n auth_overview: MetricsAuthOverviewSchema,\n payments_overview: MetricsPaymentsOverviewSchema,\n email_overview: MetricsEmailOverviewSchema,\n analytics_overview: MetricsAnalyticsOverviewSchema,\n}).defined();\n\nexport const MetricsUserCountsSchema = yupObject({\n total_users: yupNumber().integer().defined(),\n anonymous_users: yupNumber().integer().defined(),\n}).defined();\n\n// Derived static types — single source of truth lives in the schemas above.\nexport type MetricsDataPoint = yup.InferType<typeof MetricsDataPointSchema>;\nexport type MetricsActivitySplit = yup.InferType<typeof MetricsActivitySplitSchema>;\nexport type MetricsAuthOverview = yup.InferType<typeof MetricsAuthOverviewSchema>;\nexport type MetricsPaymentsOverview = yup.InferType<typeof MetricsPaymentsOverviewSchema>;\nexport type MetricsRecentEmail = yup.InferType<typeof MetricsRecentEmailSchema>;\nexport type MetricsDailyEmailStatusBreakdown = yup.InferType<typeof MetricsDailyEmailStatusBreakdownSchema>;\nexport type MetricsEmailOverview = yup.InferType<typeof MetricsEmailOverviewSchema>;\nexport type MetricsDailyRevenuePoint = yup.InferType<typeof MetricsDailyRevenuePointSchema>;\nexport type MetricsTopReferrer = yup.InferType<typeof MetricsTopReferrerSchema>;\nexport type MetricsTopRegion = yup.InferType<typeof MetricsTopRegionSchema>;\nexport type MetricsAnalyticsOverview = yup.InferType<typeof MetricsAnalyticsOverviewSchema>;\nexport type MetricsLoginMethodEntry = yup.InferType<typeof MetricsLoginMethodEntrySchema>;\nexport type MetricsRecentUser = yup.InferType<typeof MetricsRecentUserSchema>;\nexport type MetricsResponse = yup.InferType<typeof MetricsResponseBodySchema>;\nexport type MetricsUserCounts = yup.InferType<typeof MetricsUserCountsSchema>;\nexport type UserActivityResponse = yup.InferType<typeof UserActivityResponseBodySchema>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-metrics.js","names":[],"sources":["../../../src/interface/admin-metrics.ts"],"sourcesContent":["import yup from \"yup\";\nimport { yupArray, yupMixed, yupNumber, yupObject, yupRecord, yupString } from \"../schema-fields\";\n\n// Single source of truth for the `/internal/metrics` endpoint shape.\n//\n// Both the backend route handler (`apps/backend/src/app/api/latest/internal/metrics/route.tsx`)\n// and the dashboard hook (`apps/dashboard/src/lib/hexclave-app-internals.ts`) import\n// these schemas. The runtime validation lives in the schemas; the static types\n// are derived via `yup.InferType` so we never have to keep parallel copies in\n// sync.\n\nexport const MetricsDataPointSchema = yupObject({\n date: yupString().defined(),\n activity: yupNumber().defined(),\n}).defined();\n\nexport const MetricsDataPointsSchema = yupArray(MetricsDataPointSchema).defined();\n\nexport const MetricsActivitySplitSchema = yupObject({\n total: MetricsDataPointsSchema,\n new: MetricsDataPointsSchema,\n retained: MetricsDataPointsSchema,\n reactivated: MetricsDataPointsSchema,\n}).defined();\n\nexport const MetricsAuthOverviewSchema = yupObject({\n verified_users: yupNumber().integer().defined(),\n unverified_users: yupNumber().integer().defined(),\n anonymous_users: yupNumber().integer().defined(),\n total_teams: yupNumber().integer().defined(),\n mau: yupNumber().integer().defined(),\n daily_active_users_split: MetricsActivitySplitSchema,\n daily_active_teams_split: MetricsActivitySplitSchema,\n total_users_filtered: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsPaymentsOverviewSchema = yupObject({\n subscriptions_by_status: yupRecord(yupString().defined(), yupNumber().defined()).defined(),\n active_subscription_count: yupNumber().integer().defined(),\n total_one_time_purchases: yupNumber().integer().defined(),\n daily_subscriptions: MetricsDataPointsSchema,\n revenue_cents: yupNumber().integer().defined(),\n mrr_cents: yupNumber().integer().defined(),\n total_orders: yupNumber().integer().defined(),\n checkout_conversion_rate: yupNumber().defined(),\n}).defined();\n\nexport const MetricsRecentEmailSchema = yupObject({\n id: yupString().defined(),\n status: yupString().defined(),\n subject: yupString().defined(),\n created_at_millis: yupNumber().defined(),\n}).defined();\n\nexport const MetricsDailyEmailStatusBreakdownSchema = yupObject({\n date: yupString().defined(),\n ok: yupNumber().integer().defined(),\n error: yupNumber().integer().defined(),\n in_progress: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsEmailOverviewSchema = yupObject({\n emails_by_status: yupRecord(yupString().defined(), yupNumber().defined()).defined(),\n total_emails: yupNumber().integer().defined(),\n daily_emails: MetricsDataPointsSchema,\n daily_emails_by_status: yupArray(MetricsDailyEmailStatusBreakdownSchema).defined(),\n emails_sent: yupNumber().integer().defined(),\n recent_emails: yupArray(MetricsRecentEmailSchema).defined(),\n deliverability_status: yupObject({\n delivered: yupNumber().integer().defined(),\n bounced: yupNumber().integer().defined(),\n error: yupNumber().integer().defined(),\n in_progress: yupNumber().integer().defined(),\n }).defined(),\n deliverability_rate: yupNumber().defined(),\n bounce_rate: yupNumber().defined(),\n click_rate: yupNumber().defined(),\n}).defined();\n\nexport const MetricsDailyRevenuePointSchema = yupObject({\n date: yupString().defined(),\n new_cents: yupNumber().integer().defined(),\n refund_cents: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsTopReferrerSchema = yupObject({\n referrer: yupString().defined(),\n visitors: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsTopRegionSchema = yupObject({\n country_code: yupString().nullable().defined(),\n region_code: yupString().nullable().defined(),\n count: yupNumber().integer().defined(),\n}).defined();\n\nexport const MetricsAnalyticsOverviewSchema = yupObject({\n daily_page_views: MetricsDataPointsSchema,\n daily_clicks: MetricsDataPointsSchema,\n daily_visitors: MetricsDataPointsSchema,\n // Token-refresh-derived anonymous-visitor fallback. Populated only when the\n // analytics app isn't installed (no `$page-view` events) — counts DISTINCT\n // anonymous users per day from the events table. See\n // `loadAnonymousVisitorsFromTokenRefresh` in the backend metrics route.\n //\n // Optional for one release cycle so older clients/servers don't hard-fail\n // validation during a staged rollout. Tighten to `.defined()` after.\n daily_anonymous_visitors_fallback: yupArray(MetricsDataPointSchema).optional().default([]),\n daily_revenue: yupArray(MetricsDailyRevenuePointSchema).defined(),\n total_revenue_cents: yupNumber().integer().defined(),\n total_replays: yupNumber().integer().defined(),\n recent_replays: yupNumber().integer().defined(),\n visitors: yupNumber().integer().defined(),\n anonymous_visitors_fallback: yupNumber().integer().optional().default(0),\n avg_session_seconds: yupNumber().defined(),\n online_live: yupNumber().integer().defined(),\n revenue_per_visitor: yupNumber().defined(),\n top_referrers: yupArray(MetricsTopReferrerSchema).defined(),\n top_region: MetricsTopRegionSchema.nullable().defined(),\n // dev-fallback fields (only present in non-production environments)\n bounce_rate: yupNumber().optional(),\n conversion_rate: yupNumber().optional(),\n deltas: yupMixed().optional(),\n}).defined();\n\nexport const MetricsLoginMethodEntrySchema = yupObject({\n method: yupString().defined(),\n count: yupNumber().integer().defined(),\n}).defined();\n\n// Recent user summary — a slim projection of UsersCrud[\"Admin\"][\"Read\"] with\n// just the fields the overview list views actually read. Defined here so the\n// metrics response stays self-contained and doesn't pull in users-crud.\n//\n// `.noUnknown(false)` tells our strict object validator to allow the extra\n// fields that the backend returns as part of the full users-crud payload —\n// `is_anonymous`, `has_password`, `oauth_providers`, etc. — without rejecting\n// them. Only the keys explicitly listed here are validated; extras pass through.\nexport const MetricsRecentUserSchema = yupObject({\n id: yupString().defined(),\n display_name: yupString().nullable().defined(),\n primary_email: yupString().nullable().defined(),\n profile_image_url: yupString().nullable().defined(),\n signed_up_at_millis: yupNumber().defined(),\n last_active_at_millis: yupNumber().nullable().defined(),\n}).noUnknown(false).defined();\n\n// Per-user activity heatmap — a simple list of daily event counts for a single\n// user. Backed by ClickHouse `analytics_internal.events` filtered by user_id,\n// project_id, and branch_id. See `/internal/user-activity` on the backend.\nexport const UserActivityResponseBodySchema = yupObject({\n data_points: MetricsDataPointsSchema,\n}).defined();\n\n// Recent \"currently live\" users keyed by ISO country code. Populated by\n// joining a bounded ClickHouse selection from the live `$token-refresh` window\n// with the corresponding Prisma profile rows, so the overview globe can render\n// real avatars of real users from each country. Optional for one release cycle\n// so clients talking to older servers don't fail validation on the returned\n// body.\nexport const MetricsActiveUsersByCountrySchema = yupRecord(\n yupString().defined(),\n yupArray(MetricsRecentUserSchema).defined(),\n).optional().default({});\n\nexport const MetricsResponseBodySchema = yupObject({\n total_users: yupNumber().integer().defined(),\n // Count of distinct users seen refreshing a token in the last ~2 minutes —\n // the \"who's online right now\" number rendered on the overview globe. Derived\n // from the same `$token-refresh` window that powers `active_users_by_country`,\n // so it works for every project regardless of whether the analytics app\n // (page-view-based `analytics_overview.online_live`) is installed.\n //\n // Optional for one release cycle so older servers don't fail schema\n // validation on the returned body. Tighten to `.defined()` after.\n live_users: yupNumber().integer().optional().default(0),\n daily_users: MetricsDataPointsSchema,\n daily_active_users: MetricsDataPointsSchema,\n users_by_country: yupRecord(yupString().defined(), yupNumber().defined()).defined(),\n active_users_by_country: MetricsActiveUsersByCountrySchema,\n // recently_registered/active are CRUD User objects passed through from the\n // backend. The schema only validates the fields the dashboard actually\n // reads — extra fields from UsersCrud[\"Admin\"][\"Read\"] are allowed through.\n recently_registered: yupArray(MetricsRecentUserSchema).defined(),\n recently_active: yupArray(MetricsRecentUserSchema).defined(),\n login_methods: yupArray(MetricsLoginMethodEntrySchema).defined(),\n auth_overview: MetricsAuthOverviewSchema,\n payments_overview: MetricsPaymentsOverviewSchema,\n email_overview: MetricsEmailOverviewSchema,\n analytics_overview: MetricsAnalyticsOverviewSchema,\n}).defined();\n\nexport const MetricsUserCountsSchema = yupObject({\n total_users: yupNumber().integer().defined(),\n anonymous_users: yupNumber().integer().defined(),\n}).defined();\n\n// Derived static types — single source of truth lives in the schemas above.\nexport type MetricsDataPoint = yup.InferType<typeof MetricsDataPointSchema>;\nexport type MetricsActivitySplit = yup.InferType<typeof MetricsActivitySplitSchema>;\nexport type MetricsAuthOverview = yup.InferType<typeof MetricsAuthOverviewSchema>;\nexport type MetricsPaymentsOverview = yup.InferType<typeof MetricsPaymentsOverviewSchema>;\nexport type MetricsRecentEmail = yup.InferType<typeof MetricsRecentEmailSchema>;\nexport type MetricsDailyEmailStatusBreakdown = yup.InferType<typeof MetricsDailyEmailStatusBreakdownSchema>;\nexport type MetricsEmailOverview = yup.InferType<typeof MetricsEmailOverviewSchema>;\nexport type MetricsDailyRevenuePoint = yup.InferType<typeof MetricsDailyRevenuePointSchema>;\nexport type MetricsTopReferrer = yup.InferType<typeof MetricsTopReferrerSchema>;\nexport type MetricsTopRegion = yup.InferType<typeof MetricsTopRegionSchema>;\nexport type MetricsAnalyticsOverview = yup.InferType<typeof MetricsAnalyticsOverviewSchema>;\nexport type MetricsLoginMethodEntry = yup.InferType<typeof MetricsLoginMethodEntrySchema>;\nexport type MetricsRecentUser = yup.InferType<typeof MetricsRecentUserSchema>;\nexport type MetricsResponse = yup.InferType<typeof MetricsResponseBodySchema>;\nexport type MetricsUserCounts = yup.InferType<typeof MetricsUserCountsSchema>;\nexport type UserActivityResponse = yup.InferType<typeof UserActivityResponseBodySchema>;\n"],"mappings":"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"}
|
|
@@ -11,9 +11,9 @@ import { globalVar } from "../utils/globals.js";
|
|
|
11
11
|
import { HTTP_METHODS } from "../utils/http.js";
|
|
12
12
|
import { wait } from "../utils/promises.js";
|
|
13
13
|
|
|
14
|
-
//#region ../../node_modules/.pnpm/oauth4webapi@3.8.
|
|
14
|
+
//#region ../../node_modules/.pnpm/oauth4webapi@3.8.5/node_modules/oauth4webapi/build/index.js
|
|
15
15
|
let USER_AGENT;
|
|
16
|
-
if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) USER_AGENT = `oauth4webapi/v3.8.
|
|
16
|
+
if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) USER_AGENT = `oauth4webapi/v3.8.5`;
|
|
17
17
|
function looseInstanceOf(input, expected) {
|
|
18
18
|
if (input == null) return false;
|
|
19
19
|
try {
|