@lssm/lib.contracts 0.0.0-canary-20251217062943 → 0.0.0-canary-20251217072406
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/app-config/app-config.feature.js +53 -1
- package/dist/app-config/contracts.d.ts +50 -50
- package/dist/app-config/contracts.js +396 -1
- package/dist/app-config/docs/app-config.docblock.js +22 -220
- package/dist/app-config/events.js +168 -1
- package/dist/app-config/index.js +8 -1
- package/dist/app-config/lifecycle-contracts.js +441 -1
- package/dist/app-config/runtime.js +617 -1
- package/dist/app-config/spec.js +36 -1
- package/dist/app-config/validation.js +538 -1
- package/dist/capabilities/docs/capabilities.docblock.js +22 -1
- package/dist/capabilities/openbanking.js +92 -1
- package/dist/capabilities.js +50 -1
- package/dist/client/index.js +9 -1
- package/dist/client/react/drivers/rn-reusables.js +21 -1
- package/dist/client/react/drivers/shadcn.js +11 -1
- package/dist/client/react/feature-render.js +43 -1
- package/dist/client/react/form-render.js +298 -1
- package/dist/client/react/index.js +8 -1
- package/dist/contract-registry/index.js +3 -1
- package/dist/contract-registry/schemas.js +61 -1
- package/dist/contracts-adapter-hydration.js +41 -1
- package/dist/contracts-adapter-input.js +77 -1
- package/dist/data-views/docs/data-views.docblock.js +22 -1
- package/dist/data-views/query-generator.js +48 -1
- package/dist/data-views/runtime.js +39 -1
- package/dist/data-views.js +35 -1
- package/dist/docs/PUBLISHING.docblock.js +17 -76
- package/dist/docs/accessibility_wcag_compliance_specs.docblock.js +17 -350
- package/dist/docs/index.js +33 -1
- package/dist/docs/meta.docs.js +15 -2
- package/dist/docs/presentations.js +77 -1
- package/dist/docs/registry.js +51 -1
- package/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +17 -383
- package/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +17 -68
- package/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +17 -140
- package/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +17 -86
- package/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +17 -1
- package/dist/docs/tech/auth/better-auth-nextjs.docblock.js +25 -2
- package/dist/docs/tech/contracts/README.docblock.js +21 -1
- package/dist/docs/tech/contracts/create-subscription.docblock.js +21 -1
- package/dist/docs/tech/contracts/graphql-typed-outputs.docblock.js +21 -180
- package/dist/docs/tech/contracts/migrations.docblock.js +21 -1
- package/dist/docs/tech/contracts/openapi-export.docblock.js +22 -2
- package/dist/docs/tech/contracts/ops-to-presentation-linking.docblock.js +19 -60
- package/dist/docs/tech/contracts/overlays.docblock.js +21 -68
- package/dist/docs/tech/contracts/tests.docblock.js +21 -132
- package/dist/docs/tech/contracts/themes.docblock.js +21 -1
- package/dist/docs/tech/contracts/vertical-pocket-family-office.docblock.js +21 -106
- package/dist/docs/tech/lifecycle-stage-system.docblock.js +17 -213
- package/dist/docs/tech/llm/llm-integration.docblock.js +74 -5
- package/dist/docs/tech/mcp-endpoints.docblock.js +38 -1
- package/dist/docs/tech/presentation-runtime.docblock.js +17 -1
- package/dist/docs/tech/schema/README.docblock.js +21 -262
- package/dist/docs/tech/studio/learning-events.docblock.js +49 -1
- package/dist/docs/tech/studio/learning-journeys.docblock.js +25 -2
- package/dist/docs/tech/studio/platform-admin-panel.docblock.js +24 -2
- package/dist/docs/tech/studio/project-access-teams.docblock.js +26 -16
- package/dist/docs/tech/studio/project-routing.docblock.js +68 -1
- package/dist/docs/tech/studio/sandbox-unlogged.docblock.js +23 -2
- package/dist/docs/tech/studio/team-invitations.docblock.js +41 -36
- package/dist/docs/tech/studio/workspace-ops.docblock.js +48 -1
- package/dist/docs/tech/studio/workspaces.docblock.js +24 -2
- package/dist/docs/tech/telemetry-ingest.docblock.js +37 -3
- package/dist/docs/tech/templates/runtime.docblock.js +21 -1
- package/dist/docs/tech/vscode-extension.docblock.js +37 -3
- package/dist/docs/tech/workflows/overview.docblock.js +21 -1
- package/dist/docs/tech-contracts.docs.js +19 -2
- package/dist/events.js +12 -1
- package/dist/experiments/docs/experiments.docblock.js +22 -128
- package/dist/experiments/evaluator.js +101 -1
- package/dist/experiments/spec.js +33 -1
- package/dist/features.js +68 -1
- package/dist/forms/docs/forms.docblock.js +22 -1
- package/dist/forms.js +119 -1
- package/dist/index.js +107 -1
- package/dist/install.js +40 -1
- package/dist/integrations/contracts.d.ts +102 -102
- package/dist/integrations/contracts.js +388 -1
- package/dist/integrations/docs/integrations.docblock.js +95 -1
- package/dist/integrations/health.js +69 -1
- package/dist/integrations/index.js +23 -1
- package/dist/integrations/openbanking/contracts/accounts.d.ts +66 -66
- package/dist/integrations/openbanking/contracts/accounts.js +237 -1
- package/dist/integrations/openbanking/contracts/balances.d.ts +34 -34
- package/dist/integrations/openbanking/contracts/balances.js +167 -1
- package/dist/integrations/openbanking/contracts/index.js +12 -1
- package/dist/integrations/openbanking/contracts/transactions.d.ts +48 -48
- package/dist/integrations/openbanking/contracts/transactions.js +218 -1
- package/dist/integrations/openbanking/guards.js +32 -1
- package/dist/integrations/openbanking/models.d.ts +55 -55
- package/dist/integrations/openbanking/models.js +242 -1
- package/dist/integrations/openbanking/openbanking.feature.js +68 -1
- package/dist/integrations/openbanking/telemetry.js +39 -1
- package/dist/integrations/providers/elevenlabs.js +56 -1
- package/dist/integrations/providers/gcs-storage.js +79 -1
- package/dist/integrations/providers/gmail.js +91 -1
- package/dist/integrations/providers/google-calendar.js +70 -1
- package/dist/integrations/providers/impls/elevenlabs-voice.js +95 -1
- package/dist/integrations/providers/impls/gcs-storage.js +88 -1
- package/dist/integrations/providers/impls/gmail-inbound.js +200 -1
- package/dist/integrations/providers/impls/gmail-outbound.js +104 -5
- package/dist/integrations/providers/impls/google-calendar.js +154 -1
- package/dist/integrations/providers/impls/index.js +16 -1
- package/dist/integrations/providers/impls/mistral-embedding.js +41 -1
- package/dist/integrations/providers/impls/mistral-llm.js +247 -1
- package/dist/integrations/providers/impls/postmark-email.js +55 -1
- package/dist/integrations/providers/impls/powens-client.js +171 -1
- package/dist/integrations/providers/impls/powens-openbanking.js +218 -1
- package/dist/integrations/providers/impls/provider-factory.js +142 -1
- package/dist/integrations/providers/impls/qdrant-vector.js +69 -1
- package/dist/integrations/providers/impls/stripe-payments.js +202 -1
- package/dist/integrations/providers/impls/twilio-sms.js +58 -1
- package/dist/integrations/providers/index.js +13 -1
- package/dist/integrations/providers/mistral.js +72 -1
- package/dist/integrations/providers/postmark.js +72 -1
- package/dist/integrations/providers/powens.js +120 -1
- package/dist/integrations/providers/qdrant.js +77 -1
- package/dist/integrations/providers/registry.js +34 -1
- package/dist/integrations/providers/stripe.js +87 -1
- package/dist/integrations/providers/twilio-sms.js +65 -1
- package/dist/integrations/runtime.js +186 -1
- package/dist/integrations/secrets/aws-secret-manager.js +231 -1
- package/dist/integrations/secrets/env-secret-provider.js +81 -1
- package/dist/integrations/secrets/gcp-secret-manager.js +229 -1
- package/dist/integrations/secrets/index.js +8 -1
- package/dist/integrations/secrets/manager.js +103 -1
- package/dist/integrations/secrets/provider.js +58 -1
- package/dist/integrations/secrets/scaleway-secret-manager.js +247 -1
- package/dist/integrations/spec.js +39 -1
- package/dist/jobs/define-job.js +16 -1
- package/dist/jobs/gcp-cloud-tasks.js +53 -1
- package/dist/jobs/gcp-pubsub.js +39 -1
- package/dist/jobs/handlers/gmail-sync-handler.js +9 -1
- package/dist/jobs/handlers/index.js +12 -1
- package/dist/jobs/handlers/ping-handler.js +15 -1
- package/dist/jobs/handlers/storage-document-handler.js +14 -1
- package/dist/jobs/index.js +4 -1
- package/dist/jobs/memory-queue.js +71 -1
- package/dist/jobs/queue.js +33 -1
- package/dist/jobs/scaleway-sqs-queue.js +153 -1
- package/dist/jsonschema.d.ts +3 -3
- package/dist/jsonschema.js +32 -1
- package/dist/knowledge/contracts.d.ts +66 -66
- package/dist/knowledge/contracts.js +317 -1
- package/dist/knowledge/docs/knowledge.docblock.js +22 -138
- package/dist/knowledge/index.js +10 -1
- package/dist/knowledge/ingestion/document-processor.js +54 -1
- package/dist/knowledge/ingestion/embedding-service.js +25 -1
- package/dist/knowledge/ingestion/gmail-adapter.js +50 -5
- package/dist/knowledge/ingestion/index.js +7 -1
- package/dist/knowledge/ingestion/storage-adapter.js +26 -1
- package/dist/knowledge/ingestion/vector-indexer.js +32 -1
- package/dist/knowledge/query/index.js +3 -1
- package/dist/knowledge/query/service.js +64 -2
- package/dist/knowledge/runtime.js +49 -1
- package/dist/knowledge/spaces/email-threads.js +38 -1
- package/dist/knowledge/spaces/financial-docs.js +38 -1
- package/dist/knowledge/spaces/financial-overview.js +42 -1
- package/dist/knowledge/spaces/index.js +8 -1
- package/dist/knowledge/spaces/product-canon.js +38 -1
- package/dist/knowledge/spaces/support-faq.js +41 -1
- package/dist/knowledge/spaces/uploaded-docs.js +38 -1
- package/dist/knowledge/spec.js +39 -1
- package/dist/llm/exporters.js +541 -8
- package/dist/llm/index.js +4 -1
- package/dist/llm/prompts.js +246 -56
- package/dist/markdown.js +116 -3
- package/dist/migrations.js +33 -1
- package/dist/onboarding-base.d.ts +29 -29
- package/dist/onboarding-base.js +196 -1
- package/dist/openapi.js +75 -1
- package/dist/openbanking/docs/openbanking.docblock.js +22 -109
- package/dist/ownership.js +40 -1
- package/dist/policy/docs/policy.docblock.js +22 -1
- package/dist/policy/engine.js +223 -1
- package/dist/policy/opa-adapter.js +71 -1
- package/dist/policy/spec.js +33 -1
- package/dist/presentations/docs/presentations-conventions.docblock.js +21 -7
- package/dist/presentations.backcompat.js +47 -1
- package/dist/presentations.d.ts +3 -3
- package/dist/presentations.js +66 -1
- package/dist/presentations.v2.js +278 -6
- package/dist/prompt.js +10 -1
- package/dist/promptRegistry.js +34 -1
- package/dist/regenerator/docs/regenerator.docblock.js +22 -184
- package/dist/regenerator/executor.js +86 -1
- package/dist/regenerator/index.js +6 -1
- package/dist/regenerator/service.js +92 -1
- package/dist/regenerator/sinks.js +32 -1
- package/dist/regenerator/utils.js +51 -1
- package/dist/registry.js +208 -1
- package/dist/resources.js +47 -1
- package/dist/schema/dist/EnumType.js +2 -1
- package/dist/schema/dist/FieldType.js +49 -1
- package/dist/schema/dist/ScalarTypeEnum.js +236 -1
- package/dist/schema/dist/SchemaModel.js +39 -1
- package/dist/schema/dist/entity/defineEntity.js +1 -1
- package/dist/schema/dist/entity/index.js +2 -1
- package/dist/schema/dist/entity/types.js +1 -1
- package/dist/schema/dist/index.js +6 -1
- package/dist/schema-to-markdown.js +214 -10
- package/dist/server/graphql-pothos.js +128 -1
- package/dist/server/index.js +10 -1
- package/dist/server/mcp/createMcpServer.js +28 -1
- package/dist/server/mcp/registerPresentations.js +151 -1
- package/dist/server/mcp/registerPrompts.js +36 -2
- package/dist/server/mcp/registerResources.js +35 -1
- package/dist/server/mcp/registerTools.js +22 -1
- package/dist/server/provider-mcp.js +3 -1
- package/dist/server/rest-elysia.js +20 -1
- package/dist/server/rest-express.js +39 -1
- package/dist/server/rest-generic.js +125 -1
- package/dist/server/rest-next-app.js +38 -1
- package/dist/server/rest-next-mcp.js +45 -1
- package/dist/server/rest-next-pages.js +25 -1
- package/dist/spec.js +35 -1
- package/dist/telemetry/anomaly.js +48 -1
- package/dist/telemetry/docs/telemetry.docblock.js +22 -139
- package/dist/telemetry/index.js +5 -1
- package/dist/telemetry/spec.js +69 -1
- package/dist/telemetry/tracker.js +76 -1
- package/dist/tests/index.js +4 -1
- package/dist/tests/runner.js +150 -1
- package/dist/tests/spec.js +33 -1
- package/dist/themes.js +39 -1
- package/dist/workflow/adapters/db-adapter.js +83 -1
- package/dist/workflow/adapters/file-adapter.js +11 -1
- package/dist/workflow/adapters/index.js +5 -1
- package/dist/workflow/adapters/memory-store.js +58 -1
- package/dist/workflow/expression.js +98 -1
- package/dist/workflow/index.js +9 -1
- package/dist/workflow/runner.js +337 -1
- package/dist/workflow/sla-monitor.js +47 -1
- package/dist/workflow/spec.js +32 -1
- package/dist/workflow/validation.js +175 -1
- package/package.json +11 -4
|
@@ -1 +1,92 @@
|
|
|
1
|
-
import{StabilityEnum
|
|
1
|
+
import { StabilityEnum } from "../ownership.js";
|
|
2
|
+
|
|
3
|
+
//#region src/capabilities/openbanking.ts
|
|
4
|
+
const OWNERS = ["platform.finance"];
|
|
5
|
+
const TAGS = ["open-banking", "finance"];
|
|
6
|
+
const openBankingAccountsReadCapability = {
|
|
7
|
+
meta: {
|
|
8
|
+
key: "openbanking.accounts.read",
|
|
9
|
+
version: 1,
|
|
10
|
+
kind: "integration",
|
|
11
|
+
title: "Open Banking Accounts (Read)",
|
|
12
|
+
description: "Provides read-only access to linked bank accounts, including account summaries and metadata.",
|
|
13
|
+
domain: "finance",
|
|
14
|
+
owners: [...OWNERS],
|
|
15
|
+
tags: [...TAGS],
|
|
16
|
+
stability: StabilityEnum.Experimental
|
|
17
|
+
},
|
|
18
|
+
provides: [
|
|
19
|
+
{
|
|
20
|
+
surface: "operation",
|
|
21
|
+
name: "openbanking.accounts.list",
|
|
22
|
+
version: 1,
|
|
23
|
+
description: "List bank accounts linked to a Powens open banking connection."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
surface: "operation",
|
|
27
|
+
name: "openbanking.accounts.get",
|
|
28
|
+
version: 1,
|
|
29
|
+
description: "Retrieve the canonical bank account record for a specific account."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
surface: "operation",
|
|
33
|
+
name: "openbanking.accounts.sync",
|
|
34
|
+
version: 1,
|
|
35
|
+
description: "Trigger a refresh of bank account metadata from the open banking provider."
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
};
|
|
39
|
+
const openBankingTransactionsReadCapability = {
|
|
40
|
+
meta: {
|
|
41
|
+
key: "openbanking.transactions.read",
|
|
42
|
+
version: 1,
|
|
43
|
+
kind: "integration",
|
|
44
|
+
title: "Open Banking Transactions (Read)",
|
|
45
|
+
description: "Enables retrieval of transaction history for linked bank accounts via open banking providers.",
|
|
46
|
+
domain: "finance",
|
|
47
|
+
owners: [...OWNERS],
|
|
48
|
+
tags: [...TAGS, "transactions"],
|
|
49
|
+
stability: StabilityEnum.Experimental
|
|
50
|
+
},
|
|
51
|
+
provides: [{
|
|
52
|
+
surface: "operation",
|
|
53
|
+
name: "openbanking.transactions.list",
|
|
54
|
+
version: 1,
|
|
55
|
+
description: "List transactions for a given bank account with optional date filtering."
|
|
56
|
+
}, {
|
|
57
|
+
surface: "operation",
|
|
58
|
+
name: "openbanking.transactions.sync",
|
|
59
|
+
version: 1,
|
|
60
|
+
description: "Synchronise transactions from the open banking provider into the canonical ledger."
|
|
61
|
+
}]
|
|
62
|
+
};
|
|
63
|
+
const openBankingBalancesReadCapability = {
|
|
64
|
+
meta: {
|
|
65
|
+
key: "openbanking.balances.read",
|
|
66
|
+
version: 1,
|
|
67
|
+
kind: "integration",
|
|
68
|
+
title: "Open Banking Balances (Read)",
|
|
69
|
+
description: "Allows querying of current and available balances for linked bank accounts via open banking providers.",
|
|
70
|
+
domain: "finance",
|
|
71
|
+
owners: [...OWNERS],
|
|
72
|
+
tags: [...TAGS, "balances"],
|
|
73
|
+
stability: StabilityEnum.Experimental
|
|
74
|
+
},
|
|
75
|
+
provides: [{
|
|
76
|
+
surface: "operation",
|
|
77
|
+
name: "openbanking.balances.get",
|
|
78
|
+
version: 1,
|
|
79
|
+
description: "Retrieve the latest known balances for a specified bank account."
|
|
80
|
+
}, {
|
|
81
|
+
surface: "operation",
|
|
82
|
+
name: "openbanking.balances.refresh",
|
|
83
|
+
version: 1,
|
|
84
|
+
description: "Force a balance refresh from the open banking provider."
|
|
85
|
+
}]
|
|
86
|
+
};
|
|
87
|
+
function registerOpenBankingCapabilities(registry) {
|
|
88
|
+
return registry.register(openBankingAccountsReadCapability).register(openBankingTransactionsReadCapability).register(openBankingBalancesReadCapability);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
//#endregion
|
|
92
|
+
export { openBankingAccountsReadCapability, openBankingBalancesReadCapability, openBankingTransactionsReadCapability, registerOpenBankingCapabilities };
|
package/dist/capabilities.js
CHANGED
|
@@ -1 +1,50 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/capabilities.ts
|
|
2
|
+
const capKey = (key, version) => `${key}.v${version}`;
|
|
3
|
+
var CapabilityRegistry = class {
|
|
4
|
+
items = /* @__PURE__ */ new Map();
|
|
5
|
+
register(spec) {
|
|
6
|
+
const key = capKey(spec.meta.key, spec.meta.version);
|
|
7
|
+
if (this.items.has(key)) throw new Error(`Duplicate capability ${key}`);
|
|
8
|
+
this.items.set(key, spec);
|
|
9
|
+
return this;
|
|
10
|
+
}
|
|
11
|
+
list() {
|
|
12
|
+
return [...this.items.values()];
|
|
13
|
+
}
|
|
14
|
+
get(key, version) {
|
|
15
|
+
if (version != null) return this.items.get(capKey(key, version));
|
|
16
|
+
let candidate;
|
|
17
|
+
let max = -Infinity;
|
|
18
|
+
for (const spec of this.items.values()) {
|
|
19
|
+
if (spec.meta.key !== key) continue;
|
|
20
|
+
if (spec.meta.version > max) {
|
|
21
|
+
max = spec.meta.version;
|
|
22
|
+
candidate = spec;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return candidate;
|
|
26
|
+
}
|
|
27
|
+
satisfies(requirement, additional) {
|
|
28
|
+
if (requirement.optional) return true;
|
|
29
|
+
if (additional?.some((ref) => matchesRequirement(ref, requirement))) return true;
|
|
30
|
+
const spec = requirement.version ? this.get(requirement.key, requirement.version) : this.get(requirement.key);
|
|
31
|
+
if (!spec) return false;
|
|
32
|
+
if (requirement.kind && spec.meta.kind !== requirement.kind) return false;
|
|
33
|
+
if (requirement.version != null && spec.meta.version !== requirement.version) return false;
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
function matchesRequirement(ref, requirement) {
|
|
38
|
+
if (ref.key !== requirement.key) return false;
|
|
39
|
+
if (requirement.version != null && ref.version !== requirement.version) return false;
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
function capabilityKey(spec) {
|
|
43
|
+
return capKey(spec.meta.key, spec.meta.version);
|
|
44
|
+
}
|
|
45
|
+
function defineCapability(spec) {
|
|
46
|
+
return spec;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { CapabilityRegistry, capabilityKey, defineCapability };
|
package/dist/client/index.js
CHANGED
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createEngineWithDefaults, createFeatureModule, registerFeature, renderFeaturePresentation } from "./react/feature-render.js";
|
|
4
|
+
import { createFormRenderer } from "./react/form-render.js";
|
|
5
|
+
import { shadcnDriver } from "./react/drivers/shadcn.js";
|
|
6
|
+
import { rnReusablesDriver } from "./react/drivers/rn-reusables.js";
|
|
7
|
+
import "./react/index.js";
|
|
8
|
+
|
|
9
|
+
export { createEngineWithDefaults, createFeatureModule, createFormRenderer, registerFeature, renderFeaturePresentation, rnReusablesDriver, shadcnDriver };
|
|
@@ -1 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/client/react/drivers/rn-reusables.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a React Native UI-kit driver by mapping required slots to components.
|
|
4
|
+
* Host apps should import their UI-kit primitives and pass them here.
|
|
5
|
+
*
|
|
6
|
+
* Example usage:
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { rnReusablesDriver } from '@lssm/lib.contracts/client/react/drivers/rn-reusables';
|
|
9
|
+
* import { Input, Textarea, Button } from '@lssm/lib.ui-kit/ui';
|
|
10
|
+
*
|
|
11
|
+
* const driver = rnReusablesDriver({
|
|
12
|
+
* Input, Textarea, Button, // ... other components
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
function rnReusablesDriver(slots) {
|
|
17
|
+
return slots;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { rnReusablesDriver };
|
|
@@ -1 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/client/react/drivers/shadcn.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a shadcn/ui driver by mapping required slots to components.
|
|
4
|
+
* Host apps should import their shadcn primitives and pass them here.
|
|
5
|
+
*/
|
|
6
|
+
function shadcnDriver(slots) {
|
|
7
|
+
return slots;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { shadcnDriver };
|
|
@@ -1 +1,43 @@
|
|
|
1
|
-
import{createDefaultTransformEngine
|
|
1
|
+
import { createDefaultTransformEngine, registerBasicValidation, registerDefaultReactRenderer } from "../../presentations.v2.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/client/react/feature-render.ts
|
|
5
|
+
function createEngineWithDefaults() {
|
|
6
|
+
return registerBasicValidation(registerDefaultReactRenderer(createDefaultTransformEngine()));
|
|
7
|
+
}
|
|
8
|
+
async function renderFeaturePresentation(engine, target, desc, options) {
|
|
9
|
+
if (target === "react") {
|
|
10
|
+
const rd = await engine.render("react", desc);
|
|
11
|
+
if (rd.kind === "react_component") {
|
|
12
|
+
const C = (options?.componentMap ?? {})[rd.componentKey];
|
|
13
|
+
if (!C) return null;
|
|
14
|
+
const merged = {
|
|
15
|
+
...rd.props ?? {},
|
|
16
|
+
...options?.reactProps ?? {}
|
|
17
|
+
};
|
|
18
|
+
return React.createElement(C, merged);
|
|
19
|
+
}
|
|
20
|
+
if (rd.kind === "blocknotejs") {
|
|
21
|
+
if (options?.renderBlockNote) return options.renderBlockNote(rd.docJson, rd.blockConfig);
|
|
22
|
+
return React.createElement("div", {}, "[BlockNote renderer not configured]");
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (target === "markdown") return engine.render(target, desc);
|
|
27
|
+
if (target === "application/json") return engine.render(target, desc);
|
|
28
|
+
if (target === "application/xml") return engine.render(target, desc);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function createFeatureModule(meta, refs) {
|
|
32
|
+
return {
|
|
33
|
+
meta,
|
|
34
|
+
...refs
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function registerFeature(registry, feature) {
|
|
38
|
+
registry.register(feature);
|
|
39
|
+
return registry;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createEngineWithDefaults, createFeatureModule, registerFeature, renderFeaturePresentation };
|
|
@@ -1 +1,298 @@
|
|
|
1
|
-
import{buildZodWithRelations
|
|
1
|
+
import { buildZodWithRelations, evalPredicate } from "../../forms.js";
|
|
2
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
|
4
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/client/react/form-render.tsx
|
|
8
|
+
function toOptionsArray(src) {
|
|
9
|
+
if (!src) return void 0;
|
|
10
|
+
if (Array.isArray(src)) return {
|
|
11
|
+
kind: "static",
|
|
12
|
+
options: src
|
|
13
|
+
};
|
|
14
|
+
return src;
|
|
15
|
+
}
|
|
16
|
+
function getAtPath(values, path) {
|
|
17
|
+
if (!path) return void 0;
|
|
18
|
+
const segs = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
19
|
+
let cur = values;
|
|
20
|
+
for (const s of segs) {
|
|
21
|
+
if (cur == null) return void 0;
|
|
22
|
+
cur = cur[s];
|
|
23
|
+
}
|
|
24
|
+
return cur;
|
|
25
|
+
}
|
|
26
|
+
function makeDepsKey(values, deps) {
|
|
27
|
+
if (!deps || deps.length === 0) return "[]";
|
|
28
|
+
try {
|
|
29
|
+
return JSON.stringify(deps.map((d) => getAtPath(values, d)));
|
|
30
|
+
} catch {
|
|
31
|
+
return "[]";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function useResolvedOptions(values, source, resolvers) {
|
|
35
|
+
const [opts, setOpts] = useState([]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
let mounted = true;
|
|
38
|
+
const run = async () => {
|
|
39
|
+
if (!source) return setOpts([]);
|
|
40
|
+
if (source.kind === "static") return setOpts([...source.options ?? []]);
|
|
41
|
+
const fn = resolvers?.[source.resolverKey];
|
|
42
|
+
if (!fn) return setOpts([]);
|
|
43
|
+
const res = await fn(values, source.args);
|
|
44
|
+
if (mounted) setOpts([...res ?? []]);
|
|
45
|
+
};
|
|
46
|
+
run();
|
|
47
|
+
return () => {
|
|
48
|
+
mounted = false;
|
|
49
|
+
};
|
|
50
|
+
}, [useMemo(() => {
|
|
51
|
+
if (!source) return "nil";
|
|
52
|
+
if (source.kind === "static") return JSON.stringify(source.options ?? []);
|
|
53
|
+
return makeDepsKey(values, source.deps);
|
|
54
|
+
}, [source, values]), source && source.resolverKey]);
|
|
55
|
+
return opts;
|
|
56
|
+
}
|
|
57
|
+
function fieldPath(parent, name, arrayIndex) {
|
|
58
|
+
if (!name) return parent ?? "";
|
|
59
|
+
const child = typeof arrayIndex === "number" ? `${name.replace(/^\$index$/, String(arrayIndex))}` : name;
|
|
60
|
+
return parent ? `${parent}${typeof arrayIndex === "number" ? `.${arrayIndex}` : ""}.${child}`.replace(/\.+/g, ".") : child;
|
|
61
|
+
}
|
|
62
|
+
function createFormRenderer(base) {
|
|
63
|
+
const conf = base;
|
|
64
|
+
const { driver } = conf;
|
|
65
|
+
function InternalForm(props) {
|
|
66
|
+
const { spec, options, merged } = props;
|
|
67
|
+
const baseZod = useMemo(() => buildZodWithRelations(spec), [spec]);
|
|
68
|
+
const form = useForm({
|
|
69
|
+
...merged.formOptions,
|
|
70
|
+
resolver: zodResolver(baseZod),
|
|
71
|
+
defaultValues: options?.defaultValues
|
|
72
|
+
});
|
|
73
|
+
const values = form.watch();
|
|
74
|
+
const renderOne = (f, parent, arrayIndex) => {
|
|
75
|
+
const DriverField = driver.Field;
|
|
76
|
+
const DriverLabel = driver.FieldLabel;
|
|
77
|
+
const DriverDesc = driver.FieldDescription;
|
|
78
|
+
const DriverError = driver.FieldError;
|
|
79
|
+
const name = fieldPath(parent, f.name, arrayIndex);
|
|
80
|
+
const visible = evalPredicate(values, f.visibleWhen);
|
|
81
|
+
const enabled = evalPredicate(values, f.enabledWhen);
|
|
82
|
+
const invalid = Boolean(form.getFieldState(name)?.invalid);
|
|
83
|
+
if (!visible) return null;
|
|
84
|
+
const id = name?.replace(/\./g, "-");
|
|
85
|
+
const commonWrapProps = {
|
|
86
|
+
"data-invalid": invalid,
|
|
87
|
+
hidden: !visible,
|
|
88
|
+
disabled: !enabled
|
|
89
|
+
};
|
|
90
|
+
const labelNode = f.labelI18n ? /* @__PURE__ */ jsx(DriverLabel, {
|
|
91
|
+
htmlFor: id,
|
|
92
|
+
children: f.labelI18n
|
|
93
|
+
}) : null;
|
|
94
|
+
const descNode = f.descriptionI18n ? /* @__PURE__ */ jsx(DriverDesc, { children: f.descriptionI18n }) : null;
|
|
95
|
+
if (f.kind === "group") {
|
|
96
|
+
const children = f.fields.map((c, i) => /* @__PURE__ */ jsx(React.Fragment, { children: renderOne(c, name, arrayIndex) }, `${name}-${i}`));
|
|
97
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
98
|
+
...commonWrapProps,
|
|
99
|
+
children: [
|
|
100
|
+
labelNode,
|
|
101
|
+
children,
|
|
102
|
+
descNode
|
|
103
|
+
]
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (f.kind === "array") return renderArray(f, parent);
|
|
107
|
+
return /* @__PURE__ */ jsx(Controller, {
|
|
108
|
+
name,
|
|
109
|
+
control: form.control,
|
|
110
|
+
render: ({ field, fieldState }) => {
|
|
111
|
+
const err = fieldState.error ? [fieldState.error] : [];
|
|
112
|
+
const ariaInvalid = fieldState.invalid || void 0;
|
|
113
|
+
if (f.kind === "text") {
|
|
114
|
+
const Input = driver.Input;
|
|
115
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
116
|
+
...commonWrapProps,
|
|
117
|
+
children: [
|
|
118
|
+
labelNode,
|
|
119
|
+
/* @__PURE__ */ jsx(Input, {
|
|
120
|
+
id,
|
|
121
|
+
"aria-invalid": ariaInvalid,
|
|
122
|
+
placeholder: f.placeholderI18n,
|
|
123
|
+
autoComplete: f.autoComplete,
|
|
124
|
+
inputMode: f.inputMode,
|
|
125
|
+
maxLength: f.maxLength,
|
|
126
|
+
minLength: f.minLength,
|
|
127
|
+
disabled: !enabled,
|
|
128
|
+
...field,
|
|
129
|
+
...f.uiProps,
|
|
130
|
+
keyboard: f.keyboard,
|
|
131
|
+
autoComplete: f.keyboard?.autoComplete ?? f.autoComplete
|
|
132
|
+
}),
|
|
133
|
+
descNode,
|
|
134
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (f.kind === "textarea") {
|
|
139
|
+
const Textarea = driver.Textarea;
|
|
140
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
141
|
+
...commonWrapProps,
|
|
142
|
+
children: [
|
|
143
|
+
labelNode,
|
|
144
|
+
/* @__PURE__ */ jsx(Textarea, {
|
|
145
|
+
id,
|
|
146
|
+
"aria-invalid": ariaInvalid,
|
|
147
|
+
placeholder: f.placeholderI18n,
|
|
148
|
+
rows: f.rows,
|
|
149
|
+
maxLength: f.maxLength,
|
|
150
|
+
disabled: !enabled,
|
|
151
|
+
...field,
|
|
152
|
+
...f.uiProps,
|
|
153
|
+
keyboard: f.keyboard,
|
|
154
|
+
autoComplete: f.keyboard?.autoComplete ?? f.autoComplete
|
|
155
|
+
}),
|
|
156
|
+
descNode,
|
|
157
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
158
|
+
]
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (f.kind === "select") {
|
|
162
|
+
const Select = driver.Select;
|
|
163
|
+
const opts = useResolvedOptions(values, toOptionsArray(f.options), merged.resolvers);
|
|
164
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
165
|
+
...commonWrapProps,
|
|
166
|
+
children: [
|
|
167
|
+
labelNode,
|
|
168
|
+
/* @__PURE__ */ jsx(Select, {
|
|
169
|
+
id,
|
|
170
|
+
name,
|
|
171
|
+
"aria-invalid": ariaInvalid,
|
|
172
|
+
disabled: !enabled,
|
|
173
|
+
value: field.value,
|
|
174
|
+
onChange: (v) => field.onChange(v),
|
|
175
|
+
options: opts,
|
|
176
|
+
...f.uiProps
|
|
177
|
+
}),
|
|
178
|
+
descNode,
|
|
179
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
180
|
+
]
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
if (f.kind === "checkbox") {
|
|
184
|
+
const Checkbox = driver.Checkbox;
|
|
185
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
186
|
+
...commonWrapProps,
|
|
187
|
+
children: [
|
|
188
|
+
labelNode,
|
|
189
|
+
/* @__PURE__ */ jsx(Checkbox, {
|
|
190
|
+
id,
|
|
191
|
+
name,
|
|
192
|
+
disabled: !enabled,
|
|
193
|
+
checked: !!field.value,
|
|
194
|
+
onCheckedChange: (v) => field.onChange(v),
|
|
195
|
+
...f.uiProps
|
|
196
|
+
}),
|
|
197
|
+
descNode,
|
|
198
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
199
|
+
]
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (f.kind === "radio") {
|
|
203
|
+
const RadioGroup = driver.RadioGroup;
|
|
204
|
+
const opts = useResolvedOptions(values, toOptionsArray(f.options), merged.resolvers);
|
|
205
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
206
|
+
...commonWrapProps,
|
|
207
|
+
children: [
|
|
208
|
+
labelNode,
|
|
209
|
+
/* @__PURE__ */ jsx(RadioGroup, {
|
|
210
|
+
id,
|
|
211
|
+
name,
|
|
212
|
+
disabled: !enabled,
|
|
213
|
+
value: field.value,
|
|
214
|
+
onValueChange: (v) => field.onChange(v),
|
|
215
|
+
options: opts,
|
|
216
|
+
...f.uiProps
|
|
217
|
+
}),
|
|
218
|
+
descNode,
|
|
219
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
220
|
+
]
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (f.kind === "switch") {
|
|
224
|
+
const Switch = driver.Switch;
|
|
225
|
+
return /* @__PURE__ */ jsxs(DriverField, {
|
|
226
|
+
...commonWrapProps,
|
|
227
|
+
children: [
|
|
228
|
+
labelNode,
|
|
229
|
+
/* @__PURE__ */ jsx(Switch, {
|
|
230
|
+
id,
|
|
231
|
+
name,
|
|
232
|
+
disabled: !enabled,
|
|
233
|
+
checked: !!field.value,
|
|
234
|
+
onCheckedChange: (v) => field.onChange(v),
|
|
235
|
+
...f.uiProps
|
|
236
|
+
}),
|
|
237
|
+
descNode,
|
|
238
|
+
fieldState.invalid ? /* @__PURE__ */ jsx(DriverError, { errors: err }) : null
|
|
239
|
+
]
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
243
|
+
}
|
|
244
|
+
}, name);
|
|
245
|
+
};
|
|
246
|
+
const renderArray = (f, parent) => {
|
|
247
|
+
const name = fieldPath(parent, f.name);
|
|
248
|
+
const { fields, append, remove } = useFieldArray({
|
|
249
|
+
control: form.control,
|
|
250
|
+
name
|
|
251
|
+
});
|
|
252
|
+
const canAdd = f.max == null || fields.length < f.max;
|
|
253
|
+
const canRemove = (idx) => (f.min == null ? fields.length > 0 : fields.length > f.min) && idx >= 0;
|
|
254
|
+
const Button$1 = driver.Button;
|
|
255
|
+
const Label = driver.FieldLabel;
|
|
256
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
257
|
+
f.labelI18n ? /* @__PURE__ */ jsx(Label, { children: f.labelI18n }) : null,
|
|
258
|
+
fields.map((row, idx) => /* @__PURE__ */ jsxs("div", { children: [renderOne(f.of, name, idx), canRemove(idx) ? /* @__PURE__ */ jsx(Button$1, {
|
|
259
|
+
type: "button",
|
|
260
|
+
variant: "ghost",
|
|
261
|
+
size: "sm",
|
|
262
|
+
onClick: () => remove(idx),
|
|
263
|
+
children: "Remove"
|
|
264
|
+
}) : null] }, row.id ?? idx)),
|
|
265
|
+
canAdd ? /* @__PURE__ */ jsx(Button$1, {
|
|
266
|
+
type: "button",
|
|
267
|
+
variant: "outline",
|
|
268
|
+
size: "sm",
|
|
269
|
+
onClick: () => append({}),
|
|
270
|
+
children: "Add"
|
|
271
|
+
}) : null
|
|
272
|
+
] }, name);
|
|
273
|
+
};
|
|
274
|
+
const onSubmit = async (data) => {
|
|
275
|
+
const actionKey = spec.actions?.[0]?.key ?? "submit";
|
|
276
|
+
if (merged.onSubmitOverride) return merged.onSubmitOverride(data, actionKey);
|
|
277
|
+
};
|
|
278
|
+
const Button = driver.Button;
|
|
279
|
+
return /* @__PURE__ */ jsxs("form", {
|
|
280
|
+
onSubmit: form.handleSubmit(onSubmit),
|
|
281
|
+
children: [(spec.fields || []).map((f, i) => /* @__PURE__ */ jsx(React.Fragment, { children: renderOne(f) }, i)), spec.actions && spec.actions.length ? /* @__PURE__ */ jsx("div", { children: spec.actions.map((a) => /* @__PURE__ */ jsx(Button, {
|
|
282
|
+
type: "submit",
|
|
283
|
+
children: a.labelI18n
|
|
284
|
+
}, a.key)) }) : null]
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
return { render: (spec, options) => /* @__PURE__ */ jsx(InternalForm, {
|
|
288
|
+
spec,
|
|
289
|
+
options,
|
|
290
|
+
merged: {
|
|
291
|
+
...conf,
|
|
292
|
+
...options?.overrides ?? {}
|
|
293
|
+
}
|
|
294
|
+
}) };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
//#endregion
|
|
298
|
+
export { createFormRenderer };
|
|
@@ -1 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { createEngineWithDefaults, createFeatureModule, registerFeature, renderFeaturePresentation } from "./feature-render.js";
|
|
4
|
+
import { createFormRenderer } from "./form-render.js";
|
|
5
|
+
import { shadcnDriver } from "./drivers/shadcn.js";
|
|
6
|
+
import { rnReusablesDriver } from "./drivers/rn-reusables.js";
|
|
7
|
+
|
|
8
|
+
export { createEngineWithDefaults, createFeatureModule, createFormRenderer, registerFeature, renderFeaturePresentation, rnReusablesDriver, shadcnDriver };
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
import{ContractRegistryFileSchema
|
|
1
|
+
import { ContractRegistryFileSchema, ContractRegistryItemSchema, ContractRegistryItemTypeSchema, ContractRegistryManifestSchema } from "./schemas.js";
|
|
2
|
+
|
|
3
|
+
export { ContractRegistryFileSchema, ContractRegistryItemSchema, ContractRegistryItemTypeSchema, ContractRegistryManifestSchema };
|
|
@@ -1 +1,61 @@
|
|
|
1
|
-
import{StabilityEnum
|
|
1
|
+
import { StabilityEnum } from "../ownership.js";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/contract-registry/schemas.ts
|
|
5
|
+
const ContractRegistryItemTypeValues = [
|
|
6
|
+
"contractspec:operation",
|
|
7
|
+
"contractspec:event",
|
|
8
|
+
"contractspec:presentation",
|
|
9
|
+
"contractspec:form",
|
|
10
|
+
"contractspec:feature",
|
|
11
|
+
"contractspec:workflow",
|
|
12
|
+
"contractspec:template",
|
|
13
|
+
"contractspec:integration",
|
|
14
|
+
"contractspec:data-view",
|
|
15
|
+
"contractspec:migration",
|
|
16
|
+
"contractspec:telemetry",
|
|
17
|
+
"contractspec:experiment",
|
|
18
|
+
"contractspec:app-config",
|
|
19
|
+
"contractspec:knowledge"
|
|
20
|
+
];
|
|
21
|
+
const ContractRegistryItemTypeSchema = z.enum(ContractRegistryItemTypeValues);
|
|
22
|
+
const ContractRegistryFileSchema = z.object({
|
|
23
|
+
path: z.string().min(1),
|
|
24
|
+
type: z.string().min(1),
|
|
25
|
+
content: z.string().optional()
|
|
26
|
+
});
|
|
27
|
+
const ContractRegistryItemSchema = z.object({
|
|
28
|
+
name: z.string().min(1),
|
|
29
|
+
type: ContractRegistryItemTypeSchema,
|
|
30
|
+
version: z.number().int().nonnegative(),
|
|
31
|
+
title: z.string().min(1),
|
|
32
|
+
description: z.string().min(1),
|
|
33
|
+
meta: z.object({
|
|
34
|
+
stability: z.enum([
|
|
35
|
+
StabilityEnum.Idea,
|
|
36
|
+
StabilityEnum.InCreation,
|
|
37
|
+
StabilityEnum.Experimental,
|
|
38
|
+
StabilityEnum.Beta,
|
|
39
|
+
StabilityEnum.Stable,
|
|
40
|
+
StabilityEnum.Deprecated
|
|
41
|
+
]),
|
|
42
|
+
owners: z.array(z.string().min(1)).default([]),
|
|
43
|
+
tags: z.array(z.string().min(1)).default([])
|
|
44
|
+
}),
|
|
45
|
+
dependencies: z.array(z.string().min(1)).optional(),
|
|
46
|
+
registryDependencies: z.array(z.string().min(1)).optional(),
|
|
47
|
+
files: z.array(ContractRegistryFileSchema).min(1),
|
|
48
|
+
schema: z.object({
|
|
49
|
+
input: z.unknown().optional(),
|
|
50
|
+
output: z.unknown().optional()
|
|
51
|
+
}).optional()
|
|
52
|
+
});
|
|
53
|
+
const ContractRegistryManifestSchema = z.object({
|
|
54
|
+
$schema: z.string().min(1).optional(),
|
|
55
|
+
name: z.string().min(1),
|
|
56
|
+
homepage: z.string().min(1).optional(),
|
|
57
|
+
items: z.array(ContractRegistryItemSchema)
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
export { ContractRegistryFileSchema, ContractRegistryItemSchema, ContractRegistryItemTypeSchema, ContractRegistryManifestSchema };
|
|
@@ -1 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/contracts-adapter-hydration.ts
|
|
2
|
+
function parseReturns(returnsLike) {
|
|
3
|
+
if (!returnsLike) return {
|
|
4
|
+
isList: false,
|
|
5
|
+
inner: "JSON"
|
|
6
|
+
};
|
|
7
|
+
const trimmed = String(returnsLike).trim();
|
|
8
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) return {
|
|
9
|
+
isList: true,
|
|
10
|
+
inner: trimmed.slice(1, -1).trim()
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
isList: false,
|
|
14
|
+
inner: trimmed
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
async function hydrateResourceIfNeeded(resources, result, opts) {
|
|
18
|
+
if (!resources || !opts.template) return result;
|
|
19
|
+
const varName = opts.varName ?? "id";
|
|
20
|
+
const hydrateOne = async (item) => {
|
|
21
|
+
if (item && typeof item[varName] !== "undefined") {
|
|
22
|
+
const key = String(item[varName]);
|
|
23
|
+
const uri = opts.template.replace("{id}", key);
|
|
24
|
+
const match = resources.match(uri);
|
|
25
|
+
if (match) {
|
|
26
|
+
const resolved = await match.tmpl.resolve(match.params, {});
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(String(resolved.data || "null"));
|
|
29
|
+
} catch {
|
|
30
|
+
return resolved.data;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return item;
|
|
35
|
+
};
|
|
36
|
+
if (opts.returns.isList && Array.isArray(result)) return await Promise.all(result.map((x) => hydrateOne(x)));
|
|
37
|
+
return await hydrateOne(result);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { hydrateResourceIfNeeded, parseReturns };
|