@hexclave/shared 1.0.3 → 1.0.6
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 +216 -29
- 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 +1 -1
- 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 +215 -30
- 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 +1 -1
- 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/interface/admin-metrics.d.ts +2 -2
- 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 +7 -7
- package/dist/esm/interface/crud/email-outbox.d.ts +42 -42
- 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/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/users.d.ts +10 -10
- 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 +1 -1
- package/dist/esm/known-errors.d.ts.map +1 -1
- package/dist/esm/known-errors.js +9 -5
- package/dist/esm/known-errors.js.map +1 -1
- package/dist/esm/schema-fields.d.ts +15 -5
- 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/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/interface/admin-metrics.d.ts +12 -12
- 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 +7 -7
- package/dist/interface/crud/email-outbox.d.ts +42 -42
- package/dist/interface/crud/project-permissions.js +5 -5
- package/dist/interface/crud/project-permissions.js.map +1 -1
- 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/users.d.ts +10 -10
- 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 +1 -1
- package/dist/known-errors.d.ts.map +1 -1
- package/dist/known-errors.js +9 -5
- package/dist/known-errors.js.map +1 -1
- package/dist/schema-fields.d.ts +15 -5
- 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/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 +2034 -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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { expect, it } from "vitest";
|
|
2
|
+
import { typeAssertExtends } from "./utils/types";
|
|
3
|
+
import { defineStackConfig, type StackConfig } from "./config-authoring";
|
|
4
|
+
|
|
5
|
+
const validConfig = defineStackConfig({
|
|
6
|
+
payments: {
|
|
7
|
+
items: {
|
|
8
|
+
todos: {
|
|
9
|
+
displayName: "Todo Slots",
|
|
10
|
+
customerType: "user",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
const showOnboardingConfig = defineStackConfig("show-onboarding");
|
|
16
|
+
|
|
17
|
+
typeAssertExtends<typeof validConfig, StackConfig>()();
|
|
18
|
+
typeAssertExtends<typeof showOnboardingConfig, StackConfig>()();
|
|
19
|
+
|
|
20
|
+
it("returns its input unchanged", () => {
|
|
21
|
+
expect(defineStackConfig(validConfig)).toBe(validConfig);
|
|
22
|
+
expect(defineStackConfig(showOnboardingConfig)).toBe(showOnboardingConfig);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
defineStackConfig({
|
|
26
|
+
// @ts-expect-error Top-level dot notation should not be accepted in typed config files.
|
|
27
|
+
"payments.items": {
|
|
28
|
+
todos: {
|
|
29
|
+
displayName: "Todo Slots",
|
|
30
|
+
customerType: "user",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
defineStackConfig({
|
|
36
|
+
payments: {
|
|
37
|
+
// @ts-expect-error Unknown keys should not be accepted in typed config files.
|
|
38
|
+
missingField: true,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
defineStackConfig({
|
|
43
|
+
payments: {
|
|
44
|
+
items: {
|
|
45
|
+
todos: {
|
|
46
|
+
displayName: "Todo Slots",
|
|
47
|
+
// @ts-expect-error Invalid enum values should fail type-checking.
|
|
48
|
+
customerType: "workspace",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { BranchConfigNormalizedOverride } from "./config/schema";
|
|
2
|
+
|
|
3
|
+
type StackConfigObject = BranchConfigNormalizedOverride;
|
|
4
|
+
export const showOnboardingHexclaveConfigValue = "show-onboarding";
|
|
5
|
+
/** @deprecated Use `HexclaveConfig` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */
|
|
6
|
+
export type StackConfig = StackConfigObject | typeof showOnboardingHexclaveConfigValue;
|
|
7
|
+
|
|
8
|
+
// Hexclave alias — same shape, declared separately so it doesn't inherit the deprecation tag.
|
|
9
|
+
export type HexclaveConfig = StackConfigObject | typeof showOnboardingHexclaveConfigValue;
|
|
10
|
+
|
|
11
|
+
type StrictConfigShape<Actual, Expected> =
|
|
12
|
+
Expected extends readonly unknown[]
|
|
13
|
+
? Actual extends readonly unknown[]
|
|
14
|
+
? { [K in keyof Actual]: K extends keyof Expected ? StrictConfigShape<Actual[K], Expected[K]> : never }
|
|
15
|
+
: Actual
|
|
16
|
+
: Expected extends object
|
|
17
|
+
? Actual extends object
|
|
18
|
+
? Exclude<keyof Actual, keyof Expected> extends never
|
|
19
|
+
? { [K in keyof Actual]: K extends keyof Expected ? StrictConfigShape<Actual[K], Expected[K]> : never }
|
|
20
|
+
: never
|
|
21
|
+
: Actual
|
|
22
|
+
: Actual;
|
|
23
|
+
|
|
24
|
+
type StrictStackConfig<T extends StackConfig> =
|
|
25
|
+
T extends StackConfigObject
|
|
26
|
+
? T & StrictConfigShape<T, StackConfigObject>
|
|
27
|
+
: T;
|
|
28
|
+
|
|
29
|
+
/** @deprecated Use `defineHexclaveConfig` from the `@hexclave/*` package instead — same symbol, new brand name. See https://docs.hexclave.com/migration. */
|
|
30
|
+
export function defineStackConfig<const T extends StackConfig>(config: StrictStackConfig<T>): T {
|
|
31
|
+
return config;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Hexclave alias — separate function so it does not inherit the deprecation tag.
|
|
35
|
+
export function defineHexclaveConfig<const T extends HexclaveConfig>(config: StrictStackConfig<T>): T {
|
|
36
|
+
return config;
|
|
37
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { parseHexclaveConfigFileContent, renderConfigFileContent } from "./hexclave-config-file";
|
|
4
|
+
export { parseHexclaveConfigFileContent, renderConfigFileContent };
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Packages that export the `HexclaveConfig` type, in priority order.
|
|
8
|
+
* The first match found in a project's dependencies wins. Hexclave-branded
|
|
9
|
+
* packages come first (canonical); the legacy `@stackframe/*` names remain
|
|
10
|
+
* so projects pinned to the last legacy release still render a config file
|
|
11
|
+
* that compiles against their installed SDK.
|
|
12
|
+
*/
|
|
13
|
+
const CONFIG_IMPORT_PACKAGES = [
|
|
14
|
+
"@hexclave/next",
|
|
15
|
+
"@hexclave/react",
|
|
16
|
+
"@hexclave/js",
|
|
17
|
+
"@hexclave/template",
|
|
18
|
+
"@stackframe/stack",
|
|
19
|
+
"@stackframe/react",
|
|
20
|
+
"@stackframe/js",
|
|
21
|
+
"@stackframe/template",
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Given a list of dependency names (from package.json), returns the SDK
|
|
26
|
+
* package that should be used for the `HexclaveConfig` import, or `undefined`
|
|
27
|
+
* if none of the known packages are installed.
|
|
28
|
+
*/
|
|
29
|
+
export function detectConfigImportPackage(dependencies: string[]): string | undefined {
|
|
30
|
+
for (const pkg of CONFIG_IMPORT_PACKAGES) {
|
|
31
|
+
if (dependencies.includes(pkg)) {
|
|
32
|
+
return pkg;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Walks up from `dir` to find the nearest `package.json` and returns the
|
|
40
|
+
* best SDK package to use for the `HexclaveConfig` type import.
|
|
41
|
+
*/
|
|
42
|
+
export function detectImportPackageFromDir(dir: string): string | undefined {
|
|
43
|
+
let current = dir;
|
|
44
|
+
while (true) {
|
|
45
|
+
const pkgPath = path.join(current, "package.json");
|
|
46
|
+
if (existsSync(pkgPath)) {
|
|
47
|
+
try {
|
|
48
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
49
|
+
const deps = [
|
|
50
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
51
|
+
...Object.keys(pkg.devDependencies ?? {}),
|
|
52
|
+
];
|
|
53
|
+
return detectConfigImportPackage(deps);
|
|
54
|
+
} catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const parent = path.dirname(current);
|
|
59
|
+
if (parent === current) break;
|
|
60
|
+
current = parent;
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
import.meta.vitest?.test("renderConfigFileContent normalizes config exports", ({ expect }) => {
|
|
66
|
+
expect(renderConfigFileContent({
|
|
67
|
+
"payments.items.todos.displayName": "Todo Slots",
|
|
68
|
+
"payments.items.todos.customerType": "user",
|
|
69
|
+
})).toContain(`export const config: HexclaveConfig = {
|
|
70
|
+
"payments": {
|
|
71
|
+
"items": {
|
|
72
|
+
"todos": {
|
|
73
|
+
"displayName": "Todo Slots",
|
|
74
|
+
"customerType": "user"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};`);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
import.meta.vitest?.test("parseHexclaveConfigFileContent parses static config exports", ({ expect }) => {
|
|
82
|
+
expect(parseHexclaveConfigFileContent(`
|
|
83
|
+
import type { StackConfig } from "@hexclave/js";
|
|
84
|
+
export const config: StackConfig = {
|
|
85
|
+
auth: { allowSignUp: true },
|
|
86
|
+
payments: { testMode: false },
|
|
87
|
+
};
|
|
88
|
+
`, "stack.config.ts")).toMatchInlineSnapshot(`
|
|
89
|
+
{
|
|
90
|
+
"auth": {
|
|
91
|
+
"allowSignUp": true,
|
|
92
|
+
},
|
|
93
|
+
"payments": {
|
|
94
|
+
"testMode": false,
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
`);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
import.meta.vitest?.test("parseHexclaveConfigFileContent parses show-onboarding", ({ expect }) => {
|
|
101
|
+
expect(parseHexclaveConfigFileContent('export const config = "show-onboarding";', "stack.config.ts")).toBe("show-onboarding");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
import.meta.vitest?.test("parseHexclaveConfigFileContent rejects dynamic config exports", ({ expect }) => {
|
|
105
|
+
expect(() => parseHexclaveConfigFileContent("export const config = makeConfig();", "stack.config.ts")).toThrow(/Unsupported config expression/);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
import.meta.vitest?.test("renderConfigFileContent rejects conflicting dotted keys", ({ expect }) => {
|
|
109
|
+
expect(() => renderConfigFileContent({
|
|
110
|
+
"a.b": 1,
|
|
111
|
+
"a.b.c": 2,
|
|
112
|
+
})).toThrowError(/conflicting keys.*"a\.b\.c"/);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
import.meta.vitest?.test("renderConfigFileContent rejects invalid config exports", ({ expect }) => {
|
|
116
|
+
expect(() => renderConfigFileContent(null)).toThrowErrorMatchingInlineSnapshot(
|
|
117
|
+
`[Error: Invalid config: expected a plain object.]`,
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
import.meta.vitest?.test("renderConfigFileContent uses custom import package", ({ expect }) => {
|
|
122
|
+
const content = renderConfigFileContent({}, "@hexclave/next");
|
|
123
|
+
expect(content).toContain('import type { HexclaveConfig } from "@hexclave/next";');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
import.meta.vitest?.test("renderConfigFileContent defaults to @hexclave/js", ({ expect }) => {
|
|
127
|
+
const content = renderConfigFileContent({});
|
|
128
|
+
expect(content).toContain('import type { HexclaveConfig } from "@hexclave/js";');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
import.meta.vitest?.test("detectConfigImportPackage picks first matching package by priority", ({ expect }) => {
|
|
132
|
+
expect(detectConfigImportPackage(["@hexclave/next", "@hexclave/js"])).toBe("@hexclave/next");
|
|
133
|
+
expect(detectConfigImportPackage(["@hexclave/react", "@hexclave/js"])).toBe("@hexclave/react");
|
|
134
|
+
expect(detectConfigImportPackage(["@hexclave/js"])).toBe("@hexclave/js");
|
|
135
|
+
// Hexclave names take priority over legacy stackframe names when both appear.
|
|
136
|
+
expect(detectConfigImportPackage(["@stackframe/stack", "@hexclave/next"])).toBe("@hexclave/next");
|
|
137
|
+
// Legacy fallback still works for projects pinned to the last @stackframe/* release.
|
|
138
|
+
expect(detectConfigImportPackage(["@stackframe/stack"])).toBe("@stackframe/stack");
|
|
139
|
+
expect(detectConfigImportPackage(["@stackframe/template"])).toBe("@stackframe/template");
|
|
140
|
+
expect(detectConfigImportPackage(["lodash", "express"])).toBeUndefined();
|
|
141
|
+
expect(detectConfigImportPackage([])).toBeUndefined();
|
|
142
|
+
});
|
package/src/crud.tsx
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import * as yup from 'yup';
|
|
2
|
+
import { yupObject, yupString } from './schema-fields';
|
|
3
|
+
import { filterUndefined } from './utils/objects';
|
|
4
|
+
import { NullishCoalesce } from './utils/types';
|
|
5
|
+
|
|
6
|
+
export type AccessType = "client" | "server" | "admin";
|
|
7
|
+
export type CrudOperation = "create" | "read" | "update" | "delete";
|
|
8
|
+
export type CrudlOperation = "create" | "read" | "update" | "delete" | "list";
|
|
9
|
+
export type AccessTypeXCrudOperation = `${AccessType}${Capitalize<CrudOperation>}`;
|
|
10
|
+
export type AccessTypeXCrudlOperation = `${AccessType}${Capitalize<CrudlOperation>}`;
|
|
11
|
+
|
|
12
|
+
declare module 'yup' {
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
14
|
+
export interface CustomSchemaMetadata {
|
|
15
|
+
openapiField?: {
|
|
16
|
+
description?: string,
|
|
17
|
+
exampleValue?: any,
|
|
18
|
+
hidden?: boolean,
|
|
19
|
+
onlyShowInOperations?: Capitalize<CrudlOperation>[],
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type ShownEndpointDocumentation = {
|
|
25
|
+
summary: string,
|
|
26
|
+
description: string,
|
|
27
|
+
tags?: string[],
|
|
28
|
+
crudOperation?: Capitalize<CrudlOperation>,
|
|
29
|
+
};
|
|
30
|
+
export type EndpointDocumentation =
|
|
31
|
+
| ({ hidden: true } & Partial<ShownEndpointDocumentation>)
|
|
32
|
+
| ({ hidden?: boolean } & ShownEndpointDocumentation);
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
type InnerCrudSchema<
|
|
36
|
+
CreateSchema extends yup.AnySchema | undefined = yup.AnySchema | undefined,
|
|
37
|
+
ReadSchema extends yup.AnySchema | undefined = yup.AnySchema | undefined,
|
|
38
|
+
UpdateSchema extends yup.AnySchema | undefined = yup.AnySchema | undefined,
|
|
39
|
+
DeleteSchema extends yup.AnySchema | undefined = yup.AnySchema | undefined,
|
|
40
|
+
> = {
|
|
41
|
+
createSchema: CreateSchema,
|
|
42
|
+
createDocs: EndpointDocumentation | undefined,
|
|
43
|
+
|
|
44
|
+
readSchema: ReadSchema,
|
|
45
|
+
readDocs: EndpointDocumentation | undefined,
|
|
46
|
+
listDocs: EndpointDocumentation | undefined,
|
|
47
|
+
|
|
48
|
+
updateSchema: UpdateSchema,
|
|
49
|
+
updateDocs: EndpointDocumentation | undefined,
|
|
50
|
+
|
|
51
|
+
deleteSchema: DeleteSchema,
|
|
52
|
+
deleteDocs: EndpointDocumentation | undefined,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type CrudSchema<
|
|
56
|
+
ClientSchema extends InnerCrudSchema = InnerCrudSchema,
|
|
57
|
+
ServerSchema extends InnerCrudSchema = InnerCrudSchema,
|
|
58
|
+
AdminSchema extends InnerCrudSchema = InnerCrudSchema,
|
|
59
|
+
> = {
|
|
60
|
+
client: ClientSchema,
|
|
61
|
+
server: ServerSchema,
|
|
62
|
+
admin: AdminSchema,
|
|
63
|
+
|
|
64
|
+
hasCreate: boolean,
|
|
65
|
+
hasRead: boolean,
|
|
66
|
+
hasUpdate: boolean,
|
|
67
|
+
hasDelete: boolean,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type CrudSchemaCreationOptions = {
|
|
71
|
+
[K in AccessTypeXCrudOperation as `${K}Schema`]?: yup.AnySchema
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
type FillInOptionalsPrepareStep<O extends CrudSchemaCreationOptions> =
|
|
75
|
+
& { [K in keyof Required<CrudSchemaCreationOptions>]: K extends keyof O ? O[K] : undefined };
|
|
76
|
+
|
|
77
|
+
type FillInOptionalsStep<O extends FillInOptionalsPrepareStep<CrudSchemaCreationOptions>> = {
|
|
78
|
+
clientCreateSchema: NullishCoalesce<O['clientCreateSchema'], undefined>,
|
|
79
|
+
clientReadSchema: NullishCoalesce<O['clientReadSchema'], undefined>,
|
|
80
|
+
clientUpdateSchema: NullishCoalesce<O['clientUpdateSchema'], undefined>,
|
|
81
|
+
clientDeleteSchema: NullishCoalesce<O['clientDeleteSchema'], undefined>,
|
|
82
|
+
|
|
83
|
+
serverCreateSchema: NullishCoalesce<O['serverCreateSchema'], O['clientCreateSchema']>,
|
|
84
|
+
serverReadSchema: NullishCoalesce<O['serverReadSchema'], O['clientReadSchema']>,
|
|
85
|
+
serverUpdateSchema: NullishCoalesce<O['serverUpdateSchema'], O['clientUpdateSchema']>,
|
|
86
|
+
serverDeleteSchema: NullishCoalesce<O['serverDeleteSchema'], O['clientDeleteSchema']>,
|
|
87
|
+
|
|
88
|
+
adminCreateSchema: NullishCoalesce<O['adminCreateSchema'], O['serverCreateSchema']>,
|
|
89
|
+
adminReadSchema: NullishCoalesce<O['adminReadSchema'], O['serverReadSchema']>,
|
|
90
|
+
adminUpdateSchema: NullishCoalesce<O['adminUpdateSchema'], O['serverUpdateSchema']>,
|
|
91
|
+
adminDeleteSchema: NullishCoalesce<O['adminDeleteSchema'], O['serverDeleteSchema']>,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
type FillInOptionals<O extends CrudSchemaCreationOptions> = FillInOptionalsStep<FillInOptionalsStep<FillInOptionalsStep<FillInOptionalsPrepareStep<O>>>>;
|
|
95
|
+
|
|
96
|
+
type CrudSchemaFromOptionsInner<O extends FillInOptionals<any>> = CrudSchema<
|
|
97
|
+
InnerCrudSchema<O['clientCreateSchema'], O['clientReadSchema'], O['clientUpdateSchema'], O['clientDeleteSchema']>,
|
|
98
|
+
InnerCrudSchema<O['serverCreateSchema'], O['serverReadSchema'], O['serverUpdateSchema'], O['serverDeleteSchema']>,
|
|
99
|
+
InnerCrudSchema<O['adminCreateSchema'], O['adminReadSchema'], O['adminUpdateSchema'], O['adminDeleteSchema']>
|
|
100
|
+
>;
|
|
101
|
+
|
|
102
|
+
export type CrudSchemaFromOptions<O extends CrudSchemaCreationOptions> = CrudSchemaFromOptionsInner<FillInOptionals<O>>;
|
|
103
|
+
|
|
104
|
+
type InnerCrudTypeOf<S extends InnerCrudSchema> =
|
|
105
|
+
& (S['createSchema'] extends {} ? { Create: yup.InferType<S['createSchema']> } : {})
|
|
106
|
+
& (S['readSchema'] extends {} ? { Read: yup.InferType<S['readSchema']> } : {})
|
|
107
|
+
& (S['updateSchema'] extends {} ? { Update: yup.InferType<S['updateSchema']> } : {})
|
|
108
|
+
& (S['deleteSchema'] extends {} ? { Delete: yup.InferType<S['deleteSchema']> } : {})
|
|
109
|
+
& (S['readSchema'] extends {} ? { List: {
|
|
110
|
+
items: yup.InferType<S['readSchema']>[],
|
|
111
|
+
is_paginated: boolean,
|
|
112
|
+
pagination?: {
|
|
113
|
+
next_cursor: string | null,
|
|
114
|
+
},
|
|
115
|
+
}, } : {});
|
|
116
|
+
|
|
117
|
+
export type CrudTypeOf<S extends CrudSchema> = {
|
|
118
|
+
Client: InnerCrudTypeOf<S['client']>,
|
|
119
|
+
Server: InnerCrudTypeOf<S['server']>,
|
|
120
|
+
Admin: InnerCrudTypeOf<S['admin']>,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
type CrudDocsCreationOptions<SO extends CrudSchemaCreationOptions> = {
|
|
124
|
+
[X in AccessTypeXCrudlOperation]?: EndpointDocumentation
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export function createCrud<SO extends CrudSchemaCreationOptions>(options: SO & { docs?: CrudDocsCreationOptions<SO> }): CrudSchemaFromOptions<SO> {
|
|
128
|
+
const docs = options.docs ?? {};
|
|
129
|
+
const client = {
|
|
130
|
+
createSchema: options.clientCreateSchema,
|
|
131
|
+
createDocs: docs.clientCreate,
|
|
132
|
+
|
|
133
|
+
readSchema: options.clientReadSchema,
|
|
134
|
+
readDocs: docs.clientRead,
|
|
135
|
+
listDocs: docs.clientList,
|
|
136
|
+
|
|
137
|
+
updateSchema: options.clientUpdateSchema,
|
|
138
|
+
updateDocs: docs.clientUpdate,
|
|
139
|
+
|
|
140
|
+
deleteSchema: options.clientDeleteSchema,
|
|
141
|
+
deleteDocs: docs.clientDelete,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const serverOverrides = filterUndefined({
|
|
145
|
+
createSchema: options.serverCreateSchema,
|
|
146
|
+
createDocs: docs.serverCreate,
|
|
147
|
+
|
|
148
|
+
readSchema: options.serverReadSchema,
|
|
149
|
+
readDocs: docs.serverRead,
|
|
150
|
+
listDocs: docs.serverList,
|
|
151
|
+
|
|
152
|
+
updateSchema: options.serverUpdateSchema,
|
|
153
|
+
updateDocs: docs.serverUpdate,
|
|
154
|
+
|
|
155
|
+
deleteSchema: options.serverDeleteSchema,
|
|
156
|
+
deleteDocs: docs.serverDelete,
|
|
157
|
+
});
|
|
158
|
+
const server = {
|
|
159
|
+
...client,
|
|
160
|
+
...serverOverrides,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const adminOverrides = filterUndefined({
|
|
164
|
+
createSchema: options.adminCreateSchema,
|
|
165
|
+
createDocs: docs.adminCreate,
|
|
166
|
+
|
|
167
|
+
readSchema: options.adminReadSchema,
|
|
168
|
+
readDocs: docs.adminRead,
|
|
169
|
+
listDocs: docs.adminList,
|
|
170
|
+
|
|
171
|
+
updateSchema: options.adminUpdateSchema,
|
|
172
|
+
updateDocs: docs.adminUpdate,
|
|
173
|
+
|
|
174
|
+
deleteSchema: options.adminDeleteSchema,
|
|
175
|
+
deleteDocs: docs.adminDelete,
|
|
176
|
+
});
|
|
177
|
+
const admin = {
|
|
178
|
+
...server,
|
|
179
|
+
...adminOverrides,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
client: client as any,
|
|
184
|
+
server: server as any,
|
|
185
|
+
admin: admin as any,
|
|
186
|
+
|
|
187
|
+
hasCreate: !!admin.createSchema,
|
|
188
|
+
hasRead: !!admin.readSchema,
|
|
189
|
+
hasUpdate: !!admin.updateSchema,
|
|
190
|
+
hasDelete: !!admin.deleteSchema,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
import.meta.vitest?.test("createCrud", ({ expect }) => {
|
|
195
|
+
// Test with empty options
|
|
196
|
+
const emptyCrud = createCrud({});
|
|
197
|
+
expect(emptyCrud.hasCreate).toBe(false);
|
|
198
|
+
expect(emptyCrud.hasRead).toBe(false);
|
|
199
|
+
expect(emptyCrud.hasUpdate).toBe(false);
|
|
200
|
+
expect(emptyCrud.hasDelete).toBe(false);
|
|
201
|
+
expect(emptyCrud.client.createSchema).toBeUndefined();
|
|
202
|
+
expect(emptyCrud.server.createSchema).toBeUndefined();
|
|
203
|
+
expect(emptyCrud.admin.createSchema).toBeUndefined();
|
|
204
|
+
|
|
205
|
+
// Test with client schemas only
|
|
206
|
+
const mockSchema = yupObject().shape({
|
|
207
|
+
name: yupString().defined(),
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const clientOnlyCrud = createCrud({
|
|
211
|
+
clientCreateSchema: mockSchema,
|
|
212
|
+
clientReadSchema: mockSchema,
|
|
213
|
+
});
|
|
214
|
+
expect(clientOnlyCrud.hasCreate).toBe(true);
|
|
215
|
+
expect(clientOnlyCrud.hasRead).toBe(true);
|
|
216
|
+
expect(clientOnlyCrud.hasUpdate).toBe(false);
|
|
217
|
+
expect(clientOnlyCrud.hasDelete).toBe(false);
|
|
218
|
+
expect(clientOnlyCrud.client.createSchema).toBe(mockSchema);
|
|
219
|
+
expect(clientOnlyCrud.server.createSchema).toBe(mockSchema);
|
|
220
|
+
expect(clientOnlyCrud.admin.createSchema).toBe(mockSchema);
|
|
221
|
+
|
|
222
|
+
// Test with server overrides
|
|
223
|
+
const serverSchema = yupObject().shape({
|
|
224
|
+
name: yupString().defined(),
|
|
225
|
+
internalField: yupString().defined(),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const serverOverrideCrud = createCrud({
|
|
229
|
+
clientCreateSchema: mockSchema,
|
|
230
|
+
serverCreateSchema: serverSchema,
|
|
231
|
+
});
|
|
232
|
+
expect(serverOverrideCrud.hasCreate).toBe(true);
|
|
233
|
+
expect(serverOverrideCrud.client.createSchema).toBe(mockSchema);
|
|
234
|
+
expect(serverOverrideCrud.server.createSchema).toBe(serverSchema);
|
|
235
|
+
expect(serverOverrideCrud.admin.createSchema).toBe(serverSchema);
|
|
236
|
+
|
|
237
|
+
// Test with admin overrides
|
|
238
|
+
const adminSchema = yupObject().shape({
|
|
239
|
+
name: yupString().defined(),
|
|
240
|
+
internalField: yupString().defined(),
|
|
241
|
+
adminField: yupString().defined(),
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const fullOverrideCrud = createCrud({
|
|
245
|
+
clientCreateSchema: mockSchema,
|
|
246
|
+
serverCreateSchema: serverSchema,
|
|
247
|
+
adminCreateSchema: adminSchema,
|
|
248
|
+
});
|
|
249
|
+
expect(fullOverrideCrud.hasCreate).toBe(true);
|
|
250
|
+
expect(fullOverrideCrud.client.createSchema).toBe(mockSchema);
|
|
251
|
+
expect(fullOverrideCrud.server.createSchema).toBe(serverSchema);
|
|
252
|
+
expect(fullOverrideCrud.admin.createSchema).toBe(adminSchema);
|
|
253
|
+
|
|
254
|
+
// Test with documentation
|
|
255
|
+
const crudWithDocs = createCrud({
|
|
256
|
+
clientCreateSchema: mockSchema,
|
|
257
|
+
docs: {
|
|
258
|
+
clientCreate: {
|
|
259
|
+
summary: "Create a resource",
|
|
260
|
+
description: "Creates a new resource",
|
|
261
|
+
tags: ["resources"],
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
expect(crudWithDocs.client.createDocs).toEqual({
|
|
266
|
+
summary: "Create a resource",
|
|
267
|
+
description: "Creates a new resource",
|
|
268
|
+
tags: ["resources"],
|
|
269
|
+
});
|
|
270
|
+
expect(crudWithDocs.server.createDocs).toEqual({
|
|
271
|
+
summary: "Create a resource",
|
|
272
|
+
description: "Creates a new resource",
|
|
273
|
+
tags: ["resources"],
|
|
274
|
+
});
|
|
275
|
+
});
|
package/src/global.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import type { } from "react/canary";
|