cvx-kit 0.1.12 → 0.1.13
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/CHANGELOG.md +16 -0
- package/dist/modules/contracts/binding.d.mts +13 -1
- package/dist/modules/contracts/binding.mjs +1 -1
- package/dist/modules/contracts/binding.mjs.map +1 -1
- package/dist/modules/effect/command.d.mts +13 -9
- package/dist/modules/effect/command.mjs.map +1 -1
- package/dist/modules/effect/domain.d.mts +31 -3
- package/dist/modules/effect/domain.mjs.map +1 -1
- package/dist/modules/effect/query.d.mts +6 -5
- package/dist/modules/effect/query.mjs.map +1 -1
- package/dist/modules/foundation/foundation.d.mts +14 -13
- package/dist/modules/foundation/foundation.mjs.map +1 -1
- package/dist/modules/foundation/operation.d.mts +20 -1
- package/dist/modules/foundation/operation.mjs.map +1 -1
- package/docs/domain-contracts.md +42 -9
- package/package.json +1 -1
- package/scripts/test-packed-effect.mjs +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,22 @@ are this file's matching section.
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
|
+
## [0.1.13] - 2026-10-10
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- Implement contracted operations with `command.handler(handler, options?)` and
|
|
20
|
+
`query.handler(handler, options?)` in both Promise and Effect registries.
|
|
21
|
+
- Infer each handler's input and result from its operation object key, without
|
|
22
|
+
repeating the operation name; preserve existing named helpers.
|
|
23
|
+
|
|
24
|
+
### Verified
|
|
25
|
+
|
|
26
|
+
- Cover contract binding, validation, audits, and handler inference with 684
|
|
27
|
+
runtime tests and strict type fixtures.
|
|
28
|
+
- Compile the documentation examples and test packed npm/Bun consumers with
|
|
29
|
+
and without Effect.
|
|
30
|
+
|
|
15
31
|
## [0.1.12] - 2026-10-10
|
|
16
32
|
|
|
17
33
|
### Added
|
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
import { DomainContract } from "./domain.mjs";
|
|
1
|
+
import { DomainContract, DomainOperationContract } from "./domain.mjs";
|
|
2
2
|
//#region src/modules/contracts/binding.d.ts
|
|
3
|
+
declare const declaredSchemas: unique symbol;
|
|
4
|
+
/** Private evidence for contextual inference; schemas are installed only at registration. */
|
|
5
|
+
export type DeclaredSchemas<Entry> = {
|
|
6
|
+
readonly [declaredSchemas]: Entry;
|
|
7
|
+
};
|
|
8
|
+
export type BoundOperations<Operations extends Readonly<Record<keyof Entries, {
|
|
9
|
+
handler: (...arguments_: never[]) => unknown;
|
|
10
|
+
}>>, Entries extends Readonly<Record<string, DomainOperationContract>>> = { [Key in keyof Entries]: Entries[Key] & Operations[Key] & {
|
|
11
|
+
input: Entries[Key]['input'];
|
|
12
|
+
result: Entries[Key]['result'];
|
|
13
|
+
handler: Operations[Key]['handler'];
|
|
14
|
+
}; };
|
|
3
15
|
/** Both adapters bind declarations through the same configuration boundary. */
|
|
4
16
|
export declare function domainHelpers(entries: Readonly<Record<string, object>>): {
|
|
5
17
|
[k: string]: (implementation: object) => {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=[`input`,`result`,`classification`,`replayResult`,`wire`],t=/* @__PURE__ */ new WeakMap;function
|
|
1
|
+
const e=[`input`,`result`,`classification`,`replayResult`,`wire`],t=/* @__PURE__ */ new WeakMap,n=/* @__PURE__ */ new WeakMap;function r(e){let t=Object.fromEntries(Object.keys(e).map(t=>[t,n=>i(t,e[t],n)])),r=t.handler;return t.handler=(t,i)=>{if(typeof t!=`function`&&r)return r(t);if(typeof t!=`function`)throw Error(`Invalid operation handler`);let a={...i,handler:t};return n.set(a,e),a},t}function i(n,r,i){for(let e of[`handler`,`audit`,`prepare`,`guard`,`middleware`,`context`])if(Object.prototype.hasOwnProperty.call(r,e))throw Error(`Domain contract ${n} cannot contain ${e}`);for(let t of e)if(Object.prototype.hasOwnProperty.call(i,t))throw Error(`Contracted operation ${n} cannot override ${t}`);let a={...i,...r};return t.set(a,{key:n,declaration:r}),a}function a(r,a,o,s){if(s!==void 0&&typeof s!=`function`)throw Error(`Invalid registry audit callback`);let c=a?.[o];if(a&&!c)throw Error(`Domain contract has no ${o} section`);let l=Object.keys(r);if(c&&(l.length!==Object.keys(c).length||l.some(e=>!Object.prototype.hasOwnProperty.call(c,e))))throw Error(`Contract operation keys must match exactly`);let u=l.map(a=>{let l=r[a];if(c){if(n.has(l)){if(n.get(l)!==c)throw Error(`Operation ${a} must use its own contract helper`);l=i(a,c[a],l)}let r=t.get(l);if(!r||r.key!==a||r.declaration!==c[a]||e.some(e=>l[e]!==c[a][e]))throw Error(`Operation ${a} must use its own contract helper`)}let u={...l};if(u.wire&&=Object.freeze({...u.wire}),o===`commands`){let e=u.audit;if(e!==void 0&&typeof e!=`function`)throw Error(`Invalid audit for ${a}`);if(e===void 0){if(!s)throw Error(`Command ${a} requires an audit callback`);u.audit=(e,t)=>s({operation:a,input:e.command,result:e.result},t)}}return[a,Object.freeze(u)]});return Object.freeze(Object.fromEntries(u))}export{i as bindDomainImplementation,r as domainHelpers,a as snapshotOperations};
|
|
2
2
|
//# sourceMappingURL=binding.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.mjs","names":["protectedFields","bindings","domainHelpers","entries","key","bindDomainImplementation","implementation","field","declaration","definition","snapshotOperations","audit","declarations","contract","section","keys","operations","original","binding","override","resolution","context"],"sources":["../../../src/modules/contracts/binding.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-object-parameters, anti-slop/no-unsafe-dictionary-type, anti-slop/no-known-value-widening, anti-slop/no-runtime-typeof, anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns -- Configuration boundary validates heterogeneous own-key records and callback presence; validators remain opaque identities. */\nimport type { DomainContract } from './domain'\n\n// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\nconst protectedFields = ['input', 'result', 'classification', 'replayResult', 'wire'] as const\nconst bindings = new WeakMap<object, { key: string; declaration: object }>()\n\n/** Both adapters bind declarations through the same configuration boundary. */\nexport function domainHelpers(entries: Readonly<Record<string, object>>) {\n\
|
|
1
|
+
{"version":3,"file":"binding.mjs","names":["protectedFields","bindings","pending","domainHelpers","helpers","entries","key","bindDomainImplementation","implementation","namedHandler","handler","options","field","declaration","definition","snapshotOperations","audit","declarations","contract","section","keys","operations","original","binding","override","resolution","context"],"sources":["../../../src/modules/contracts/binding.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-object-parameters, anti-slop/no-unsafe-dictionary-type, anti-slop/no-known-value-widening, anti-slop/no-runtime-typeof, anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns -- Configuration boundary validates heterogeneous own-key records and callback presence; validators remain opaque identities. */\nimport type { DomainContract, DomainOperationContract } from './domain'\n\ndeclare const declaredSchemas: unique symbol\n/** Private evidence for contextual inference; schemas are installed only at registration. */\nexport type DeclaredSchemas<Entry> = { readonly [declaredSchemas]: Entry }\nexport type BoundOperations<\n\tOperations extends Readonly<\n\t\tRecord<keyof Entries, { handler: (...arguments_: never[]) => unknown }>\n\t>,\n\tEntries extends Readonly<Record<string, DomainOperationContract>>,\n> = {\n\t[Key in keyof Entries]: Entries[Key] &\n\t\tOperations[Key] & {\n\t\t\tinput: Entries[Key]['input']\n\t\t\tresult: Entries[Key]['result']\n\t\t\thandler: Operations[Key]['handler']\n\t\t}\n}\n\n// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\nconst protectedFields = ['input', 'result', 'classification', 'replayResult', 'wire'] as const\nconst bindings = new WeakMap<object, { key: string; declaration: object }>()\nconst pending = new WeakMap<object, Readonly<Record<string, object>>>()\n\n/** Both adapters bind declarations through the same configuration boundary. */\nexport function domainHelpers(entries: Readonly<Record<string, object>>) {\n\tconst helpers = Object.fromEntries(\n\t\tObject.keys(entries).map((key) => [\n\t\t\tkey,\n\t\t\t(implementation: object) => bindDomainImplementation(key, entries[key], implementation),\n\t\t]),\n\t)\n\tconst namedHandler = helpers.handler\n\thelpers.handler = (handler: Function | object, options?: object) => {\n\t\tif (typeof handler !== 'function' && namedHandler) return namedHandler(handler)\n\t\tif (typeof handler !== 'function') throw Error('Invalid operation handler')\n\t\tconst implementation = { ...options, handler }\n\t\tpending.set(implementation, entries)\n\t\treturn implementation\n\t}\n\treturn helpers\n}\n\n/** Bind only opaque schema references; never invoke user callbacks at construction. */\nexport function bindDomainImplementation(key: string, declaration: object, implementation: object) {\n\tfor (const field of ['handler', 'audit', 'prepare', 'guard', 'middleware', 'context']) {\n\t\tif (Object.prototype.hasOwnProperty.call(declaration, field))\n\t\t\tthrow Error(`Domain contract ${key} cannot contain ${field}`)\n\t}\n\tfor (const field of protectedFields) {\n\t\tif (Object.prototype.hasOwnProperty.call(implementation, field))\n\t\t\tthrow Error(`Contracted operation ${key} cannot override ${field}`)\n\t}\n\tconst definition = { ...implementation, ...declaration }\n\tbindings.set(definition, { key, declaration })\n\treturn definition\n}\n\n/** Snapshot records and verify key ownership before the executor closes over them. */\nexport function snapshotOperations(\n\toperations: Readonly<Record<string, object>>,\n\tcontract: DomainContract | undefined,\n\tsection: 'commands' | 'queries',\n\taudit?: (resolution: never, context: never) => unknown,\n) {\n\tif (audit !== undefined && typeof audit !== 'function')\n\t\tthrow Error('Invalid registry audit callback')\n\tconst declarations = contract?.[section]\n\tif (contract && !declarations) throw Error(`Domain contract has no ${section} section`)\n\tconst keys = Object.keys(operations)\n\tif (\n\t\tdeclarations &&\n\t\t(keys.length !== Object.keys(declarations).length ||\n\t\t\tkeys.some((key) => !Object.prototype.hasOwnProperty.call(declarations, key)))\n\t)\n\t\tthrow Error('Contract operation keys must match exactly')\n\tconst entries = keys.map((key) => {\n\t\tlet original = operations[key]\n\t\tif (declarations) {\n\t\t\tif (pending.has(original)) {\n\t\t\t\tif (pending.get(original) !== declarations)\n\t\t\t\t\tthrow Error(`Operation ${key} must use its own contract helper`)\n\t\t\t\toriginal = bindDomainImplementation(key, declarations[key], original)\n\t\t\t}\n\t\t\tconst binding = bindings.get(original)\n\t\t\tif (\n\t\t\t\t!binding ||\n\t\t\t\tbinding.key !== key ||\n\t\t\t\tbinding.declaration !== declarations[key] ||\n\t\t\t\tprotectedFields.some(\n\t\t\t\t\t(field) =>\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t(original as Record<string, unknown>)[field] !==\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t(declarations[key] as Record<string, unknown>)[field],\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tthrow Error(`Operation ${key} must use its own contract helper`)\n\t\t}\n\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\tconst definition = { ...original } as Record<string, unknown>\n\t\tif (definition.wire) {\n\t\t\t// SAFETY: wire is configuration, while its schema stays an opaque reference.\n\t\t\tdefinition.wire = Object.freeze({ ...(definition.wire as object) })\n\t\t}\n\t\tif (section === 'commands') {\n\t\t\tconst override = definition.audit\n\t\t\tif (override !== undefined && typeof override !== 'function')\n\t\t\t\tthrow Error(`Invalid audit for ${key}`)\n\t\t\tif (override === undefined) {\n\t\t\t\tif (!audit) throw Error(`Command ${key} requires an audit callback`)\n\t\t\t\tdefinition.audit = (resolution: { command: unknown; result: unknown }, context: unknown) =>\n\t\t\t\t\taudit(\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\t{ operation: key, input: resolution.command, result: resolution.result } as never,\n\t\t\t\t\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\t\t\t\t\tcontext as never,\n\t\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\t// SAFETY: this configuration boundary compares opaque fields or restores callback slots checked by the public helpers.\n\t\treturn [key, Object.freeze(definition)] as const\n\t})\n\treturn Object.freeze(Object.fromEntries(entries))\n}\n"],"mappings":"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"}
|
|
@@ -4,7 +4,8 @@ import { Observability } from "../../components/foundation/modules/observability
|
|
|
4
4
|
import { AuditEntryInput } from "../../components/foundation/client.mjs";
|
|
5
5
|
import { DomainAuditInput, DomainCommandContract, DomainContract } from "../contracts/domain.mjs";
|
|
6
6
|
import { CallbackError, CallbackRequirements, CheckedEffectOperation, EffectOperationArgument, EffectOperationError, EffectOperationRequirements, EffectOperationResult, EffectValue, UnwrappedDefaultError, UnwrappedDefaultRequirements, ValidatedEffectOperations, effectOperationFactory } from "./operation.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import { BoundOperations } from "../contracts/binding.mjs";
|
|
8
|
+
import { AuditValue, AuditedOperations, DomainEffectFactory, DomainEffectImplementations, ExactDomainOperations, SharedEffectFactory } from "./domain.mjs";
|
|
8
9
|
import { Effect } from "effect";
|
|
9
10
|
//#region src/modules/effect/command.d.ts
|
|
10
11
|
type Supported<Value> = Value | PromiseLike<Value> | Effect.Effect<Value, unknown, unknown>;
|
|
@@ -62,26 +63,29 @@ export declare function createEffectCommand<Resolve extends Resolver, const Oper
|
|
|
62
63
|
export declare function bindEffectCommand<const Dependencies extends EffectCommandDependencies>(dependencies: Dependencies): {
|
|
63
64
|
<Resolve extends Resolver, const Contract extends DomainContract & {
|
|
64
65
|
commands: Readonly<Record<string, DomainCommandContract>>;
|
|
65
|
-
}, const Operations extends
|
|
66
|
-
contract: Contract
|
|
66
|
+
}, const Operations extends DomainEffectImplementations<DomainOf<Resolve>, Contract['commands'], true>, Mode extends true, Guard = never>(configuration: {
|
|
67
|
+
contract: Contract & NoInfer<Operations extends ExactDomainOperations<Operations, Contract['commands']> & ValidatedEffectOperations<Operations> ? unknown : never>;
|
|
67
68
|
context: Resolve;
|
|
68
69
|
audit?: never;
|
|
69
|
-
operations: (define: DomainEffectFactory<DomainOf<Resolve>, Contract['commands'], Mode, never, NoInfer<CallbackError<Guard>>, NoInfer<CallbackRequirements<Guard>>>) => Operations
|
|
70
|
+
operations: (define: DomainEffectFactory<DomainOf<Resolve>, Contract['commands'], Mode, never, NoInfer<CallbackError<Guard>>, NoInfer<CallbackRequirements<Guard>>>) => Operations;
|
|
70
71
|
defaults?: {
|
|
71
72
|
guard?: (context: DomainOf<Resolve>) => Guard;
|
|
72
73
|
};
|
|
73
|
-
} & HostCompatible<Resolve, Dependencies>): ReturnType<typeof createEffectCommand<Resolve, Operations,
|
|
74
|
+
} & HostCompatible<Resolve, Dependencies>): ReturnType<typeof createEffectCommand<Resolve, BoundOperations<Operations, Contract['commands']> & { [Key in keyof Contract['commands']]: {
|
|
75
|
+
classification: Contract['commands'][Key]['classification'];
|
|
76
|
+
audit: Operations[Key]['audit'];
|
|
77
|
+
}; }, Dependencies, Guard>>;
|
|
74
78
|
<Resolve extends Resolver, const Contract extends DomainContract & {
|
|
75
79
|
commands: Readonly<Record<string, DomainCommandContract>>;
|
|
76
|
-
}, const Operations extends
|
|
77
|
-
contract: Contract
|
|
80
|
+
}, const Operations extends DomainEffectImplementations<DomainOf<Resolve>, Contract['commands']>, Returned extends AuditValue, Guard = never>(configuration: {
|
|
81
|
+
contract: Contract & NoInfer<Operations extends ExactDomainOperations<Operations, Contract['commands']> & ValidatedEffectOperations<Operations> ? unknown : never>;
|
|
78
82
|
context: Resolve;
|
|
79
83
|
audit: (resolution: DomainAuditInput<Contract['commands']>, context: DomainOf<Resolve>) => Returned;
|
|
80
|
-
operations: (define: DomainEffectFactory<DomainOf<Resolve>, Contract['commands'], true, [Returned] extends [never] ? never : (resolution: never, context: never) => Returned, NoInfer<CallbackError<Guard>>, NoInfer<CallbackRequirements<Guard>>>) => Operations
|
|
84
|
+
operations: (define: DomainEffectFactory<DomainOf<Resolve>, Contract['commands'], true, [Returned] extends [never] ? never : (resolution: never, context: never) => Returned, NoInfer<CallbackError<Guard>>, NoInfer<CallbackRequirements<Guard>>>) => Operations;
|
|
81
85
|
defaults?: {
|
|
82
86
|
guard?: (context: DomainOf<Resolve>) => Guard;
|
|
83
87
|
};
|
|
84
|
-
} & HostCompatible<Resolve, Dependencies>): ReturnType<typeof createEffectCommand<Resolve, AuditedOperations<Operations, (resolution: never, context: never) => Returned>, Dependencies, Guard>>;
|
|
88
|
+
} & HostCompatible<Resolve, Dependencies>): ReturnType<typeof createEffectCommand<Resolve, AuditedOperations<BoundOperations<Operations, Contract['commands']>, (resolution: never, context: never) => Returned>, Dependencies, Guard>>;
|
|
85
89
|
<Resolve extends Resolver, const Operations extends Readonly<Record<string, Pick<Operation, "classification" | "handler" | "input" | "result"> & CheckedEffectOperation<EffectValue<ReturnType<Resolve>>>>>, Returned extends AuditValue, Guard>(configuration: {
|
|
86
90
|
context: Resolve;
|
|
87
91
|
audit: (resolution: DomainAuditInput<Operations>, context: DomainOf<Resolve>) => Returned;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.mjs","names":["effectLifecycle","Effect","createEffectCommand","operations","configuration","effectOperationFactory","exec","operation","definition","decodeEffectContract","input","command","decoded","observation","resolve","normalizeEffect","host","executeCommandLifecycle","CommandPermissionError","context","preparation","result","value","normalizeCommandResult","input_","enriched","entry","Exit","exit","observationFailure","selectOperation","owner","bindEffectCommand","definitions","domainEffectFactory","snapshotOperations","dependencies","invoke"],"sources":["../../../src/modules/effect/command.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-returns, anti-slop/no-unsafe-dictionary-type -- Overload implementation storage is erased; public signatures retain concrete values, errors and services. */\nimport { Effect, Exit } from 'effect'\nimport type { AuditEntryInput } from '../../components/foundation/client'\nimport type { ContractSchema } from '../contracts/contract'\nimport {\n\tselectOperation,\n\ttype SelectedOperation,\n\ttype OperationPublicResult,\n} from '../contracts/exposure'\nimport { decodeEffectContract } from './schema'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Internal optional adapter shares the Effect-free Foundation lifecycle and types without entering the Convex component deployment graph.\nimport {\n\tCommandPermissionError,\n\texecuteCommandLifecycle,\n\ttype ExecutionKind,\n\ttype LifecycleAlgebra,\n\ttype LifecyclePreparation,\n} from '../../components/foundation/modules/command/lifecycle'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Internal optional adapter shares the Effect-free Foundation lifecycle and types without entering the Convex component deployment graph.\nimport type { Observability } from '../../components/foundation/modules/observability/observability'\nimport { normalizeEffect, observationFailure } from './normalize'\nimport {\n\teffectOperationFactory,\n\ttype CallbackError,\n\ttype CallbackRequirements,\n\ttype EffectValue,\n\ttype EffectOperationArgument,\n\ttype EffectOperationInput,\n\ttype EffectOperationHandlerResult,\n\ttype EffectPreparation,\n\ttype EffectOperationResult,\n\ttype EffectOperationError,\n\ttype EffectOperationRequirements,\n\ttype CheckedEffectOperation,\n\ttype UnwrappedDefaultError,\n\ttype UnwrappedDefaultRequirements,\n\ttype ValidatedEffectOperations,\n} from './operation'\n\nimport type { DomainContract, DomainCommandContract, DomainAuditInput } from '../contracts/domain'\nimport { snapshotOperations } from '../contracts/binding'\nimport {\n\tdomainEffectFactory,\n\ttype DomainEffectFactory,\n\ttype ExactDomainOperations,\n\ttype AuditedOperations,\n\ttype SharedEffectFactory,\n\ttype AuditValue,\n} from './domain'\n\ntype Supported<Value> = Value | PromiseLike<Value> | Effect.Effect<Value, unknown, unknown>\n// Heterogeneous storage constraints preserve concrete callbacks in inferred definitions.\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal callback storage; selected definitions retain concrete return contracts.\ntype Callback = (...arguments_: never[]) => Supported<unknown>\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- Resolver constraint captures its concrete return in Resolve; it never exposes this storage type at exec.\ntype Resolver = (host: never) => Supported<unknown>\ntype HostOf<Resolve extends Resolver> = Parameters<Resolve>[0]\ntype DomainOf<Resolve extends Resolver> = EffectValue<ReturnType<Resolve>>\ntype Operation = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\tclassification: string\n\thandler: Callback\n\taudit: Callback\n\tguard?: Callback\n\tprepare?: Callback\n\tmiddleware?: Callback\n\tpermission?: string\n\taggregates?: readonly string[]\n\treplayResult?: ContractSchema\n}\ntype Registry<Context> = Readonly<\n\tRecord<\n\t\tstring,\n\t\tPick<Operation, 'input' | 'result' | 'classification' | 'handler' | 'audit'> &\n\t\t\tCheckedEffectOperation<Context>\n\t>\n>\nexport type EffectCommandDependencies = {\n\tobservability: Observability\n\tcheckPermission?: (\n\t\thost: never,\n\t\tinput: { permission: string; operation: string },\n\t) => Supported<void>\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Audit writer storage; its concrete return/error/services remain in Dependencies.\n\twriteAudit: (host: never, entry: AuditEntryInput) => Supported<unknown>\n}\ntype HostParameter<Policy> = [Exclude<Policy, undefined>] extends [never]\n\t? unknown\n\t: // oxlint-disable-next-line anti-slop/no-unknown-returns -- Conditional parameter-extraction predicate, not an executable callback contract.\n\t\tExclude<Policy, undefined> extends (...arguments_: infer Arguments) => Supported<unknown>\n\t\t? Arguments extends []\n\t\t\t? unknown\n\t\t\t: Arguments[0]\n\t\t: unknown\ntype PolicyHost<Dependencies extends EffectCommandDependencies> = HostParameter<\n\tDependencies['writeAudit']\n> &\n\tHostParameter<Dependencies['checkPermission']>\ntype HostCompatible<Resolve extends Resolver, Dependencies extends EffectCommandDependencies> = [\n\tHostOf<Resolve>,\n] extends [PolicyHost<Dependencies>]\n\t? unknown\n\t: { context: never }\ntype Factory<Resolve extends Resolver, Guard> = ReturnType<\n\ttypeof effectOperationFactory<\n\t\tDomainOf<Resolve>,\n\t\tRecord<never, never>,\n\t\tNoInfer<CallbackError<Guard>>,\n\t\tNoInfer<CallbackRequirements<Guard>>\n\t>\n>\nexport type EffectCommandConfiguration<\n\tResolve extends Resolver,\n\tOperations extends Registry<DomainOf<Resolve>>,\n\tGuard,\n> = {\n\tcontext: Resolve\n\toperations: (\n\t\tdefine: Factory<Resolve, Guard>,\n\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\tdefaults?: { guard?: (context: DomainOf<Resolve>) => Guard }\n}\ntype ErrorOf<Definition, Resolve, Dependencies, Guard> =\n\t| EffectOperationError<Definition>\n\t| CallbackError<Resolve | Dependencies[keyof Dependencies]>\n\t| UnwrappedDefaultError<Definition, Guard>\ntype RequirementsOf<Definition, Resolve, Dependencies, Guard> =\n\t| EffectOperationRequirements<Definition>\n\t| CallbackRequirements<Resolve | Dependencies[keyof Dependencies]>\n\t| UnwrappedDefaultRequirements<Definition, Guard>\ninterface EffectExecution extends ExecutionKind {\n\treadonly type: Effect.Effect<this['value'], unknown, unknown>\n}\nconst effectLifecycle: LifecycleAlgebra<EffectExecution> = {\n\tsucceed: Effect.succeed,\n\tsuspend: Effect.suspend,\n\tflatMap: Effect.flatMap,\n}\ntype RuntimeOperation<Context, Input, Raw, Result> = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\tclassification: string\n\tpermission?: string\n\taggregates?: readonly string[]\n\treplayResult?: ContractSchema\n\thandler: (input: Input, context: Context) => Supported<Raw>\n\tguard?: (context: Context, input: Input) => Supported<void>\n\tprepare?: (\n\t\tcontext: Context,\n\t\tinput: Input,\n\t) => Supported<EffectPreparation<Result, unknown, unknown>>\n\taudit: (\n\t\tresolution: { command: Input; result: Result },\n\t\tcontext: Context,\n\t) => Supported<Omit<AuditEntryInput, 'classification'> | null>\n\tmiddleware?: (input: {\n\t\toperation: string\n\t\tcommand: Input\n\t\tinput: Input\n\t\tcontext: Context\n\t\tnext: (options?: { context?: object }) => Effect.Effect<Raw, unknown, unknown>\n\t}) => Supported<Raw>\n}\n\n/** Internal registry constructor: the public Foundation binds host policies once. */\nexport function createEffectCommand<\n\tResolve extends Resolver,\n\tconst Operations extends Registry<DomainOf<Resolve>>,\n\tconst Dependencies extends EffectCommandDependencies,\n\tGuard = never,\n>(\n\tconfiguration: EffectCommandConfiguration<Resolve, Operations, Guard> &\n\t\tDependencies &\n\t\tHostCompatible<Resolve, Dependencies>,\n) {\n\tconst operations: Operations =\n\t\tconfiguration.operations(\n\t\t\teffectOperationFactory<\n\t\t\t\tDomainOf<Resolve>,\n\t\t\t\tRecord<never, never>,\n\t\t\t\tCallbackError<Guard>,\n\t\t\t\tCallbackRequirements<Guard>\n\t\t\t>(),\n\t\t)\n\tconst exec = <Key extends Extract<keyof Operations, string>>(\n\t\toperation: Key,\n\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\thost: HostOf<Resolve>,\n\t): Effect.Effect<\n\t\tEffectOperationResult<Operations[Key]>,\n\t\tErrorOf<Operations[Key], Resolve, Dependencies, Guard>,\n\t\tRequirementsOf<Operations[Key], Resolve, Dependencies, Guard>\n\t> => {\n\t\tconst execution = Effect.suspend(() => {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(operations, operation))\n\t\t\t\tthrow Error('The selected command operation is not configured')\n\t\t\t// SAFETY: this helper checked selected callbacks against their parsed schemas and domain context.\n\t\t\tconst definition = operations[operation] as Operations[Key] &\n\t\t\t\tRuntimeOperation<\n\t\t\t\t\tDomainOf<Resolve>,\n\t\t\t\t\tEffectOperationInput<Operations[Key]>,\n\t\t\t\t\tEffectOperationHandlerResult<Operations[Key]>,\n\t\t\t\t\tEffectOperationResult<Operations[Key]>\n\t\t\t\t>\n\t\t\t// SAFETY: selected command input was parsed by its own paired schema.\n\t\t\treturn Effect.flatMap(decodeEffectContract(definition.input, input), (decoded) => {\n\t\t\t\t// SAFETY: the selected operation's decoder owns this concrete domain input.\n\t\t\t\tconst command = decoded as EffectOperationInput<Operations[Key]>\n\t\t\t\tconst observation = configuration.observability.start({\n\t\t\t\t\toperation,\n\t\t\t\t\tclassification: definition.classification,\n\t\t\t\t})\n\t\t\t\t// SAFETY: resolver identity owns its concrete invocation return and host parameter.\n\t\t\t\tconst resolve = configuration.context as (host: HostOf<Resolve>) => ReturnType<Resolve>\n\t\t\t\treturn normalizeEffect(() => resolve(host)).pipe(\n\t\t\t\t\tEffect.flatMap((context) => {\n\t\t\t\t\t\tconst lifecycle = executeCommandLifecycle<\n\t\t\t\t\t\t\tEffectExecution,\n\t\t\t\t\t\t\tDomainOf<Resolve>,\n\t\t\t\t\t\t\tEffectOperationInput<Operations[Key]>,\n\t\t\t\t\t\t\tEffectOperationHandlerResult<Operations[Key]>,\n\t\t\t\t\t\t\tEffectOperationResult<Operations[Key]>\n\t\t\t\t\t\t>(effectLifecycle, {\n\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\tclassification: definition.classification,\n\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\tcommand,\n\t\t\t\t\t\t\tpermission:\n\t\t\t\t\t\t\t\tdefinition.permission === undefined\n\t\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t\t: () =>\n\t\t\t\t\t\t\t\t\t\t\tnormalizeEffect(() => {\n\t\t\t\t\t\t\t\t\t\t\t\tif (!configuration.checkPermission)\n\t\t\t\t\t\t\t\t\t\t\t\t\tthrow new CommandPermissionError(operation)\n\t\t\t\t\t\t\t\t\t\t\t\t// SAFETY: HostCompatible proves this invocation satisfies the configured policy host.\n\t\t\t\t\t\t\t\t\t\t\t\treturn configuration.checkPermission(host as never, {\n\t\t\t\t\t\t\t\t\t\t\t\t\tpermission: definition.permission!,\n\t\t\t\t\t\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\t}).pipe(Effect.asVoid),\n\t\t\t\t\t\t\tprepare: () =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => definition.prepare?.(context, command)).pipe(\n\t\t\t\t\t\t\t\t\tEffect.map((preparation) => {\n\t\t\t\t\t\t\t\t\t\tif (preparation?.kind !== 'execute') return preparation\n\t\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t\tkind: 'execute',\n\t\t\t\t\t\t\t\t\t\t\tcomplete: preparation.complete\n\t\t\t\t\t\t\t\t\t\t\t\t? (result) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tnormalizeEffect(() => preparation.complete!(result)).pipe(Effect.asVoid)\n\t\t\t\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\t\t\t\t} satisfies LifecyclePreparation<\n\t\t\t\t\t\t\t\t\t\t\tEffectExecution,\n\t\t\t\t\t\t\t\t\t\t\tEffectOperationResult<Operations[Key]>\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t// SAFETY: the selected final replay contract owns this result; operation types retain its E/R.\n\t\t\t\t\t\t\tdecodeReplay: (value) =>\n\t\t\t\t\t\t\t\tdecodeEffectContract(\n\t\t\t\t\t\t\t\t\tdefinition.replayResult ?? definition.result,\n\t\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\t) as Effect.Effect<EffectOperationResult<Operations[Key]>, unknown, unknown>,\n\t\t\t\t\t\t\tmiddleware: definition.middleware\n\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t(input_) =>\n\t\t\t\t\t\t\t\t\t\t\tnormalizeCommandResult(() =>\n\t\t\t\t\t\t\t\t\t\t\t\tdefinition.middleware!({ ...input_, input: command }),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t: [],\n\t\t\t\t\t\t\tdefaultGuard: (enriched) =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => configuration.defaults?.guard?.(enriched)).pipe(\n\t\t\t\t\t\t\t\t\tEffect.asVoid,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tguard: (enriched) =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => definition.guard?.(enriched, command)).pipe(Effect.asVoid),\n\t\t\t\t\t\t\trun: (enriched) =>\n\t\t\t\t\t\t\t\tnormalizeCommandResult(() => definition.handler(command, enriched)),\n\t\t\t\t\t\t\t// SAFETY: the selected contract owns the decoded result; the public operation retains decoder E/R.\n\t\t\t\t\t\t\tdecodeResult: (value) =>\n\t\t\t\t\t\t\t\tdecodeEffectContract(definition.result, value) as Effect.Effect<\n\t\t\t\t\t\t\t\t\tEffectOperationResult<Operations[Key]>,\n\t\t\t\t\t\t\t\t\tunknown,\n\t\t\t\t\t\t\t\t\tunknown\n\t\t\t\t\t\t\t\t>,\n\t\t\t\t\t\t\taudit: (result) =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => definition.audit({ command, result }, context)),\n\t\t\t\t\t\t\twriteAudit: (entry) =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => {\n\t\t\t\t\t\t\t\t\t// SAFETY: HostCompatible proves this invocation satisfies the configured writer host.\n\t\t\t\t\t\t\t\t\treturn configuration.writeAudit(host as never, entry)\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\taggregates: definition.aggregates,\n\t\t\t\t\t\t})\n\t\t\t\t\t\treturn lifecycle\n\t\t\t\t\t}),\n\t\t\t\t\tEffect.onExit((exit) =>\n\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\tif (Exit.isSuccess(exit)) observation.completed()\n\t\t\t\t\t\t\telse observation.failed(observationFailure(exit.cause))\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\t\t// SAFETY: dispatch selects exactly this operation; callbacks preserve the concrete definition/policy E/R.\n\t\treturn execution as Effect.Effect<\n\t\t\tEffectOperationResult<Operations[Key]>,\n\t\t\tErrorOf<Operations[Key], Resolve, Dependencies, Guard>,\n\t\t\tRequirementsOf<Operations[Key], Resolve, Dependencies, Guard>\n\t\t>\n\t}\n\treturn {\n\t\t/** Bind invocation context without resolving it or running an operation. */\n\t\twithContext(context: HostOf<Resolve>) {\n\t\t\treturn {\n\t\t\t\texec: <Key extends Extract<keyof Operations, string>>(\n\t\t\t\t\toperation: Key,\n\t\t\t\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\t\t\t) => exec(operation, input, context),\n\t\t\t}\n\t\t},\n\t\texpose<const Owner extends symbol, const Key extends Extract<keyof Operations, string>>(\n\t\t\towner: Owner,\n\t\t\toperation: Key,\n\t\t): SelectedOperation<\n\t\t\tOwner,\n\t\t\tKey,\n\t\t\tOperations[Key]['input'],\n\t\t\tOperationPublicResult<Operations[Key]>\n\t\t> {\n\t\t\tif (!Object.hasOwn(operations, operation))\n\t\t\t\tthrow Error('The selected command operation is not configured')\n\t\t\treturn selectOperation(owner, 'mutation', operation, operations[operation])\n\t\t},\n\t\texec,\n\t}\n}\n\n/** Bind trusted application policies without exposing a loose public command kernel. */\nexport function bindEffectCommand<const Dependencies extends EffectCommandDependencies>(\n\tdependencies: Dependencies,\n) {\n\ttype LooseRegistry<Context> = Readonly<\n\t\tRecord<\n\t\t\tstring,\n\t\t\tPick<Operation, 'input' | 'result' | 'classification' | 'handler'> &\n\t\t\t\tCheckedEffectOperation<Context>\n\t\t>\n\t>\n\n\tfunction command<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & {\n\t\t\tcommands: Readonly<Record<string, DomainCommandContract>>\n\t\t},\n\t\tconst Operations extends Registry<DomainOf<Resolve>>,\n\t\tMode extends true,\n\t\tGuard = never,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract\n\t\t\tcontext: Resolve\n\t\t\taudit?: never\n\t\t\toperations: (\n\t\t\t\tdefine: DomainEffectFactory<\n\t\t\t\t\tDomainOf<Resolve>,\n\t\t\t\t\tContract['commands'],\n\t\t\t\t\tMode,\n\t\t\t\t\tnever,\n\t\t\t\t\tNoInfer<CallbackError<Guard>>,\n\t\t\t\t\tNoInfer<CallbackRequirements<Guard>>\n\t\t\t\t>,\n\t\t\t) => Operations &\n\t\t\t\tNoInfer<ExactDomainOperations<Operations, Contract['commands']>> &\n\t\t\t\tNoInfer<ValidatedEffectOperations<Operations>>\n\t\t\tdefaults?: { guard?: (context: DomainOf<Resolve>) => Guard }\n\t\t} & HostCompatible<Resolve, Dependencies>,\n\t): ReturnType<typeof createEffectCommand<Resolve, Operations, Dependencies, Guard>>\n\tfunction command<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & {\n\t\t\tcommands: Readonly<Record<string, DomainCommandContract>>\n\t\t},\n\t\tconst Operations extends LooseRegistry<DomainOf<Resolve>>,\n\t\tReturned extends AuditValue,\n\t\tGuard = never,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract\n\t\t\tcontext: Resolve\n\t\t\taudit: (\n\t\t\t\tresolution: DomainAuditInput<Contract['commands']>,\n\t\t\t\tcontext: DomainOf<Resolve>,\n\t\t\t) => Returned\n\t\t\toperations: (\n\t\t\t\tdefine: DomainEffectFactory<\n\t\t\t\t\tDomainOf<Resolve>,\n\t\t\t\t\tContract['commands'],\n\t\t\t\t\ttrue,\n\t\t\t\t\t[Returned] extends [never] ? never : (resolution: never, context: never) => Returned,\n\t\t\t\t\tNoInfer<CallbackError<Guard>>,\n\t\t\t\t\tNoInfer<CallbackRequirements<Guard>>\n\t\t\t\t>,\n\t\t\t) => Operations &\n\t\t\t\tNoInfer<ExactDomainOperations<Operations, Contract['commands']>> &\n\t\t\t\tNoInfer<ValidatedEffectOperations<Operations>>\n\t\t\tdefaults?: { guard?: (context: DomainOf<Resolve>) => Guard }\n\t\t} & HostCompatible<Resolve, Dependencies>,\n\t): ReturnType<\n\t\ttypeof createEffectCommand<\n\t\t\tResolve,\n\t\t\tAuditedOperations<Operations, (resolution: never, context: never) => Returned>,\n\t\t\tDependencies,\n\t\t\tGuard\n\t\t>\n\t>\n\tfunction command<\n\t\tResolve extends Resolver,\n\t\tconst Operations extends LooseRegistry<DomainOf<Resolve>>,\n\t\tReturned extends AuditValue,\n\t\tGuard,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontext: Resolve\n\t\t\taudit: (resolution: DomainAuditInput<Operations>, context: DomainOf<Resolve>) => Returned\n\t\t\toperations: (\n\t\t\t\tdefine: SharedEffectFactory<DomainOf<Resolve>, Guard>,\n\t\t\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\t\t\tdefaults?: { guard?: (context: DomainOf<Resolve>) => Guard }\n\t\t} & HostCompatible<Resolve, Dependencies>,\n\t): ReturnType<\n\t\ttypeof createEffectCommand<\n\t\t\tResolve,\n\t\t\tAuditedOperations<Operations, (resolution: never, context: never) => Returned>,\n\t\t\tDependencies,\n\t\t\tGuard\n\t\t>\n\t>\n\n\tfunction command<\n\t\tResolve extends Resolver,\n\t\tconst Operations extends Registry<DomainOf<Resolve>>,\n\t\tGuard = never,\n\t>(\n\t\tconfiguration: EffectCommandConfiguration<Resolve, Operations, Guard> &\n\t\t\tHostCompatible<Resolve, Dependencies>,\n\t): ReturnType<typeof createEffectCommand<Resolve, Operations, Dependencies, Guard>>\n\tfunction command(configuration: {\n\t\tcontext: Resolver\n\t\tcontract?: DomainContract\n\t\taudit?: (resolution: never, context: never) => AuditValue\n\t\toperations: (define: never) => Readonly<Record<string, object>>\n\t\tdefaults?: { guard?: (context: never) => unknown }\n\t}): unknown {\n\t\tconst definitions = configuration.contract\n\t\t\t? domainEffectFactory(configuration.contract.commands ?? {}, true)\n\t\t\t: effectOperationFactory()\n\t\tconst operations = snapshotOperations(\n\t\t\tconfiguration.operations(\n\t\t\t\t// SAFETY: the overload chooses this exact inline or contracted helper factory.\n\t\t\t\tdefinitions as never,\n\t\t\t),\n\t\t\tconfiguration.contract,\n\t\t\t'commands',\n\t\t\tconfiguration.audit,\n\t\t)\n\t\t// SAFETY: overloads check callbacks and schemas; binding validates exact keys and snapshots runtime records.\n\t\treturn createEffectCommand({\n\t\t\t...configuration,\n\t\t\t...dependencies,\n\t\t\toperations: () => operations,\n\t\t} as never)\n\t}\n\treturn command\n}\n\nfunction normalizeCommandResult<Value>(\n\tinvoke: () => Supported<Value>,\n): Effect.Effect<Value, unknown, unknown> {\n\t// SAFETY: selected definition helper checks the callback's normalized success against the schema input.\n\treturn normalizeEffect(invoke) as Effect.Effect<Value, unknown, unknown>\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command.mjs","names":["effectLifecycle","Effect","createEffectCommand","operations","configuration","effectOperationFactory","exec","operation","definition","decodeEffectContract","input","command","decoded","observation","resolve","normalizeEffect","host","executeCommandLifecycle","CommandPermissionError","context","preparation","result","value","normalizeCommandResult","input_","enriched","entry","Exit","exit","observationFailure","selectOperation","owner","bindEffectCommand","definitions","domainEffectFactory","snapshotOperations","dependencies","invoke"],"sources":["../../../src/modules/effect/command.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-returns, anti-slop/no-unsafe-dictionary-type -- Overload implementation storage is erased; public signatures retain concrete values, errors and services. */\nimport { Effect, Exit } from 'effect'\nimport type { AuditEntryInput } from '../../components/foundation/client'\nimport type { ContractSchema } from '../contracts/contract'\nimport {\n\tselectOperation,\n\ttype SelectedOperation,\n\ttype OperationPublicResult,\n} from '../contracts/exposure'\nimport { decodeEffectContract } from './schema'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Internal optional adapter shares the Effect-free Foundation lifecycle and types without entering the Convex component deployment graph.\nimport {\n\tCommandPermissionError,\n\texecuteCommandLifecycle,\n\ttype ExecutionKind,\n\ttype LifecycleAlgebra,\n\ttype LifecyclePreparation,\n} from '../../components/foundation/modules/command/lifecycle'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Internal optional adapter shares the Effect-free Foundation lifecycle and types without entering the Convex component deployment graph.\nimport type { Observability } from '../../components/foundation/modules/observability/observability'\nimport { normalizeEffect, observationFailure } from './normalize'\nimport {\n\teffectOperationFactory,\n\ttype CallbackError,\n\ttype CallbackRequirements,\n\ttype EffectValue,\n\ttype EffectOperationArgument,\n\ttype EffectOperationInput,\n\ttype EffectOperationHandlerResult,\n\ttype EffectPreparation,\n\ttype EffectOperationResult,\n\ttype EffectOperationError,\n\ttype EffectOperationRequirements,\n\ttype CheckedEffectOperation,\n\ttype UnwrappedDefaultError,\n\ttype UnwrappedDefaultRequirements,\n\ttype ValidatedEffectOperations,\n} from './operation'\n\nimport type { DomainContract, DomainCommandContract, DomainAuditInput } from '../contracts/domain'\nimport { snapshotOperations, type BoundOperations } from '../contracts/binding'\nimport {\n\tdomainEffectFactory,\n\ttype DomainEffectFactory,\n\ttype DomainEffectImplementations,\n\ttype ExactDomainOperations,\n\ttype AuditedOperations,\n\ttype SharedEffectFactory,\n\ttype AuditValue,\n} from './domain'\n\ntype Supported<Value> = Value | PromiseLike<Value> | Effect.Effect<Value, unknown, unknown>\n// Heterogeneous storage constraints preserve concrete callbacks in inferred definitions.\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal callback storage; selected definitions retain concrete return contracts.\ntype Callback = (...arguments_: never[]) => Supported<unknown>\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- Resolver constraint captures its concrete return in Resolve; it never exposes this storage type at exec.\ntype Resolver = (host: never) => Supported<unknown>\ntype HostOf<Resolve extends Resolver> = Parameters<Resolve>[0]\ntype DomainOf<Resolve extends Resolver> = EffectValue<ReturnType<Resolve>>\ntype Operation = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\tclassification: string\n\thandler: Callback\n\taudit: Callback\n\tguard?: Callback\n\tprepare?: Callback\n\tmiddleware?: Callback\n\tpermission?: string\n\taggregates?: readonly string[]\n\treplayResult?: ContractSchema\n}\ntype Registry<Context> = Readonly<\n\tRecord<\n\t\tstring,\n\t\tPick<Operation, 'input' | 'result' | 'classification' | 'handler' | 'audit'> &\n\t\t\tCheckedEffectOperation<Context>\n\t>\n>\nexport type EffectCommandDependencies = {\n\tobservability: Observability\n\tcheckPermission?: (\n\t\thost: never,\n\t\tinput: { permission: string; operation: string },\n\t) => Supported<void>\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Audit writer storage; its concrete return/error/services remain in Dependencies.\n\twriteAudit: (host: never, entry: AuditEntryInput) => Supported<unknown>\n}\ntype HostParameter<Policy> = [Exclude<Policy, undefined>] extends [never]\n\t? unknown\n\t: // oxlint-disable-next-line anti-slop/no-unknown-returns -- Conditional parameter-extraction predicate, not an executable callback contract.\n\t\tExclude<Policy, undefined> extends (...arguments_: infer Arguments) => Supported<unknown>\n\t\t? Arguments extends []\n\t\t\t? unknown\n\t\t\t: Arguments[0]\n\t\t: unknown\ntype PolicyHost<Dependencies extends EffectCommandDependencies> = HostParameter<\n\tDependencies['writeAudit']\n> &\n\tHostParameter<Dependencies['checkPermission']>\ntype HostCompatible<Resolve extends Resolver, Dependencies extends EffectCommandDependencies> = [\n\tHostOf<Resolve>,\n] extends [PolicyHost<Dependencies>]\n\t? unknown\n\t: { context: never }\ntype Factory<Resolve extends Resolver, Guard> = ReturnType<\n\ttypeof effectOperationFactory<\n\t\tDomainOf<Resolve>,\n\t\tRecord<never, never>,\n\t\tNoInfer<CallbackError<Guard>>,\n\t\tNoInfer<CallbackRequirements<Guard>>\n\t>\n>\nexport type EffectCommandConfiguration<\n\tResolve extends Resolver,\n\tOperations extends Registry<DomainOf<Resolve>>,\n\tGuard,\n> = {\n\tcontext: Resolve\n\toperations: (\n\t\tdefine: Factory<Resolve, Guard>,\n\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\tdefaults?: { guard?: (context: DomainOf<Resolve>) => Guard }\n}\ntype ErrorOf<Definition, Resolve, Dependencies, Guard> =\n\t| EffectOperationError<Definition>\n\t| CallbackError<Resolve | Dependencies[keyof Dependencies]>\n\t| UnwrappedDefaultError<Definition, Guard>\ntype RequirementsOf<Definition, Resolve, Dependencies, Guard> =\n\t| EffectOperationRequirements<Definition>\n\t| CallbackRequirements<Resolve | Dependencies[keyof Dependencies]>\n\t| UnwrappedDefaultRequirements<Definition, Guard>\ninterface EffectExecution extends ExecutionKind {\n\treadonly type: Effect.Effect<this['value'], unknown, unknown>\n}\nconst effectLifecycle: LifecycleAlgebra<EffectExecution> = {\n\tsucceed: Effect.succeed,\n\tsuspend: Effect.suspend,\n\tflatMap: Effect.flatMap,\n}\ntype RuntimeOperation<Context, Input, Raw, Result> = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\tclassification: string\n\tpermission?: string\n\taggregates?: readonly string[]\n\treplayResult?: ContractSchema\n\thandler: (input: Input, context: Context) => Supported<Raw>\n\tguard?: (context: Context, input: Input) => Supported<void>\n\tprepare?: (\n\t\tcontext: Context,\n\t\tinput: Input,\n\t) => Supported<EffectPreparation<Result, unknown, unknown>>\n\taudit: (\n\t\tresolution: { command: Input; result: Result },\n\t\tcontext: Context,\n\t) => Supported<Omit<AuditEntryInput, 'classification'> | null>\n\tmiddleware?: (input: {\n\t\toperation: string\n\t\tcommand: Input\n\t\tinput: Input\n\t\tcontext: Context\n\t\tnext: (options?: { context?: object }) => Effect.Effect<Raw, unknown, unknown>\n\t}) => Supported<Raw>\n}\n\n/** Internal registry constructor: the public Foundation binds host policies once. */\nexport function createEffectCommand<\n\tResolve extends Resolver,\n\tconst Operations extends Registry<DomainOf<Resolve>>,\n\tconst Dependencies extends EffectCommandDependencies,\n\tGuard = never,\n>(\n\tconfiguration: EffectCommandConfiguration<Resolve, Operations, Guard> &\n\t\tDependencies &\n\t\tHostCompatible<Resolve, Dependencies>,\n) {\n\tconst operations: Operations =\n\t\tconfiguration.operations(\n\t\t\teffectOperationFactory<\n\t\t\t\tDomainOf<Resolve>,\n\t\t\t\tRecord<never, never>,\n\t\t\t\tCallbackError<Guard>,\n\t\t\t\tCallbackRequirements<Guard>\n\t\t\t>(),\n\t\t)\n\tconst exec = <Key extends Extract<keyof Operations, string>>(\n\t\toperation: Key,\n\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\thost: HostOf<Resolve>,\n\t): Effect.Effect<\n\t\tEffectOperationResult<Operations[Key]>,\n\t\tErrorOf<Operations[Key], Resolve, Dependencies, Guard>,\n\t\tRequirementsOf<Operations[Key], Resolve, Dependencies, Guard>\n\t> => {\n\t\tconst execution = Effect.suspend(() => {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(operations, operation))\n\t\t\t\tthrow Error('The selected command operation is not configured')\n\t\t\t// SAFETY: this helper checked selected callbacks against their parsed schemas and domain context.\n\t\t\tconst definition = operations[operation] as Operations[Key] &\n\t\t\t\tRuntimeOperation<\n\t\t\t\t\tDomainOf<Resolve>,\n\t\t\t\t\tEffectOperationInput<Operations[Key]>,\n\t\t\t\t\tEffectOperationHandlerResult<Operations[Key]>,\n\t\t\t\t\tEffectOperationResult<Operations[Key]>\n\t\t\t\t>\n\t\t\t// SAFETY: selected command input was parsed by its own paired schema.\n\t\t\treturn Effect.flatMap(decodeEffectContract(definition.input, input), (decoded) => {\n\t\t\t\t// SAFETY: the selected operation's decoder owns this concrete domain input.\n\t\t\t\tconst command = decoded as EffectOperationInput<Operations[Key]>\n\t\t\t\tconst observation = configuration.observability.start({\n\t\t\t\t\toperation,\n\t\t\t\t\tclassification: definition.classification,\n\t\t\t\t})\n\t\t\t\t// SAFETY: resolver identity owns its concrete invocation return and host parameter.\n\t\t\t\tconst resolve = configuration.context as (host: HostOf<Resolve>) => ReturnType<Resolve>\n\t\t\t\treturn normalizeEffect(() => resolve(host)).pipe(\n\t\t\t\t\tEffect.flatMap((context) => {\n\t\t\t\t\t\tconst lifecycle = executeCommandLifecycle<\n\t\t\t\t\t\t\tEffectExecution,\n\t\t\t\t\t\t\tDomainOf<Resolve>,\n\t\t\t\t\t\t\tEffectOperationInput<Operations[Key]>,\n\t\t\t\t\t\t\tEffectOperationHandlerResult<Operations[Key]>,\n\t\t\t\t\t\t\tEffectOperationResult<Operations[Key]>\n\t\t\t\t\t\t>(effectLifecycle, {\n\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\tclassification: definition.classification,\n\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\tcommand,\n\t\t\t\t\t\t\tpermission:\n\t\t\t\t\t\t\t\tdefinition.permission === undefined\n\t\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t\t: () =>\n\t\t\t\t\t\t\t\t\t\t\tnormalizeEffect(() => {\n\t\t\t\t\t\t\t\t\t\t\t\tif (!configuration.checkPermission)\n\t\t\t\t\t\t\t\t\t\t\t\t\tthrow new CommandPermissionError(operation)\n\t\t\t\t\t\t\t\t\t\t\t\t// SAFETY: HostCompatible proves this invocation satisfies the configured policy host.\n\t\t\t\t\t\t\t\t\t\t\t\treturn configuration.checkPermission(host as never, {\n\t\t\t\t\t\t\t\t\t\t\t\t\tpermission: definition.permission!,\n\t\t\t\t\t\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\t}).pipe(Effect.asVoid),\n\t\t\t\t\t\t\tprepare: () =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => definition.prepare?.(context, command)).pipe(\n\t\t\t\t\t\t\t\t\tEffect.map((preparation) => {\n\t\t\t\t\t\t\t\t\t\tif (preparation?.kind !== 'execute') return preparation\n\t\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t\tkind: 'execute',\n\t\t\t\t\t\t\t\t\t\t\tcomplete: preparation.complete\n\t\t\t\t\t\t\t\t\t\t\t\t? (result) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tnormalizeEffect(() => preparation.complete!(result)).pipe(Effect.asVoid)\n\t\t\t\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\t\t\t\t} satisfies LifecyclePreparation<\n\t\t\t\t\t\t\t\t\t\t\tEffectExecution,\n\t\t\t\t\t\t\t\t\t\t\tEffectOperationResult<Operations[Key]>\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t// SAFETY: the selected final replay contract owns this result; operation types retain its E/R.\n\t\t\t\t\t\t\tdecodeReplay: (value) =>\n\t\t\t\t\t\t\t\tdecodeEffectContract(\n\t\t\t\t\t\t\t\t\tdefinition.replayResult ?? definition.result,\n\t\t\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\t\t) as Effect.Effect<EffectOperationResult<Operations[Key]>, unknown, unknown>,\n\t\t\t\t\t\t\tmiddleware: definition.middleware\n\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t(input_) =>\n\t\t\t\t\t\t\t\t\t\t\tnormalizeCommandResult(() =>\n\t\t\t\t\t\t\t\t\t\t\t\tdefinition.middleware!({ ...input_, input: command }),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t: [],\n\t\t\t\t\t\t\tdefaultGuard: (enriched) =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => configuration.defaults?.guard?.(enriched)).pipe(\n\t\t\t\t\t\t\t\t\tEffect.asVoid,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tguard: (enriched) =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => definition.guard?.(enriched, command)).pipe(Effect.asVoid),\n\t\t\t\t\t\t\trun: (enriched) =>\n\t\t\t\t\t\t\t\tnormalizeCommandResult(() => definition.handler(command, enriched)),\n\t\t\t\t\t\t\t// SAFETY: the selected contract owns the decoded result; the public operation retains decoder E/R.\n\t\t\t\t\t\t\tdecodeResult: (value) =>\n\t\t\t\t\t\t\t\tdecodeEffectContract(definition.result, value) as Effect.Effect<\n\t\t\t\t\t\t\t\t\tEffectOperationResult<Operations[Key]>,\n\t\t\t\t\t\t\t\t\tunknown,\n\t\t\t\t\t\t\t\t\tunknown\n\t\t\t\t\t\t\t\t>,\n\t\t\t\t\t\t\taudit: (result) =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => definition.audit({ command, result }, context)),\n\t\t\t\t\t\t\twriteAudit: (entry) =>\n\t\t\t\t\t\t\t\tnormalizeEffect(() => {\n\t\t\t\t\t\t\t\t\t// SAFETY: HostCompatible proves this invocation satisfies the configured writer host.\n\t\t\t\t\t\t\t\t\treturn configuration.writeAudit(host as never, entry)\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\taggregates: definition.aggregates,\n\t\t\t\t\t\t})\n\t\t\t\t\t\treturn lifecycle\n\t\t\t\t\t}),\n\t\t\t\t\tEffect.onExit((exit) =>\n\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\tif (Exit.isSuccess(exit)) observation.completed()\n\t\t\t\t\t\t\telse observation.failed(observationFailure(exit.cause))\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\t\t// SAFETY: dispatch selects exactly this operation; callbacks preserve the concrete definition/policy E/R.\n\t\treturn execution as Effect.Effect<\n\t\t\tEffectOperationResult<Operations[Key]>,\n\t\t\tErrorOf<Operations[Key], Resolve, Dependencies, Guard>,\n\t\t\tRequirementsOf<Operations[Key], Resolve, Dependencies, Guard>\n\t\t>\n\t}\n\treturn {\n\t\t/** Bind invocation context without resolving it or running an operation. */\n\t\twithContext(context: HostOf<Resolve>) {\n\t\t\treturn {\n\t\t\t\texec: <Key extends Extract<keyof Operations, string>>(\n\t\t\t\t\toperation: Key,\n\t\t\t\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\t\t\t) => exec(operation, input, context),\n\t\t\t}\n\t\t},\n\t\texpose<const Owner extends symbol, const Key extends Extract<keyof Operations, string>>(\n\t\t\towner: Owner,\n\t\t\toperation: Key,\n\t\t): SelectedOperation<\n\t\t\tOwner,\n\t\t\tKey,\n\t\t\tOperations[Key]['input'],\n\t\t\tOperationPublicResult<Operations[Key]>\n\t\t> {\n\t\t\tif (!Object.hasOwn(operations, operation))\n\t\t\t\tthrow Error('The selected command operation is not configured')\n\t\t\treturn selectOperation(owner, 'mutation', operation, operations[operation])\n\t\t},\n\t\texec,\n\t}\n}\n\n/** Bind trusted application policies without exposing a loose public command kernel. */\nexport function bindEffectCommand<const Dependencies extends EffectCommandDependencies>(\n\tdependencies: Dependencies,\n) {\n\ttype LooseRegistry<Context> = Readonly<\n\t\tRecord<\n\t\t\tstring,\n\t\t\tPick<Operation, 'input' | 'result' | 'classification' | 'handler'> &\n\t\t\t\tCheckedEffectOperation<Context>\n\t\t>\n\t>\n\n\tfunction command<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & {\n\t\t\tcommands: Readonly<Record<string, DomainCommandContract>>\n\t\t},\n\t\tconst Operations extends DomainEffectImplementations<\n\t\t\tDomainOf<Resolve>,\n\t\t\tContract['commands'],\n\t\t\ttrue\n\t\t>,\n\t\tMode extends true,\n\t\tGuard = never,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract &\n\t\t\t\tNoInfer<\n\t\t\t\t\tOperations extends ExactDomainOperations<Operations, Contract['commands']> &\n\t\t\t\t\t\tValidatedEffectOperations<Operations>\n\t\t\t\t\t\t? unknown\n\t\t\t\t\t\t: never\n\t\t\t\t>\n\t\t\tcontext: Resolve\n\t\t\taudit?: never\n\t\t\toperations: (\n\t\t\t\tdefine: DomainEffectFactory<\n\t\t\t\t\tDomainOf<Resolve>,\n\t\t\t\t\tContract['commands'],\n\t\t\t\t\tMode,\n\t\t\t\t\tnever,\n\t\t\t\t\tNoInfer<CallbackError<Guard>>,\n\t\t\t\t\tNoInfer<CallbackRequirements<Guard>>\n\t\t\t\t>,\n\t\t\t) => Operations\n\t\t\tdefaults?: { guard?: (context: DomainOf<Resolve>) => Guard }\n\t\t} & HostCompatible<Resolve, Dependencies>,\n\t): ReturnType<\n\t\ttypeof createEffectCommand<\n\t\t\tResolve,\n\t\t\tBoundOperations<Operations, Contract['commands']> & {\n\t\t\t\t[Key in keyof Contract['commands']]: {\n\t\t\t\t\tclassification: Contract['commands'][Key]['classification']\n\t\t\t\t\taudit: Operations[Key]['audit']\n\t\t\t\t}\n\t\t\t},\n\t\t\tDependencies,\n\t\t\tGuard\n\t\t>\n\t>\n\tfunction command<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & {\n\t\t\tcommands: Readonly<Record<string, DomainCommandContract>>\n\t\t},\n\t\tconst Operations extends DomainEffectImplementations<DomainOf<Resolve>, Contract['commands']>,\n\t\tReturned extends AuditValue,\n\t\tGuard = never,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract &\n\t\t\t\tNoInfer<\n\t\t\t\t\tOperations extends ExactDomainOperations<Operations, Contract['commands']> &\n\t\t\t\t\t\tValidatedEffectOperations<Operations>\n\t\t\t\t\t\t? unknown\n\t\t\t\t\t\t: never\n\t\t\t\t>\n\t\t\tcontext: Resolve\n\t\t\taudit: (\n\t\t\t\tresolution: DomainAuditInput<Contract['commands']>,\n\t\t\t\tcontext: DomainOf<Resolve>,\n\t\t\t) => Returned\n\t\t\toperations: (\n\t\t\t\tdefine: DomainEffectFactory<\n\t\t\t\t\tDomainOf<Resolve>,\n\t\t\t\t\tContract['commands'],\n\t\t\t\t\ttrue,\n\t\t\t\t\t[Returned] extends [never] ? never : (resolution: never, context: never) => Returned,\n\t\t\t\t\tNoInfer<CallbackError<Guard>>,\n\t\t\t\t\tNoInfer<CallbackRequirements<Guard>>\n\t\t\t\t>,\n\t\t\t) => Operations\n\t\t\tdefaults?: { guard?: (context: DomainOf<Resolve>) => Guard }\n\t\t} & HostCompatible<Resolve, Dependencies>,\n\t): ReturnType<\n\t\ttypeof createEffectCommand<\n\t\t\tResolve,\n\t\t\tAuditedOperations<\n\t\t\t\tBoundOperations<Operations, Contract['commands']>,\n\t\t\t\t(resolution: never, context: never) => Returned\n\t\t\t>,\n\t\t\tDependencies,\n\t\t\tGuard\n\t\t>\n\t>\n\tfunction command<\n\t\tResolve extends Resolver,\n\t\tconst Operations extends LooseRegistry<DomainOf<Resolve>>,\n\t\tReturned extends AuditValue,\n\t\tGuard,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontext: Resolve\n\t\t\taudit: (resolution: DomainAuditInput<Operations>, context: DomainOf<Resolve>) => Returned\n\t\t\toperations: (\n\t\t\t\tdefine: SharedEffectFactory<DomainOf<Resolve>, Guard>,\n\t\t\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\t\t\tdefaults?: { guard?: (context: DomainOf<Resolve>) => Guard }\n\t\t} & HostCompatible<Resolve, Dependencies>,\n\t): ReturnType<\n\t\ttypeof createEffectCommand<\n\t\t\tResolve,\n\t\t\tAuditedOperations<Operations, (resolution: never, context: never) => Returned>,\n\t\t\tDependencies,\n\t\t\tGuard\n\t\t>\n\t>\n\n\tfunction command<\n\t\tResolve extends Resolver,\n\t\tconst Operations extends Registry<DomainOf<Resolve>>,\n\t\tGuard = never,\n\t>(\n\t\tconfiguration: EffectCommandConfiguration<Resolve, Operations, Guard> &\n\t\t\tHostCompatible<Resolve, Dependencies>,\n\t): ReturnType<typeof createEffectCommand<Resolve, Operations, Dependencies, Guard>>\n\tfunction command(configuration: {\n\t\tcontext: Resolver\n\t\tcontract?: DomainContract\n\t\taudit?: (resolution: never, context: never) => AuditValue\n\t\toperations: (define: never) => Readonly<Record<string, object>>\n\t\tdefaults?: { guard?: (context: never) => unknown }\n\t}): unknown {\n\t\tconst definitions = configuration.contract\n\t\t\t? domainEffectFactory(configuration.contract.commands ?? {}, true)\n\t\t\t: effectOperationFactory()\n\t\tconst operations = snapshotOperations(\n\t\t\tconfiguration.operations(\n\t\t\t\t// SAFETY: the overload chooses this exact inline or contracted helper factory.\n\t\t\t\tdefinitions as never,\n\t\t\t),\n\t\t\tconfiguration.contract,\n\t\t\t'commands',\n\t\t\tconfiguration.audit,\n\t\t)\n\t\t// SAFETY: overloads check callbacks and schemas; binding validates exact keys and snapshots runtime records.\n\t\treturn createEffectCommand({\n\t\t\t...configuration,\n\t\t\t...dependencies,\n\t\t\toperations: () => operations,\n\t\t} as never)\n\t}\n\treturn command\n}\n\nfunction normalizeCommandResult<Value>(\n\tinvoke: () => Supported<Value>,\n): Effect.Effect<Value, unknown, unknown> {\n\t// SAFETY: selected definition helper checks the callback's normalized success against the schema input.\n\treturn normalizeEffect(invoke) as Effect.Effect<Value, unknown, unknown>\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ContractInput, ContractOutput, ContractSchema } from "../contracts/contract.mjs";
|
|
2
2
|
import { AuditEntryInput } from "../../components/foundation/client.mjs";
|
|
3
3
|
import { DomainOperationContract, ExactOperationKeys } from "../contracts/domain.mjs";
|
|
4
|
-
import { CallbackError, CallbackRequirements, CheckedEffectDefinition, EffectPreparation, OperationDefinition, effectOperationFactory } from "./operation.mjs";
|
|
4
|
+
import { CallbackError, CallbackRequirements, CheckedEffectDefinition, CheckedEffectOperation, EffectPreparation, OperationDefinition, effectOperationFactory } from "./operation.mjs";
|
|
5
|
+
import { DeclaredSchemas } from "../contracts/binding.mjs";
|
|
5
6
|
import { Effect } from "effect";
|
|
6
7
|
//#region src/modules/effect/domain.d.ts
|
|
7
8
|
type Supported<A> = A | PromiseLike<A> | Effect.Effect<A, unknown, unknown>;
|
|
@@ -35,8 +36,35 @@ type Helper<Context, Entry extends DomainOperationContract, Key, Command extends
|
|
|
35
36
|
audit?: never;
|
|
36
37
|
prepare?: never;
|
|
37
38
|
aggregates?: never;
|
|
38
|
-
})) => CheckedEffectDefinition<Context, Schemas<Entry> & Definition & BoundKey<Key>, BaseError, BaseRequirements>;
|
|
39
|
-
|
|
39
|
+
})) => DeclaredSchemas<Entry> & CheckedEffectDefinition<Context, Schemas<Entry> & Definition & BoundKey<Key>, BaseError, BaseRequirements>;
|
|
40
|
+
type HandlerArguments<Options, Command extends boolean, Default, RequiredAudit> = Command extends true ? [Default] extends [never] ? [options: Options & RequiredAudit] : [options?: Options] : [options?: Options];
|
|
41
|
+
type HandlerHelper<Context, Entries extends Readonly<Record<string, DomainOperationContract>>, Command extends boolean, Default, BaseError, BaseRequirements> = <const Input extends ContractSchema, const Result extends ContractSchema, Key extends keyof Entries, Handler extends Supported<ContractInput<Result>>, Guard extends Supported<void> = never, Preparation extends Supported<EffectPreparation<ContractOutput<Result>, unknown, unknown>> = never, const Aggregates extends readonly string[] = readonly string[], AuditReturned extends Supported<Audit> = never, Middleware extends Supported<ContractInput<Result>> = never, const Metadata extends object = Record<never, never>, const Definition extends object = object>(handler: (input: ContractOutput<Input>, context: Context) => Handler, ...options: HandlerArguments<Definition & Forbidden & {
|
|
42
|
+
handler?: never;
|
|
43
|
+
} & Omit<OperationDefinition<Context, Input, Result, Record<never, never>, Aggregates, Handler, Guard, Preparation, AuditReturned, Middleware, Metadata, BaseError, BaseRequirements, ContractSchema, never>, 'handler' | 'input' | 'result' | 'classification' | 'replayResult' | 'wire'> & (Command extends true ? {} : {
|
|
44
|
+
audit?: never;
|
|
45
|
+
prepare?: never;
|
|
46
|
+
aggregates?: never;
|
|
47
|
+
}), Command, Default, {
|
|
48
|
+
audit: AuditCallback<Context, {
|
|
49
|
+
input: Input;
|
|
50
|
+
result: Result;
|
|
51
|
+
}, AuditReturned>;
|
|
52
|
+
}>) => DeclaredSchemas<{
|
|
53
|
+
input: Input;
|
|
54
|
+
result: Result;
|
|
55
|
+
}> & {
|
|
56
|
+
handler: (input: ContractOutput<Input>, context: Context) => NoInfer<Handler>;
|
|
57
|
+
} & NoInfer<Definition> & BoundKey<Key> & CheckedEffectDefinition<Context, NoInfer<Definition> & {
|
|
58
|
+
handler: (input: ContractOutput<Input>, context: Context) => Handler;
|
|
59
|
+
} & BoundKey<Key>, BaseError, BaseRequirements>;
|
|
60
|
+
export type DomainEffectFactory<Context, Entries extends Readonly<Record<string, DomainOperationContract>>, Command extends boolean, Default = never, BaseError = never, BaseRequirements = never> = { [Kind in Command extends true ? 'command' : 'query']: { readonly [Key in keyof Entries]: Helper<Context, Entries[Key], Key, Command, Default, BaseError, BaseRequirements>; } & {
|
|
61
|
+
handler: HandlerHelper<Context, Entries, Command, Default, BaseError, BaseRequirements>;
|
|
62
|
+
}; };
|
|
63
|
+
export type DomainEffectImplementations<Context, Entries extends Readonly<Record<string, DomainOperationContract>>, Required extends boolean = false> = { [Key in keyof Entries]: DeclaredSchemas<Pick<Entries[Key], 'input' | 'result'>> & BoundKey<Key> & CheckedEffectOperation<Context> & {
|
|
64
|
+
handler: (input: ContractOutput<Entries[Key]['input']>, context: Context) => Supported<ContractInput<Entries[Key]['result']>>;
|
|
65
|
+
} & (Required extends true ? {
|
|
66
|
+
audit: AuditCallback<Context, Entries[Key], Supported<Audit>>;
|
|
67
|
+
} : {}); };
|
|
40
68
|
export declare function domainEffectFactory<Context, Entries extends Readonly<Record<string, DomainOperationContract>>, Command extends boolean, Default, Guard>(entries: Entries, command: Command): DomainEffectFactory<Context, Entries, Command, Default, CallbackError<Guard>, CallbackRequirements<Guard>>;
|
|
41
69
|
export type SharedEffectFactory<Context, Guard> = ReturnType<typeof effectOperationFactory<Context, Record<never, never>, NoInfer<CallbackError<Guard>>, NoInfer<CallbackRequirements<Guard>>, false>>;
|
|
42
70
|
export type AuditValue = Supported<Audit>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain.mjs","names":["domainEffectFactory","helpers","domainHelpers","entries","command"],"sources":["../../../src/modules/effect/domain.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-object-parameters -- Internal helper storage is heterogeneous; the exported mapped signatures validate the schema-paired implementation. */\nimport type { Effect } from 'effect'\nimport type { AuditEntryInput } from '../../components/foundation/client'\nimport type { ContractInput, ContractOutput, ContractSchema } from '../contracts/contract'\nimport type { DomainOperationContract, ExactOperationKeys } from '../contracts/domain'\nimport { domainHelpers } from '../contracts/binding'\nimport {\n\teffectOperationFactory,\n\ttype OperationDefinition,\n\ttype CheckedEffectDefinition,\n\ttype CallbackError,\n\ttype CallbackRequirements,\n\ttype EffectPreparation,\n} from './operation'\n\ntype Supported<A> = A | PromiseLike<A> | Effect.Effect<A, unknown, unknown>\ntype Audit = Omit<AuditEntryInput, 'classification'> | null\ndeclare const domainKey: unique symbol\ntype BoundKey<Key> = { readonly [domainKey]: Key }\ntype Schemas<Entry extends DomainOperationContract> = Pick<Entry, 'input' | 'result'> &\n\tOmit<Entry, 'input' | 'result'>\ntype Forbidden = {\n\tinput?: never\n\tresult?: never\n\tclassification?: never\n\treplayResult?: never\n\twire?: never\n}\ntype AuditCallback<Context, Entry extends DomainOperationContract, Value> = (\n\tresolution: { command: ContractOutput<Entry['input']>; result: ContractOutput<Entry['result']> },\n\tcontext: Context,\n) => Value\nexport type SelectedAudit<Definition, Default> = Definition extends { audit: infer Override }\n\t? Override\n\t: 'audit' extends keyof Definition\n\t\t? Exclude<Definition['audit' & keyof Definition], undefined> | Default\n\t\t: Default\nexport type AuditedOperations<Operations, Default> = {\n\t[Key in keyof Operations]: Omit<Operations[Key], 'audit'> & {\n\t\taudit: SelectedAudit<Operations[Key], Default>\n\t}\n}\nexport type ExactDomainOperations<Operations, Contracts> = ExactOperationKeys<\n\tOperations,\n\tContracts\n> & {\n\t[Key in keyof Operations]: Operations[Key] extends BoundKey<Key> ? Operations[Key] : never\n}\n\ntype Helper<\n\tContext,\n\tEntry extends DomainOperationContract,\n\tKey,\n\tCommand extends boolean,\n\tDefault,\n\tBaseError,\n\tBaseRequirements,\n> = <\n\tHandler extends Supported<ContractInput<Entry['result']>>,\n\tGuard extends Supported<void> = never,\n\tPreparation extends Supported<\n\t\tEffectPreparation<ContractOutput<Entry['result']>, unknown, unknown>\n\t> = never,\n\tconst Aggregates extends readonly string[] = readonly string[],\n\tAuditReturned extends Supported<Audit> = never,\n\tMiddleware extends Supported<ContractInput<Entry['result']>> = never,\n\tconst Metadata extends object = Record<never, never>,\n\tconst Definition extends object = object,\n>(\n\timplementation: Definition &\n\t\tForbidden &\n\t\tOmit<\n\t\t\tOperationDefinition<\n\t\t\t\tContext,\n\t\t\t\tEntry['input'],\n\t\t\t\tEntry['result'],\n\t\t\t\tRecord<never, never>,\n\t\t\t\tAggregates,\n\t\t\t\tHandler,\n\t\t\t\tGuard,\n\t\t\t\tPreparation,\n\t\t\t\tAuditReturned,\n\t\t\t\tMiddleware,\n\t\t\t\tMetadata,\n\t\t\t\tBaseError,\n\t\t\t\tBaseRequirements,\n\t\t\t\tContractSchema,\n\t\t\t\tnever\n\t\t\t>,\n\t\t\t'input' | 'result' | 'classification' | 'replayResult' | 'wire'\n\t\t> &\n\t\t(Command extends true\n\t\t\t? [Default] extends [never]\n\t\t\t\t? { audit: AuditCallback<Context, Entry, AuditReturned> }\n\t\t\t\t: {}\n\t\t\t: { audit?: never; prepare?: never; aggregates?: never }),\n) =>
|
|
1
|
+
{"version":3,"file":"domain.mjs","names":["domainEffectFactory","helpers","domainHelpers","entries","command"],"sources":["../../../src/modules/effect/domain.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-object-parameters -- Internal helper storage is heterogeneous; the exported mapped signatures validate the schema-paired implementation. */\nimport type { Effect } from 'effect'\nimport type { AuditEntryInput } from '../../components/foundation/client'\nimport type { ContractInput, ContractOutput, ContractSchema } from '../contracts/contract'\nimport type { DomainOperationContract, ExactOperationKeys } from '../contracts/domain'\nimport { domainHelpers, type DeclaredSchemas } from '../contracts/binding'\nimport {\n\teffectOperationFactory,\n\ttype OperationDefinition,\n\ttype CheckedEffectDefinition,\n\ttype CheckedEffectOperation,\n\ttype CallbackError,\n\ttype CallbackRequirements,\n\ttype EffectPreparation,\n} from './operation'\n\ntype Supported<A> = A | PromiseLike<A> | Effect.Effect<A, unknown, unknown>\ntype Audit = Omit<AuditEntryInput, 'classification'> | null\ndeclare const domainKey: unique symbol\ntype BoundKey<Key> = { readonly [domainKey]: Key }\ntype Schemas<Entry extends DomainOperationContract> = Pick<Entry, 'input' | 'result'> &\n\tOmit<Entry, 'input' | 'result'>\ntype Forbidden = {\n\tinput?: never\n\tresult?: never\n\tclassification?: never\n\treplayResult?: never\n\twire?: never\n}\ntype AuditCallback<Context, Entry extends DomainOperationContract, Value> = (\n\tresolution: { command: ContractOutput<Entry['input']>; result: ContractOutput<Entry['result']> },\n\tcontext: Context,\n) => Value\nexport type SelectedAudit<Definition, Default> = Definition extends { audit: infer Override }\n\t? Override\n\t: 'audit' extends keyof Definition\n\t\t? Exclude<Definition['audit' & keyof Definition], undefined> | Default\n\t\t: Default\nexport type AuditedOperations<Operations, Default> = {\n\t[Key in keyof Operations]: Omit<Operations[Key], 'audit'> & {\n\t\taudit: SelectedAudit<Operations[Key], Default>\n\t}\n}\nexport type ExactDomainOperations<Operations, Contracts> = ExactOperationKeys<\n\tOperations,\n\tContracts\n> & {\n\t[Key in keyof Operations]: Operations[Key] extends BoundKey<Key> ? Operations[Key] : never\n}\n\ntype Helper<\n\tContext,\n\tEntry extends DomainOperationContract,\n\tKey,\n\tCommand extends boolean,\n\tDefault,\n\tBaseError,\n\tBaseRequirements,\n> = <\n\tHandler extends Supported<ContractInput<Entry['result']>>,\n\tGuard extends Supported<void> = never,\n\tPreparation extends Supported<\n\t\tEffectPreparation<ContractOutput<Entry['result']>, unknown, unknown>\n\t> = never,\n\tconst Aggregates extends readonly string[] = readonly string[],\n\tAuditReturned extends Supported<Audit> = never,\n\tMiddleware extends Supported<ContractInput<Entry['result']>> = never,\n\tconst Metadata extends object = Record<never, never>,\n\tconst Definition extends object = object,\n>(\n\timplementation: Definition &\n\t\tForbidden &\n\t\tOmit<\n\t\t\tOperationDefinition<\n\t\t\t\tContext,\n\t\t\t\tEntry['input'],\n\t\t\t\tEntry['result'],\n\t\t\t\tRecord<never, never>,\n\t\t\t\tAggregates,\n\t\t\t\tHandler,\n\t\t\t\tGuard,\n\t\t\t\tPreparation,\n\t\t\t\tAuditReturned,\n\t\t\t\tMiddleware,\n\t\t\t\tMetadata,\n\t\t\t\tBaseError,\n\t\t\t\tBaseRequirements,\n\t\t\t\tContractSchema,\n\t\t\t\tnever\n\t\t\t>,\n\t\t\t'input' | 'result' | 'classification' | 'replayResult' | 'wire'\n\t\t> &\n\t\t(Command extends true\n\t\t\t? [Default] extends [never]\n\t\t\t\t? { audit: AuditCallback<Context, Entry, AuditReturned> }\n\t\t\t\t: {}\n\t\t\t: { audit?: never; prepare?: never; aggregates?: never }),\n) => DeclaredSchemas<Entry> &\n\tCheckedEffectDefinition<\n\t\tContext,\n\t\tSchemas<Entry> & Definition & BoundKey<Key>,\n\t\tBaseError,\n\t\tBaseRequirements\n\t>\n\ntype HandlerArguments<\n\tOptions,\n\tCommand extends boolean,\n\tDefault,\n\tRequiredAudit,\n> = Command extends true\n\t? [Default] extends [never]\n\t\t? [options: Options & RequiredAudit]\n\t\t: [options?: Options]\n\t: [options?: Options]\n\ntype HandlerHelper<\n\tContext,\n\tEntries extends Readonly<Record<string, DomainOperationContract>>,\n\tCommand extends boolean,\n\tDefault,\n\tBaseError,\n\tBaseRequirements,\n> = <\n\tconst Input extends ContractSchema,\n\tconst Result extends ContractSchema,\n\tKey extends keyof Entries,\n\tHandler extends Supported<ContractInput<Result>>,\n\tGuard extends Supported<void> = never,\n\tPreparation extends Supported<EffectPreparation<ContractOutput<Result>, unknown, unknown>> =\n\t\tnever,\n\tconst Aggregates extends readonly string[] = readonly string[],\n\tAuditReturned extends Supported<Audit> = never,\n\tMiddleware extends Supported<ContractInput<Result>> = never,\n\tconst Metadata extends object = Record<never, never>,\n\tconst Definition extends object = object,\n>(\n\thandler: (input: ContractOutput<Input>, context: Context) => Handler,\n\t...options: HandlerArguments<\n\t\tDefinition &\n\t\t\tForbidden & { handler?: never } & Omit<\n\t\t\t\tOperationDefinition<\n\t\t\t\t\tContext,\n\t\t\t\t\tInput,\n\t\t\t\t\tResult,\n\t\t\t\t\tRecord<never, never>,\n\t\t\t\t\tAggregates,\n\t\t\t\t\tHandler,\n\t\t\t\t\tGuard,\n\t\t\t\t\tPreparation,\n\t\t\t\t\tAuditReturned,\n\t\t\t\t\tMiddleware,\n\t\t\t\t\tMetadata,\n\t\t\t\t\tBaseError,\n\t\t\t\t\tBaseRequirements,\n\t\t\t\t\tContractSchema,\n\t\t\t\t\tnever\n\t\t\t\t>,\n\t\t\t\t'handler' | 'input' | 'result' | 'classification' | 'replayResult' | 'wire'\n\t\t\t> &\n\t\t\t(Command extends true ? {} : { audit?: never; prepare?: never; aggregates?: never }),\n\t\tCommand,\n\t\tDefault,\n\t\t{ audit: AuditCallback<Context, { input: Input; result: Result }, AuditReturned> }\n\t>\n) => DeclaredSchemas<{ input: Input; result: Result }> & {\n\thandler: (input: ContractOutput<Input>, context: Context) => NoInfer<Handler>\n} & NoInfer<Definition> &\n\tBoundKey<Key> &\n\tCheckedEffectDefinition<\n\t\tContext,\n\t\tNoInfer<Definition> & {\n\t\t\thandler: (input: ContractOutput<Input>, context: Context) => Handler\n\t\t} & BoundKey<Key>,\n\t\tBaseError,\n\t\tBaseRequirements\n\t>\n\nexport type DomainEffectFactory<\n\tContext,\n\tEntries extends Readonly<Record<string, DomainOperationContract>>,\n\tCommand extends boolean,\n\tDefault = never,\n\tBaseError = never,\n\tBaseRequirements = never,\n> = {\n\t[Kind in Command extends true ? 'command' : 'query']: {\n\t\treadonly [Key in keyof Entries]: Helper<\n\t\t\tContext,\n\t\t\tEntries[Key],\n\t\t\tKey,\n\t\t\tCommand,\n\t\t\tDefault,\n\t\t\tBaseError,\n\t\t\tBaseRequirements\n\t\t>\n\t} & { handler: HandlerHelper<Context, Entries, Command, Default, BaseError, BaseRequirements> }\n}\n\nexport type DomainEffectImplementations<\n\tContext,\n\tEntries extends Readonly<Record<string, DomainOperationContract>>,\n\tRequired extends boolean = false,\n> = {\n\t[Key in keyof Entries]: DeclaredSchemas<Pick<Entries[Key], 'input' | 'result'>> &\n\t\tBoundKey<Key> &\n\t\tCheckedEffectOperation<Context> & {\n\t\t\thandler: (\n\t\t\t\tinput: ContractOutput<Entries[Key]['input']>,\n\t\t\t\tcontext: Context,\n\t\t\t) => Supported<ContractInput<Entries[Key]['result']>>\n\t\t} & (Required extends true\n\t\t\t? { audit: AuditCallback<Context, Entries[Key], Supported<Audit>> }\n\t\t\t: {})\n}\n\nexport function domainEffectFactory<\n\tContext,\n\tEntries extends Readonly<Record<string, DomainOperationContract>>,\n\tCommand extends boolean,\n\tDefault,\n\tGuard,\n>(\n\tentries: Entries,\n\tcommand: Command,\n): DomainEffectFactory<\n\tContext,\n\tEntries,\n\tCommand,\n\tDefault,\n\tCallbackError<Guard>,\n\tCallbackRequirements<Guard>\n> {\n\tconst helpers = domainHelpers(entries)\n\t// SAFETY: helper signatures check callbacks; registration pairs drafts with their declarations.\n\treturn { [command ? 'command' : 'query']: helpers } as DomainEffectFactory<\n\t\tContext,\n\t\tEntries,\n\t\tCommand,\n\t\tDefault,\n\t\tCallbackError<Guard>,\n\t\tCallbackRequirements<Guard>\n\t>\n}\n\nexport type SharedEffectFactory<Context, Guard> = ReturnType<\n\ttypeof effectOperationFactory<\n\t\tContext,\n\t\tRecord<never, never>,\n\t\tNoInfer<CallbackError<Guard>>,\n\t\tNoInfer<CallbackRequirements<Guard>>,\n\t\tfalse\n\t>\n>\nexport type AuditValue = Supported<Audit>\n"],"mappings":"yDAwNA,SAAgBA,EAOf,EACA,EAQC,CACD,IAAMC,EAAUC,EAAcC,CAAO,EAErC,MAAO,EAAGC,EAAU,UAAY,SAAUH,CAAQ,CAQnD"}
|
|
@@ -3,7 +3,8 @@ import { OperationPublicResult, SelectedOperation } from "../contracts/exposure.
|
|
|
3
3
|
import { Observability, ObservabilityOptions } from "../../components/foundation/modules/observability/observability.mjs";
|
|
4
4
|
import { DomainContract, DomainQueryContract } from "../contracts/domain.mjs";
|
|
5
5
|
import { CallbackError, CallbackRequirements, CheckedEffectOperation, EffectOperationArgument, EffectOperationError, EffectOperationRequirements, EffectOperationResult, EffectValue, UnwrappedDefaultError, UnwrappedDefaultRequirements, ValidatedEffectOperations, effectOperationFactory } from "./operation.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { BoundOperations } from "../contracts/binding.mjs";
|
|
7
|
+
import { DomainEffectFactory, DomainEffectImplementations, ExactDomainOperations } from "./domain.mjs";
|
|
7
8
|
import { Effect } from "effect";
|
|
8
9
|
//#region src/modules/effect/query.d.ts
|
|
9
10
|
type Supported<Value> = Value | PromiseLike<Value> | Effect.Effect<Value, unknown, unknown>;
|
|
@@ -61,15 +62,15 @@ export type EffectQueryDependencies = {
|
|
|
61
62
|
export declare function bindEffectQuery<const Dependencies extends EffectQueryDependencies>(dependencies: Dependencies): {
|
|
62
63
|
<Host extends PolicyHost<Dependencies>, ContextReturned, const Contract extends DomainContract & {
|
|
63
64
|
queries: Readonly<Record<string, DomainQueryContract>>;
|
|
64
|
-
}, const Operations extends
|
|
65
|
-
contract: Contract
|
|
65
|
+
}, const Operations extends DomainEffectImplementations<EffectValue<ContextReturned>, Contract['queries']>, Mode extends false, GuardReturned extends Supported<void> = never>(configuration: {
|
|
66
|
+
contract: Contract & NoInfer<Operations extends ExactDomainOperations<Operations, Contract['queries']> & ValidatedEffectOperations<Operations> ? unknown : never>;
|
|
66
67
|
context: (host: Host) => ContextReturned;
|
|
67
|
-
operations: (define: DomainEffectFactory<EffectValue<ContextReturned>, Contract['queries'], Mode, never, NoInfer<CallbackError<GuardReturned>>, NoInfer<CallbackRequirements<GuardReturned>>>) => Operations
|
|
68
|
+
operations: (define: DomainEffectFactory<EffectValue<ContextReturned>, Contract['queries'], Mode, never, NoInfer<CallbackError<GuardReturned>>, NoInfer<CallbackRequirements<GuardReturned>>>) => Operations;
|
|
68
69
|
defaults?: {
|
|
69
70
|
metadata?: object;
|
|
70
71
|
guard?: (context: EffectValue<ContextReturned>) => GuardReturned;
|
|
71
72
|
};
|
|
72
|
-
}): ReturnType<typeof createEffectQuery<Host, ContextReturned, Operations, PolicyReturned<Dependencies>, GuardReturned>>;
|
|
73
|
+
}): ReturnType<typeof createEffectQuery<Host, ContextReturned, BoundOperations<Operations, Contract['queries']>, PolicyReturned<Dependencies>, GuardReturned>>;
|
|
73
74
|
<Host extends PolicyHost<Dependencies>, ContextReturned, const Operations extends QueryRegistry<EffectValue<ContextReturned>>, GuardReturned extends Supported<void> = never>(configuration: {
|
|
74
75
|
context: (host: Host) => ContextReturned;
|
|
75
76
|
operations: (definitions: ReturnType<typeof effectOperationFactory<EffectValue<ContextReturned>, Record<never, never>, NoInfer<CallbackError<GuardReturned>>, NoInfer<CallbackRequirements<GuardReturned>>>>) => Operations & NoInfer<ValidatedEffectOperations<Operations>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.mjs","names":["QueryMiddlewareError","QueryConfigurationError","QueryPermissionError","createEffectQuery","definitions","effectOperationFactory","operations","configuration","observability","Observability","exec","Effect","operation","definition","decodeEffectContract","input","observation","check","normalizeEffect","host","context","metadata","core","guard","current","parsedInput","usedNext","middleware","output","options","Exit","exit","observationFailure","expose","selectOperation","owner","bindEffectQuery","query","domainEffectFactory","snapshotOperations","dependencies"],"sources":["../../../src/modules/effect/query.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-returns, anti-slop/no-unsafe-dictionary-type -- Overload implementation storage is erased; public signatures retain concrete values, errors and services. */\nimport { Effect, Exit } from 'effect'\nimport type { ContractSchema } from '../contracts/contract'\nimport {\n\tselectOperation,\n\ttype SelectedOperation,\n\ttype OperationPublicResult,\n} from '../contracts/exposure'\nimport { decodeEffectContract } from './schema'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Internal optional adapter shares the Effect-free Foundation lifecycle and types without entering the Convex component deployment graph.\nimport {\n\tObservability,\n\ttype ObservabilityOptions,\n} from '../../components/foundation/modules/observability/observability'\nimport { normalizeEffect, observationFailure } from './normalize'\nimport {\n\teffectOperationFactory,\n\ttype CallbackError,\n\ttype CallbackRequirements,\n\ttype EffectOperationArgument,\n\ttype EffectOperationError,\n\ttype EffectOperationRequirements,\n\ttype EffectOperationResult,\n\ttype EffectValue,\n\ttype CheckedEffectOperation,\n\ttype UnwrappedDefaultError,\n\ttype UnwrappedDefaultRequirements,\n\ttype ValidatedEffectOperations,\n} from './operation'\n\nimport type { DomainContract, DomainQueryContract } from '../contracts/domain'\nimport { snapshotOperations } from '../contracts/binding'\nimport { domainEffectFactory, type DomainEffectFactory, type ExactDomainOperations } from './domain'\n\ntype Supported<Value> = Value | PromiseLike<Value> | Effect.Effect<Value, unknown, unknown>\ntype QueryDefinition = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal heterogeneous storage; selected schemas restore the concrete result at exec.\n\thandler: (input: never, context: never) => unknown\n\tclassification?: string\n\tpermission?: string\n\tmetadata?: object\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal hook storage retains the concrete definition separately.\n\tguard?: (context: never, input: never) => unknown\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal hook storage retains the concrete definition separately.\n\tmiddleware?: (input: never) => unknown\n}\ntype QueryRegistry<Context> = Readonly<\n\tRecord<\n\t\tstring,\n\t\tPick<QueryDefinition, 'input' | 'result' | 'handler'> &\n\t\t\tCheckedEffectOperation<Context> & {\n\t\t\t\tprepare?: never\n\t\t\t\taudit?: never\n\t\t\t\taggregates?: never\n\t\t\t\treplayResult?: never\n\t\t\t}\n\t>\n>\ntype OperationKey<Operations> = Extract<keyof Operations, string>\n\nclass QueryMiddlewareError extends Error {\n\treadonly code = 'QUERY_MIDDLEWARE_NEXT_REUSED'\n\treadonly name = 'QueryMiddlewareError'\n\tconstructor() {\n\t\tsuper('A query middleware called next() more than once')\n\t}\n}\nclass QueryConfigurationError extends Error {\n\treadonly code = 'QUERY_OPERATION_NOT_CONFIGURED'\n\treadonly name = 'QueryConfigurationError'\n\tconstructor() {\n\t\tsuper('The selected query operation is not configured')\n\t}\n}\nclass QueryPermissionError extends Error {\n\treadonly code = 'QUERY_PERMISSION_CHECKER_MISSING'\n\treadonly name = 'QueryPermissionError'\n\tconstructor() {\n\t\tsuper('Query permission requires an injected permission checker')\n\t}\n}\n\n/** Injectable domain queries compose lazily; the API chooses native function kind. */\nexport function createEffectQuery<\n\tHost,\n\tContextReturned,\n\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\tPermissionReturned = never,\n\tGuardReturned extends Supported<void> = never,\n>(configuration: {\n\tcontext: (host: Host) => ContextReturned\n\toperations: (\n\t\tdefinitions: ReturnType<\n\t\t\ttypeof effectOperationFactory<\n\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\tRecord<never, never>,\n\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t>\n\t\t>,\n\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\tcheckPermission?: (\n\t\thost: Host,\n\t\tinput: { permission: string; operation: string },\n\t) => PermissionReturned\n\tdefaults?: { metadata?: object; guard?: (context: EffectValue<ContextReturned>) => GuardReturned }\n\tobservability?: ObservabilityOptions | Observability\n}) {\n\tconst definitions = effectOperationFactory<\n\t\tEffectValue<ContextReturned>,\n\t\tRecord<never, never>,\n\t\tCallbackError<GuardReturned>,\n\t\tCallbackRequirements<GuardReturned>\n\t>()\n\tconst operations: Operations = configuration.operations(definitions)\n\tconst observability =\n\t\tconfiguration.observability instanceof Observability\n\t\t\t? configuration.observability\n\t\t\t: new Observability(\n\t\t\t\t\tconfiguration.observability ?? {\n\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t\tclassifyError: () => ({ outcome: 'failed', errorCode: 'UNEXPECTED' }),\n\t\t\t\t\t},\n\t\t\t\t)\n\n\tfunction exec<const Key extends OperationKey<Operations>>(\n\t\toperation: Key,\n\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\thost: Host,\n\t): Effect.Effect<\n\t\tEffectOperationResult<Operations[Key]>,\n\t\t| EffectOperationError<Operations[Key]>\n\t\t| CallbackError<ContextReturned | PermissionReturned>\n\t\t| UnwrappedDefaultError<Operations[Key], GuardReturned>,\n\t\t| EffectOperationRequirements<Operations[Key]>\n\t\t| CallbackRequirements<ContextReturned | PermissionReturned>\n\t\t| UnwrappedDefaultRequirements<Operations[Key], GuardReturned>\n\t> {\n\t\tconst execution = Effect.suspend(() => {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(operations, operation)) {\n\t\t\t\treturn Effect.die(new QueryConfigurationError())\n\t\t\t}\n\t\t\t// SAFETY: operation helpers check hooks before this heterogeneous storage seam.\n\t\t\tconst definition: QueryDefinition = operations[operation]\n\t\t\treturn Effect.flatMap(decodeEffectContract(definition.input, input), (parsedInput) => {\n\t\t\t\tconst observation = observability.start({\n\t\t\t\t\toperation,\n\t\t\t\t\tclassification: definition.classification ?? 'query',\n\t\t\t\t})\n\t\t\t\tconst run = Effect.gen(function* () {\n\t\t\t\t\tif (definition.permission !== undefined) {\n\t\t\t\t\t\tconst check = configuration.checkPermission\n\t\t\t\t\t\tif (!check) return yield* Effect.die(new QueryPermissionError())\n\t\t\t\t\t\tyield* normalizeEffect(() =>\n\t\t\t\t\t\t\tcheck(host, { permission: definition.permission!, operation }),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tconst context = yield* normalizeEffect(() => configuration.context(host))\n\t\t\t\t\tconst metadata = { ...configuration.defaults?.metadata, ...definition.metadata }\n\t\t\t\t\tconst core = (current: EffectValue<ContextReturned>) =>\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tconst guard = configuration.defaults?.guard\n\t\t\t\t\t\t\tif (guard) yield* normalizeEffect(() => guard(current))\n\t\t\t\t\t\t\tif (definition.guard)\n\t\t\t\t\t\t\t\tyield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t\t// SAFETY: selected schemas and context own the stored guard parameters.\n\t\t\t\t\t\t\t\t\treturn definition.guard!(current as never, parsedInput as never)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\treturn yield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t// SAFETY: selected schemas and context own the stored handler parameters.\n\t\t\t\t\t\t\t\treturn definition.handler(parsedInput as never, current as never)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\tlet usedNext = false\n\t\t\t\t\tconst middleware = definition.middleware\n\t\t\t\t\tconst output = middleware\n\t\t\t\t\t\t? yield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t// SAFETY: the selected helper checked this middleware's input and next contract.\n\t\t\t\t\t\t\t\treturn middleware({\n\t\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\t\tinput: parsedInput,\n\t\t\t\t\t\t\t\t\tcommand: parsedInput,\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tmetadata,\n\t\t\t\t\t\t\t\t\tnext: (options?: { context?: object }) =>\n\t\t\t\t\t\t\t\t\t\tEffect.suspend(() => {\n\t\t\t\t\t\t\t\t\t\t\tif (usedNext) return Effect.die(new QueryMiddlewareError())\n\t\t\t\t\t\t\t\t\t\t\tusedNext = true\n\t\t\t\t\t\t\t\t\t\t\treturn core(\n\t\t\t\t\t\t\t\t\t\t\t\toptions?.context ? Object.assign({}, context, options.context) : context,\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as never)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: yield* core(context)\n\t\t\t\t\treturn yield* decodeEffectContract(definition.result, output)\n\t\t\t\t})\n\t\t\t\treturn run.pipe(\n\t\t\t\t\tEffect.onExit((exit) =>\n\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\tif (Exit.isSuccess(exit)) observation.completed()\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tobservation.failed(observationFailure(exit.cause))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\t\t// SAFETY: selected schemas own A; concrete callbacks and the wrapped middleware\n\t\t// own E/R. No interpreter or runner executes this Effect before the caller does.\n\t\treturn execution as ReturnType<typeof exec<Key>>\n\t}\n\tfunction expose<const Owner extends symbol, const Key extends OperationKey<Operations>>(\n\t\towner: Owner,\n\t\toperation: Key,\n\t): SelectedOperation<\n\t\tOwner,\n\t\tKey,\n\t\tOperations[Key]['input'],\n\t\tOperationPublicResult<Operations[Key]>\n\t> {\n\t\tif (!Object.hasOwn(operations, operation)) throw new QueryConfigurationError()\n\t\treturn selectOperation(owner, 'query', operation, operations[operation])\n\t}\n\treturn {\n\t\texec,\n\t\texpose,\n\t\t/** Bind invocation context without resolving it or running an operation. */\n\t\twithContext(context: Host) {\n\t\t\treturn {\n\t\t\t\texec: <const Key extends OperationKey<Operations>>(\n\t\t\t\t\toperation: Key,\n\t\t\t\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\t\t\t) => exec(operation, input, context),\n\t\t\t}\n\t\t},\n\t}\n}\n\ntype Policy<Dependencies> = 'checkPermission' extends keyof Dependencies\n\t? Dependencies['checkPermission']\n\t: never\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- Conditional type extracts the host; no unknown result is exposed by the registry.\ntype CallbackHost<Callback> = Callback extends (host: infer Host, input: never) => unknown\n\t? Host\n\t: never\ntype CallbackReturned<Callback> = Callback extends (...arguments_: never[]) => infer Returned\n\t? Returned\n\t: never\ntype PolicyHost<Dependencies> = [CallbackHost<Policy<Dependencies>>] extends [never]\n\t? unknown\n\t: CallbackHost<Policy<Dependencies>>\ntype PolicyReturned<Dependencies> = CallbackReturned<Policy<Dependencies>>\nexport type EffectQueryDependencies = {\n\tobservability: Observability\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Host policy storage is erased; the bound generic dependency retains its concrete E/R.\n\tcheckPermission?: (host: never, input: { permission: string; operation: string }) => unknown\n}\n\n/** The public Foundation binds trusted application policies once. */\nexport function bindEffectQuery<const Dependencies extends EffectQueryDependencies>(\n\tdependencies: Dependencies,\n) {\n\tfunction query<\n\t\tHost extends PolicyHost<Dependencies>,\n\t\tContextReturned,\n\t\tconst Contract extends DomainContract & {\n\t\t\tqueries: Readonly<Record<string, DomainQueryContract>>\n\t\t},\n\t\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\t\tMode extends false,\n\t\tGuardReturned extends Supported<void> = never,\n\t>(configuration: {\n\t\tcontract: Contract\n\t\tcontext: (host: Host) => ContextReturned\n\t\toperations: (\n\t\t\tdefine: DomainEffectFactory<\n\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\tContract['queries'],\n\t\t\t\tMode,\n\t\t\t\tnever,\n\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t>,\n\t\t) => Operations &\n\t\t\tNoInfer<ExactDomainOperations<Operations, Contract['queries']>> &\n\t\t\tNoInfer<ValidatedEffectOperations<Operations>>\n\t\tdefaults?: {\n\t\t\tmetadata?: object\n\t\t\tguard?: (context: EffectValue<ContextReturned>) => GuardReturned\n\t\t}\n\t}): ReturnType<\n\t\ttypeof createEffectQuery<\n\t\t\tHost,\n\t\t\tContextReturned,\n\t\t\tOperations,\n\t\t\tPolicyReturned<Dependencies>,\n\t\t\tGuardReturned\n\t\t>\n\t>\n\n\tfunction query<\n\t\tHost extends PolicyHost<Dependencies>,\n\t\tContextReturned,\n\t\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\t\tGuardReturned extends Supported<void> = never,\n\t>(configuration: {\n\t\tcontext: (host: Host) => ContextReturned\n\t\toperations: (\n\t\t\tdefinitions: ReturnType<\n\t\t\t\ttypeof effectOperationFactory<\n\t\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\t\tRecord<never, never>,\n\t\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t\t>\n\t\t\t>,\n\t\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\t\tdefaults?: {\n\t\t\tmetadata?: object\n\t\t\tguard?: (context: EffectValue<ContextReturned>) => GuardReturned\n\t\t}\n\t}): ReturnType<\n\t\ttypeof createEffectQuery<\n\t\t\tHost,\n\t\t\tContextReturned,\n\t\t\tOperations,\n\t\t\tPolicyReturned<Dependencies>,\n\t\t\tGuardReturned\n\t\t>\n\t>\n\n\tfunction query(configuration: {\n\t\tcontext: (host: never) => unknown\n\t\tcontract?: DomainContract\n\t\toperations: (define: never) => Readonly<Record<string, object>>\n\t\tdefaults?: { metadata?: object; guard?: (context: never) => Supported<void> }\n\t}): unknown {\n\t\tconst definitions = configuration.contract\n\t\t\t? domainEffectFactory(configuration.contract.queries ?? {}, false)\n\t\t\t: effectOperationFactory()\n\t\tconst operations = snapshotOperations(\n\t\t\tconfiguration.operations(\n\t\t\t\t// SAFETY: the overload chooses this exact inline or contracted helper factory.\n\t\t\t\tdefinitions as never,\n\t\t\t),\n\t\t\tconfiguration.contract,\n\t\t\t'queries',\n\t\t)\n\t\t// SAFETY: the overload verifies callback types; exact binding ownership is verified before execution.\n\t\treturn createEffectQuery({\n\t\t\t...configuration,\n\t\t\t...dependencies,\n\t\t\toperations: () => operations,\n\t\t} as never)\n\t}\n\treturn query\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"query.mjs","names":["QueryMiddlewareError","QueryConfigurationError","QueryPermissionError","createEffectQuery","definitions","effectOperationFactory","operations","configuration","observability","Observability","exec","Effect","operation","definition","decodeEffectContract","input","observation","check","normalizeEffect","host","context","metadata","core","guard","current","parsedInput","usedNext","middleware","output","options","Exit","exit","observationFailure","expose","selectOperation","owner","bindEffectQuery","query","domainEffectFactory","snapshotOperations","dependencies"],"sources":["../../../src/modules/effect/query.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-returns, anti-slop/no-unsafe-dictionary-type -- Overload implementation storage is erased; public signatures retain concrete values, errors and services. */\nimport { Effect, Exit } from 'effect'\nimport type { ContractSchema } from '../contracts/contract'\nimport {\n\tselectOperation,\n\ttype SelectedOperation,\n\ttype OperationPublicResult,\n} from '../contracts/exposure'\nimport { decodeEffectContract } from './schema'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Internal optional adapter shares the Effect-free Foundation lifecycle and types without entering the Convex component deployment graph.\nimport {\n\tObservability,\n\ttype ObservabilityOptions,\n} from '../../components/foundation/modules/observability/observability'\nimport { normalizeEffect, observationFailure } from './normalize'\nimport {\n\teffectOperationFactory,\n\ttype CallbackError,\n\ttype CallbackRequirements,\n\ttype EffectOperationArgument,\n\ttype EffectOperationError,\n\ttype EffectOperationRequirements,\n\ttype EffectOperationResult,\n\ttype EffectValue,\n\ttype CheckedEffectOperation,\n\ttype UnwrappedDefaultError,\n\ttype UnwrappedDefaultRequirements,\n\ttype ValidatedEffectOperations,\n} from './operation'\n\nimport type { DomainContract, DomainQueryContract } from '../contracts/domain'\nimport { snapshotOperations, type BoundOperations } from '../contracts/binding'\nimport {\n\tdomainEffectFactory,\n\ttype DomainEffectFactory,\n\ttype DomainEffectImplementations,\n\ttype ExactDomainOperations,\n} from './domain'\n\ntype Supported<Value> = Value | PromiseLike<Value> | Effect.Effect<Value, unknown, unknown>\ntype QueryDefinition = {\n\tinput: ContractSchema\n\tresult: ContractSchema\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal heterogeneous storage; selected schemas restore the concrete result at exec.\n\thandler: (input: never, context: never) => unknown\n\tclassification?: string\n\tpermission?: string\n\tmetadata?: object\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal hook storage retains the concrete definition separately.\n\tguard?: (context: never, input: never) => unknown\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Internal hook storage retains the concrete definition separately.\n\tmiddleware?: (input: never) => unknown\n}\ntype QueryRegistry<Context> = Readonly<\n\tRecord<\n\t\tstring,\n\t\tPick<QueryDefinition, 'input' | 'result' | 'handler'> &\n\t\t\tCheckedEffectOperation<Context> & {\n\t\t\t\tprepare?: never\n\t\t\t\taudit?: never\n\t\t\t\taggregates?: never\n\t\t\t\treplayResult?: never\n\t\t\t}\n\t>\n>\ntype OperationKey<Operations> = Extract<keyof Operations, string>\n\nclass QueryMiddlewareError extends Error {\n\treadonly code = 'QUERY_MIDDLEWARE_NEXT_REUSED'\n\treadonly name = 'QueryMiddlewareError'\n\tconstructor() {\n\t\tsuper('A query middleware called next() more than once')\n\t}\n}\nclass QueryConfigurationError extends Error {\n\treadonly code = 'QUERY_OPERATION_NOT_CONFIGURED'\n\treadonly name = 'QueryConfigurationError'\n\tconstructor() {\n\t\tsuper('The selected query operation is not configured')\n\t}\n}\nclass QueryPermissionError extends Error {\n\treadonly code = 'QUERY_PERMISSION_CHECKER_MISSING'\n\treadonly name = 'QueryPermissionError'\n\tconstructor() {\n\t\tsuper('Query permission requires an injected permission checker')\n\t}\n}\n\n/** Injectable domain queries compose lazily; the API chooses native function kind. */\nexport function createEffectQuery<\n\tHost,\n\tContextReturned,\n\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\tPermissionReturned = never,\n\tGuardReturned extends Supported<void> = never,\n>(configuration: {\n\tcontext: (host: Host) => ContextReturned\n\toperations: (\n\t\tdefinitions: ReturnType<\n\t\t\ttypeof effectOperationFactory<\n\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\tRecord<never, never>,\n\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t>\n\t\t>,\n\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\tcheckPermission?: (\n\t\thost: Host,\n\t\tinput: { permission: string; operation: string },\n\t) => PermissionReturned\n\tdefaults?: { metadata?: object; guard?: (context: EffectValue<ContextReturned>) => GuardReturned }\n\tobservability?: ObservabilityOptions | Observability\n}) {\n\tconst definitions = effectOperationFactory<\n\t\tEffectValue<ContextReturned>,\n\t\tRecord<never, never>,\n\t\tCallbackError<GuardReturned>,\n\t\tCallbackRequirements<GuardReturned>\n\t>()\n\tconst operations: Operations = configuration.operations(definitions)\n\tconst observability =\n\t\tconfiguration.observability instanceof Observability\n\t\t\t? configuration.observability\n\t\t\t: new Observability(\n\t\t\t\t\tconfiguration.observability ?? {\n\t\t\t\t\t\tenabled: false,\n\t\t\t\t\t\tclassifyError: () => ({ outcome: 'failed', errorCode: 'UNEXPECTED' }),\n\t\t\t\t\t},\n\t\t\t\t)\n\n\tfunction exec<const Key extends OperationKey<Operations>>(\n\t\toperation: Key,\n\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\thost: Host,\n\t): Effect.Effect<\n\t\tEffectOperationResult<Operations[Key]>,\n\t\t| EffectOperationError<Operations[Key]>\n\t\t| CallbackError<ContextReturned | PermissionReturned>\n\t\t| UnwrappedDefaultError<Operations[Key], GuardReturned>,\n\t\t| EffectOperationRequirements<Operations[Key]>\n\t\t| CallbackRequirements<ContextReturned | PermissionReturned>\n\t\t| UnwrappedDefaultRequirements<Operations[Key], GuardReturned>\n\t> {\n\t\tconst execution = Effect.suspend(() => {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(operations, operation)) {\n\t\t\t\treturn Effect.die(new QueryConfigurationError())\n\t\t\t}\n\t\t\t// SAFETY: operation helpers check hooks before this heterogeneous storage seam.\n\t\t\tconst definition: QueryDefinition = operations[operation]\n\t\t\treturn Effect.flatMap(decodeEffectContract(definition.input, input), (parsedInput) => {\n\t\t\t\tconst observation = observability.start({\n\t\t\t\t\toperation,\n\t\t\t\t\tclassification: definition.classification ?? 'query',\n\t\t\t\t})\n\t\t\t\tconst run = Effect.gen(function* () {\n\t\t\t\t\tif (definition.permission !== undefined) {\n\t\t\t\t\t\tconst check = configuration.checkPermission\n\t\t\t\t\t\tif (!check) return yield* Effect.die(new QueryPermissionError())\n\t\t\t\t\t\tyield* normalizeEffect(() =>\n\t\t\t\t\t\t\tcheck(host, { permission: definition.permission!, operation }),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tconst context = yield* normalizeEffect(() => configuration.context(host))\n\t\t\t\t\tconst metadata = { ...configuration.defaults?.metadata, ...definition.metadata }\n\t\t\t\t\tconst core = (current: EffectValue<ContextReturned>) =>\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tconst guard = configuration.defaults?.guard\n\t\t\t\t\t\t\tif (guard) yield* normalizeEffect(() => guard(current))\n\t\t\t\t\t\t\tif (definition.guard)\n\t\t\t\t\t\t\t\tyield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t\t// SAFETY: selected schemas and context own the stored guard parameters.\n\t\t\t\t\t\t\t\t\treturn definition.guard!(current as never, parsedInput as never)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\treturn yield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t// SAFETY: selected schemas and context own the stored handler parameters.\n\t\t\t\t\t\t\t\treturn definition.handler(parsedInput as never, current as never)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\tlet usedNext = false\n\t\t\t\t\tconst middleware = definition.middleware\n\t\t\t\t\tconst output = middleware\n\t\t\t\t\t\t? yield* normalizeEffect(() => {\n\t\t\t\t\t\t\t\t// SAFETY: the selected helper checked this middleware's input and next contract.\n\t\t\t\t\t\t\t\treturn middleware({\n\t\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\t\tinput: parsedInput,\n\t\t\t\t\t\t\t\t\tcommand: parsedInput,\n\t\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t\tmetadata,\n\t\t\t\t\t\t\t\t\tnext: (options?: { context?: object }) =>\n\t\t\t\t\t\t\t\t\t\tEffect.suspend(() => {\n\t\t\t\t\t\t\t\t\t\t\tif (usedNext) return Effect.die(new QueryMiddlewareError())\n\t\t\t\t\t\t\t\t\t\t\tusedNext = true\n\t\t\t\t\t\t\t\t\t\t\treturn core(\n\t\t\t\t\t\t\t\t\t\t\t\toptions?.context ? Object.assign({}, context, options.context) : context,\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t} as never)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: yield* core(context)\n\t\t\t\t\treturn yield* decodeEffectContract(definition.result, output)\n\t\t\t\t})\n\t\t\t\treturn run.pipe(\n\t\t\t\t\tEffect.onExit((exit) =>\n\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\tif (Exit.isSuccess(exit)) observation.completed()\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tobservation.failed(observationFailure(exit.cause))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\t\t// SAFETY: selected schemas own A; concrete callbacks and the wrapped middleware\n\t\t// own E/R. No interpreter or runner executes this Effect before the caller does.\n\t\treturn execution as ReturnType<typeof exec<Key>>\n\t}\n\tfunction expose<const Owner extends symbol, const Key extends OperationKey<Operations>>(\n\t\towner: Owner,\n\t\toperation: Key,\n\t): SelectedOperation<\n\t\tOwner,\n\t\tKey,\n\t\tOperations[Key]['input'],\n\t\tOperationPublicResult<Operations[Key]>\n\t> {\n\t\tif (!Object.hasOwn(operations, operation)) throw new QueryConfigurationError()\n\t\treturn selectOperation(owner, 'query', operation, operations[operation])\n\t}\n\treturn {\n\t\texec,\n\t\texpose,\n\t\t/** Bind invocation context without resolving it or running an operation. */\n\t\twithContext(context: Host) {\n\t\t\treturn {\n\t\t\t\texec: <const Key extends OperationKey<Operations>>(\n\t\t\t\t\toperation: Key,\n\t\t\t\t\tinput: EffectOperationArgument<Operations[Key]>,\n\t\t\t\t) => exec(operation, input, context),\n\t\t\t}\n\t\t},\n\t}\n}\n\ntype Policy<Dependencies> = 'checkPermission' extends keyof Dependencies\n\t? Dependencies['checkPermission']\n\t: never\n// oxlint-disable-next-line anti-slop/no-unknown-returns -- Conditional type extracts the host; no unknown result is exposed by the registry.\ntype CallbackHost<Callback> = Callback extends (host: infer Host, input: never) => unknown\n\t? Host\n\t: never\ntype CallbackReturned<Callback> = Callback extends (...arguments_: never[]) => infer Returned\n\t? Returned\n\t: never\ntype PolicyHost<Dependencies> = [CallbackHost<Policy<Dependencies>>] extends [never]\n\t? unknown\n\t: CallbackHost<Policy<Dependencies>>\ntype PolicyReturned<Dependencies> = CallbackReturned<Policy<Dependencies>>\nexport type EffectQueryDependencies = {\n\tobservability: Observability\n\t// oxlint-disable-next-line anti-slop/no-unknown-returns -- Host policy storage is erased; the bound generic dependency retains its concrete E/R.\n\tcheckPermission?: (host: never, input: { permission: string; operation: string }) => unknown\n}\n\n/** The public Foundation binds trusted application policies once. */\nexport function bindEffectQuery<const Dependencies extends EffectQueryDependencies>(\n\tdependencies: Dependencies,\n) {\n\tfunction query<\n\t\tHost extends PolicyHost<Dependencies>,\n\t\tContextReturned,\n\t\tconst Contract extends DomainContract & {\n\t\t\tqueries: Readonly<Record<string, DomainQueryContract>>\n\t\t},\n\t\tconst Operations extends DomainEffectImplementations<\n\t\t\tEffectValue<ContextReturned>,\n\t\t\tContract['queries']\n\t\t>,\n\t\tMode extends false,\n\t\tGuardReturned extends Supported<void> = never,\n\t>(configuration: {\n\t\tcontract: Contract &\n\t\t\tNoInfer<\n\t\t\t\tOperations extends ExactDomainOperations<Operations, Contract['queries']> &\n\t\t\t\t\tValidatedEffectOperations<Operations>\n\t\t\t\t\t? unknown\n\t\t\t\t\t: never\n\t\t\t>\n\t\tcontext: (host: Host) => ContextReturned\n\t\toperations: (\n\t\t\tdefine: DomainEffectFactory<\n\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\tContract['queries'],\n\t\t\t\tMode,\n\t\t\t\tnever,\n\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t>,\n\t\t) => Operations\n\t\tdefaults?: {\n\t\t\tmetadata?: object\n\t\t\tguard?: (context: EffectValue<ContextReturned>) => GuardReturned\n\t\t}\n\t}): ReturnType<\n\t\ttypeof createEffectQuery<\n\t\t\tHost,\n\t\t\tContextReturned,\n\t\t\tBoundOperations<Operations, Contract['queries']>,\n\t\t\tPolicyReturned<Dependencies>,\n\t\t\tGuardReturned\n\t\t>\n\t>\n\n\tfunction query<\n\t\tHost extends PolicyHost<Dependencies>,\n\t\tContextReturned,\n\t\tconst Operations extends QueryRegistry<EffectValue<ContextReturned>>,\n\t\tGuardReturned extends Supported<void> = never,\n\t>(configuration: {\n\t\tcontext: (host: Host) => ContextReturned\n\t\toperations: (\n\t\t\tdefinitions: ReturnType<\n\t\t\t\ttypeof effectOperationFactory<\n\t\t\t\t\tEffectValue<ContextReturned>,\n\t\t\t\t\tRecord<never, never>,\n\t\t\t\t\tNoInfer<CallbackError<GuardReturned>>,\n\t\t\t\t\tNoInfer<CallbackRequirements<GuardReturned>>\n\t\t\t\t>\n\t\t\t>,\n\t\t) => Operations & NoInfer<ValidatedEffectOperations<Operations>>\n\t\tdefaults?: {\n\t\t\tmetadata?: object\n\t\t\tguard?: (context: EffectValue<ContextReturned>) => GuardReturned\n\t\t}\n\t}): ReturnType<\n\t\ttypeof createEffectQuery<\n\t\t\tHost,\n\t\t\tContextReturned,\n\t\t\tOperations,\n\t\t\tPolicyReturned<Dependencies>,\n\t\t\tGuardReturned\n\t\t>\n\t>\n\n\tfunction query(configuration: {\n\t\tcontext: (host: never) => unknown\n\t\tcontract?: DomainContract\n\t\toperations: (define: never) => Readonly<Record<string, object>>\n\t\tdefaults?: { metadata?: object; guard?: (context: never) => Supported<void> }\n\t}): unknown {\n\t\tconst definitions = configuration.contract\n\t\t\t? domainEffectFactory(configuration.contract.queries ?? {}, false)\n\t\t\t: effectOperationFactory()\n\t\tconst operations = snapshotOperations(\n\t\t\tconfiguration.operations(\n\t\t\t\t// SAFETY: the overload chooses this exact inline or contracted helper factory.\n\t\t\t\tdefinitions as never,\n\t\t\t),\n\t\t\tconfiguration.contract,\n\t\t\t'queries',\n\t\t)\n\t\t// SAFETY: the overload verifies callback types; exact binding ownership is verified before execution.\n\t\treturn createEffectQuery({\n\t\t\t...configuration,\n\t\t\t...dependencies,\n\t\t\toperations: () => operations,\n\t\t} as never)\n\t}\n\treturn query\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,8 @@ import { OperationPublicResult, SelectedOperation } from "../contracts/exposure.
|
|
|
3
3
|
import { Observability, ObservabilityOptions } from "../../components/foundation/modules/observability/observability.mjs";
|
|
4
4
|
import { AuditEntryInput } from "../../components/foundation/client.mjs";
|
|
5
5
|
import { DomainAuditInput, DomainContract } from "../contracts/domain.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { BoundOperations } from "../contracts/binding.mjs";
|
|
7
|
+
import { Audit, CheckedOperation, DomainFactory, DomainImplementations, ExactOperations, InlineFactory, NormalEntry, ValidatedOperations } from "./operation.mjs";
|
|
7
8
|
//#region src/modules/foundation/foundation.d.ts
|
|
8
9
|
type Supported<Value> = Value | PromiseLike<Value>;
|
|
9
10
|
type Resolver = (host: never) => unknown;
|
|
@@ -42,28 +43,28 @@ export declare function createFoundation<const Options extends FoundationRegistr
|
|
|
42
43
|
commands: Readonly<Record<string, NormalEntry & {
|
|
43
44
|
classification: string;
|
|
44
45
|
}>>;
|
|
45
|
-
}, const Operations extends
|
|
46
|
-
contract: Contract
|
|
46
|
+
}, const Operations extends DomainImplementations<Domain<Resolve>, Contract['commands'], true, false>>(configuration: {
|
|
47
|
+
contract: Contract & NoInfer<Operations extends ExactOperations<Operations, Contract['commands']> & ValidatedOperations<Operations> ? unknown : never>;
|
|
47
48
|
context: Resolve;
|
|
48
49
|
audit: (resolution: DomainAuditInput<Contract['commands']>, context: Domain<Resolve>) => Supported<Audit>;
|
|
49
|
-
operations: (definitions: DomainFactory<Domain<Resolve>, Contract['commands'], true, false>) => Operations
|
|
50
|
+
operations: (definitions: DomainFactory<Domain<Resolve>, Contract['commands'], true, false>) => Operations;
|
|
50
51
|
defaults?: Defaults<Domain<Resolve>>;
|
|
51
52
|
} & (Host<Resolve> extends CallbackHost<Options["writeAudit"]> & CallbackHost<Options["checkPermission"]> ? unknown : {
|
|
52
53
|
context: never;
|
|
53
|
-
})): FoundationRegistry<Resolve, Operations
|
|
54
|
+
})): FoundationRegistry<Resolve, BoundOperations<Operations, Contract['commands']>>;
|
|
54
55
|
<Resolve extends Resolver, const Contract extends DomainContract & {
|
|
55
56
|
commands: Readonly<Record<string, NormalEntry & {
|
|
56
57
|
classification: string;
|
|
57
58
|
}>>;
|
|
58
|
-
}, const Operations extends
|
|
59
|
-
contract: Contract
|
|
59
|
+
}, const Operations extends DomainImplementations<Domain<Resolve>, Contract['commands'], true, true>>(configuration: {
|
|
60
|
+
contract: Contract & NoInfer<Operations extends ExactOperations<Operations, Contract['commands']> & ValidatedOperations<Operations> ? unknown : never>;
|
|
60
61
|
context: Resolve;
|
|
61
62
|
audit?: never;
|
|
62
|
-
operations: (definitions: DomainFactory<Domain<Resolve>, Contract['commands'], true, true>) => Operations
|
|
63
|
+
operations: (definitions: DomainFactory<Domain<Resolve>, Contract['commands'], true, true>) => Operations;
|
|
63
64
|
defaults?: Defaults<Domain<Resolve>>;
|
|
64
65
|
} & (Host<Resolve> extends CallbackHost<Options["writeAudit"]> & CallbackHost<Options["checkPermission"]> ? unknown : {
|
|
65
66
|
context: never;
|
|
66
|
-
})): FoundationRegistry<Resolve, Operations
|
|
67
|
+
})): FoundationRegistry<Resolve, BoundOperations<Operations, Contract['commands']>>;
|
|
67
68
|
<Resolve extends Resolver, const Operations extends Registry<Domain<Resolve>>>(configuration: {
|
|
68
69
|
contract?: never;
|
|
69
70
|
context: Resolve;
|
|
@@ -85,14 +86,14 @@ export declare function createFoundation<const Options extends FoundationRegistr
|
|
|
85
86
|
Query: {
|
|
86
87
|
<Resolve extends Resolver, const Contract extends DomainContract & {
|
|
87
88
|
queries: Readonly<Record<string, NormalEntry>>;
|
|
88
|
-
}, const Operations extends
|
|
89
|
-
contract: Contract
|
|
89
|
+
}, const Operations extends DomainImplementations<Domain<Resolve>, Contract['queries'], false, true>>(configuration: {
|
|
90
|
+
contract: Contract & NoInfer<Operations extends ExactOperations<Operations, Contract['queries']> & ValidatedOperations<Operations> ? unknown : never>;
|
|
90
91
|
context: Resolve;
|
|
91
|
-
operations: (definitions: DomainFactory<Domain<Resolve>, Contract['queries'], false, true>) => Operations
|
|
92
|
+
operations: (definitions: DomainFactory<Domain<Resolve>, Contract['queries'], false, true>) => Operations;
|
|
92
93
|
defaults?: Defaults<Domain<Resolve>>;
|
|
93
94
|
} & (Host<Resolve> extends CallbackHost<Options["writeAudit"]> & CallbackHost<Options["checkPermission"]> ? unknown : {
|
|
94
95
|
context: never;
|
|
95
|
-
})): FoundationRegistry<Resolve, Operations
|
|
96
|
+
})): FoundationRegistry<Resolve, BoundOperations<Operations, Contract['queries']>>;
|
|
96
97
|
<Resolve extends Resolver, const Operations extends Registry<Domain<Resolve>>>(configuration: {
|
|
97
98
|
contract?: never;
|
|
98
99
|
context: Resolve;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"foundation.mjs","names":["createFoundation","observability","Observability","options","Command","registry","configuration","Query","section","command","definitions","domainFactory","operationFactory","operations","snapshotOperations","exec","operation","definition","parsed","decode","input","permission","CommandPermissionError","host","context","run","enriched","guard","executeCommandLifecycle","promiseLifecycle","prepared","result","value","entry","called","next","raw","settings","selectOperation","owner","schema","decoded","decodeContract","issue"],"sources":["../../../src/modules/foundation/foundation.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns, anti-slop/no-unsafe-dictionary-type -- Private heterogeneous executor storage; public overloads restore schema-owned values and callbacks before dispatch. */\nimport type { AuditEntryInput } from '../../components/foundation/client'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Host registries share the deployed component's Effect-free interpreter.\nimport {\n\texecuteCommandLifecycle,\n\tpromiseLifecycle,\n\tCommandPermissionError,\n\ttype PromiseExecution,\n} from '../../components/foundation/modules/command/lifecycle'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Host-only observability is shared without entering the deployment graph.\nimport {\n\tObservability,\n\ttype ObservabilityOptions,\n} from '../../components/foundation/modules/observability/observability'\nimport {\n\tdecodeContract,\n\ttype ContractInput,\n\ttype ContractOutput,\n\ttype NeutralSchema,\n} from '../contracts/contract'\nimport type { DomainContract, DomainAuditInput } from '../contracts/domain'\nimport { snapshotOperations } from '../contracts/binding'\nimport {\n\tselectOperation,\n\ttype SelectedOperation,\n\ttype OperationPublicResult,\n} from '../contracts/exposure'\nimport {\n\tdomainFactory,\n\toperationFactory,\n\ttype DomainFactory,\n\ttype InlineFactory,\n\ttype NormalEntry,\n\ttype Audit,\n\ttype CheckedOperation,\n\ttype ExactOperations,\n\ttype ValidatedOperations,\n} from './operation'\n\ntype Supported<Value> = Value | PromiseLike<Value>\ntype Resolver = (host: never) => unknown\ntype Domain<Resolve extends Resolver> = Awaited<ReturnType<Resolve>>\ntype Host<Resolve extends Resolver> = Parameters<Resolve>[0]\ntype CallbackHost<Callback> = Callback extends (host: infer Host, ...args: never[]) => unknown\n\t? Host\n\t: unknown\nexport type FoundationRegistryOptions = {\n\tobservability: ObservabilityOptions\n\twriteAudit: (host: never, entry: AuditEntryInput) => Supported<unknown>\n\tcheckPermission?: (\n\t\thost: never,\n\t\tinput: { operation: string; permission: string },\n\t) => Supported<void>\n}\ntype Registry<Context> = Readonly<\n\tRecord<\n\t\tstring,\n\t\tNormalEntry & { handler: (input: never, context: never) => unknown } & CheckedOperation<Context>\n\t>\n>\ntype AuditedRegistry<Context> = Registry<Context> &\n\tReadonly<Record<string, { audit: (resolution: never, context: never) => Supported<Audit> }>>\ntype Defaults<Context> = { guard?: (context: Context) => Supported<void>; metadata?: object }\nexport type FoundationRegistry<\n\tResolve extends Resolver,\n\tOperations extends Registry<Domain<Resolve>>,\n> = {\n\texec<Key extends Extract<keyof Operations, string>>(\n\t\toperation: Key,\n\t\tinput: ContractInput<Operations[Key]['input']>,\n\t\thost: Host<Resolve>,\n\t): Promise<ContractOutput<Operations[Key]['result']>>\n\twithContext(host: Host<Resolve>): {\n\t\texec<Key extends Extract<keyof Operations, string>>(\n\t\t\toperation: Key,\n\t\t\tinput: ContractInput<Operations[Key]['input']>,\n\t\t): Promise<ContractOutput<Operations[Key]['result']>>\n\t}\n\texpose<const Owner extends symbol, const Key extends Extract<keyof Operations, string>>(\n\t\towner: Owner,\n\t\toperation: Key,\n\t): SelectedOperation<Owner, Key, Operations[Key]['input'], OperationPublicResult<Operations[Key]>>\n}\ntype RuntimeDefinition = NormalEntry & {\n\tclassification?: string\n\tpermission?: string\n\tmetadata?: object\n\taggregates?: readonly string[]\n\thandler: (input: unknown, context: unknown) => Supported<unknown>\n\tguard?: (context: unknown, input: unknown) => Supported<void>\n\tprepare?: (\n\t\tcontext: unknown,\n\t\tinput: unknown,\n\t) => Supported<\n\t\t| { kind: 'replay'; result: unknown }\n\t\t| { kind: 'execute'; complete?: (result: unknown) => Supported<void> }\n\t>\n\taudit: (resolution: { command: unknown; result: unknown }, context: unknown) => Supported<Audit>\n\tmiddleware?: (input: {\n\t\toperation: string\n\t\tcommand: unknown\n\t\tinput: unknown\n\t\tcontext: unknown\n\t\tmetadata: object\n\t\tnext: (options?: { context?: object }) => Promise<unknown>\n\t}) => Supported<unknown>\n}\ntype RuntimeConfiguration = {\n\tcontext: Resolver\n\tcontract?: DomainContract\n\toperations: (definitions: never) => Readonly<Record<string, object>>\n\taudit?: (resolution: never, context: never) => Supported<Audit>\n\tdefaults?: Defaults<never>\n}\n\n// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n/** Promise-based registries share the same command protocol as the optional Effect adapter. */\nexport function createFoundation<const Options extends FoundationRegistryOptions>(\n\toptions: Options,\n) {\n\tconst observability = new Observability(options.observability)\n\ttype PolicyHost = CallbackHost<Options['writeAudit']> & CallbackHost<Options['checkPermission']>\n\ttype Compatible<Resolve extends Resolver> =\n\t\tHost<Resolve> extends PolicyHost ? unknown : { context: never }\n\tfunction Command<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & {\n\t\t\tcommands: Readonly<Record<string, NormalEntry & { classification: string }>>\n\t\t},\n\t\tconst Operations extends Registry<Domain<Resolve>>,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract\n\t\t\tcontext: Resolve\n\t\t\taudit: (\n\t\t\t\tresolution: DomainAuditInput<Contract['commands']>,\n\t\t\t\tcontext: Domain<Resolve>,\n\t\t\t) => Supported<Audit>\n\t\t\toperations: (\n\t\t\t\tdefinitions: DomainFactory<Domain<Resolve>, Contract['commands'], true, false>,\n\t\t\t) => Operations &\n\t\t\t\tNoInfer<ExactOperations<Operations, Contract['commands']>> &\n\t\t\t\tNoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Command<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & {\n\t\t\tcommands: Readonly<Record<string, NormalEntry & { classification: string }>>\n\t\t},\n\t\tconst Operations extends AuditedRegistry<Domain<Resolve>>,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract\n\t\t\tcontext: Resolve\n\t\t\taudit?: never\n\t\t\toperations: (\n\t\t\t\tdefinitions: DomainFactory<Domain<Resolve>, Contract['commands'], true, true>,\n\t\t\t) => Operations &\n\t\t\t\tNoInfer<ExactOperations<Operations, Contract['commands']>> &\n\t\t\t\tNoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Command<Resolve extends Resolver, const Operations extends Registry<Domain<Resolve>>>(\n\t\tconfiguration: {\n\t\t\tcontract?: never\n\t\t\tcontext: Resolve\n\t\t\taudit: (\n\t\t\t\tresolution: DomainAuditInput<Operations>,\n\t\t\t\tcontext: Domain<Resolve>,\n\t\t\t) => Supported<Audit>\n\t\t\toperations: (\n\t\t\t\tdefinitions: InlineFactory<Domain<Resolve>, false>,\n\t\t\t) => Operations & NoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Command<\n\t\tResolve extends Resolver,\n\t\tconst Operations extends AuditedRegistry<Domain<Resolve>>,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract?: never\n\t\t\tcontext: Resolve\n\t\t\toperations: (\n\t\t\t\tdefinitions: InlineFactory<Domain<Resolve>, true>,\n\t\t\t) => Operations & NoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Command(configuration: RuntimeConfiguration): unknown {\n\t\treturn registry(configuration, true)\n\t}\n\tfunction Query<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & { queries: Readonly<Record<string, NormalEntry>> },\n\t\tconst Operations extends Registry<Domain<Resolve>>,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract\n\t\t\tcontext: Resolve\n\t\t\toperations: (\n\t\t\t\tdefinitions: DomainFactory<Domain<Resolve>, Contract['queries'], false, true>,\n\t\t\t) => Operations &\n\t\t\t\tNoInfer<ExactOperations<Operations, Contract['queries']>> &\n\t\t\t\tNoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Query<Resolve extends Resolver, const Operations extends Registry<Domain<Resolve>>>(\n\t\tconfiguration: {\n\t\t\tcontract?: never\n\t\t\tcontext: Resolve\n\t\t\toperations: (\n\t\t\t\tdefinitions: InlineFactory<Domain<Resolve>, true>,\n\t\t\t) => Operations & NoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Query(configuration: RuntimeConfiguration): unknown {\n\t\treturn registry(configuration, false)\n\t}\n\tfunction registry(configuration: RuntimeConfiguration, command: boolean) {\n\t\tconst section = command ? 'commands' : 'queries'\n\t\t// SAFETY: public overloads restrict Promise registries to neutral schemas.\n\t\tconst definitions = configuration.contract\n\t\t\t? domainFactory(\n\t\t\t\t\t// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n\t\t\t\t\t(configuration.contract[section] as Readonly<Record<string, NormalEntry>>) ?? {},\n\t\t\t\t\tcommand,\n\t\t\t\t)\n\t\t\t: operationFactory()\n\t\t// SAFETY: helper overloads checked the selected callbacks; storage erases only their parameters.\n\t\tconst operations = snapshotOperations(\n\t\t\t// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n\t\t\tconfiguration.operations(definitions as never),\n\t\t\tconfiguration.contract,\n\t\t\tsection,\n\t\t\tconfiguration.audit,\n\t\t)\n\t\tasync function exec(operation: string, input: unknown, host: never) {\n\t\t\tif (!Object.hasOwn(operations, operation))\n\t\t\t\tthrow Error(`The selected ${command ? 'command' : 'query'} operation is not configured`)\n\t\t\t// SAFETY: helpers verified callbacks against these paired schemas; only the runtime storage erases values.\n\t\t\tconst definition = operations[operation] as RuntimeDefinition\n\t\t\tconst parsed = await decode(definition.input, input)\n\t\t\treturn observability.observe(\n\t\t\t\t{ operation, classification: definition.classification ?? 'query' },\n\t\t\t\tasync () => {\n\t\t\t\t\tconst permission = async () => {\n\t\t\t\t\t\tif (!definition.permission) return\n\t\t\t\t\t\tif (!options.checkPermission) throw new CommandPermissionError(operation)\n\t\t\t\t\t\tawait options.checkPermission(host, { operation, permission: definition.permission })\n\t\t\t\t\t}\n\t\t\t\t\tif (!command) await permission()\n\t\t\t\t\tconst context = await configuration.context(host)\n\t\t\t\t\tconst run = (enriched: unknown) => Promise.resolve(definition.handler(parsed, enriched))\n\t\t\t\t\tconst guard = async (enriched: unknown) => {\n\t\t\t\t\t\t// SAFETY: base resolver context is the public default guard context.\n\t\t\t\t\t\tawait configuration.defaults?.guard?.(enriched as never)\n\t\t\t\t\t\tawait definition.guard?.(enriched, parsed)\n\t\t\t\t\t}\n\t\t\t\t\tif (command)\n\t\t\t\t\t\treturn executeCommandLifecycle<PromiseExecution, unknown, unknown, unknown, unknown>(\n\t\t\t\t\t\t\tpromiseLifecycle,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\tclassification: definition.classification!,\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\tcommand: parsed,\n\t\t\t\t\t\t\t\tpermission,\n\t\t\t\t\t\t\t\tprepare: async () => {\n\t\t\t\t\t\t\t\t\tconst prepared = await definition.prepare?.(context, parsed)\n\t\t\t\t\t\t\t\t\treturn prepared?.kind === 'execute'\n\t\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t\t...prepared,\n\t\t\t\t\t\t\t\t\t\t\t\tcomplete: prepared.complete\n\t\t\t\t\t\t\t\t\t\t\t\t\t? async (result) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tawait prepared.complete!(result)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t: prepared\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tmiddleware: definition.middleware\n\t\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t\t(input) =>\n\t\t\t\t\t\t\t\t\t\t\t\tPromise.resolve(\n\t\t\t\t\t\t\t\t\t\t\t\t\tdefinition.middleware!({\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t...input,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tinput: parsed,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...configuration.defaults?.metadata,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...definition.metadata,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t: [],\n\t\t\t\t\t\t\t\tdefaultGuard: async () => {},\n\t\t\t\t\t\t\t\tguard,\n\t\t\t\t\t\t\t\trun,\n\t\t\t\t\t\t\t\tdecodeReplay: (value) =>\n\t\t\t\t\t\t\t\t\tdecode(definition.replayResult ?? definition.result, value),\n\t\t\t\t\t\t\t\tdecodeResult: (value) => decode(definition.result, value),\n\t\t\t\t\t\t\t\taudit: async (result) => definition.audit({ command: parsed, result }, context),\n\t\t\t\t\t\t\t\twriteAudit: async (entry) => options.writeAudit(host, entry),\n\t\t\t\t\t\t\t\taggregates: definition.aggregates,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)\n\t\t\t\t\tlet called = false\n\t\t\t\t\tconst next = async (enriched = context) => {\n\t\t\t\t\t\tif (called) throw Error('A query middleware called next() more than once')\n\t\t\t\t\t\tcalled = true\n\t\t\t\t\t\tawait guard(enriched)\n\t\t\t\t\t\treturn run(enriched)\n\t\t\t\t\t}\n\t\t\t\t\tconst raw = definition.middleware\n\t\t\t\t\t\t? await definition.middleware({\n\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\tcommand: parsed,\n\t\t\t\t\t\t\t\tinput: parsed,\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\tmetadata: { ...configuration.defaults?.metadata, ...definition.metadata },\n\t\t\t\t\t\t\t\tnext: (settings) =>\n\t\t\t\t\t\t\t\t\tnext(\n\t\t\t\t\t\t\t\t\t\t// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n\t\t\t\t\t\t\t\t\t\tsettings?.context ? { ...(context as object), ...settings.context } : context,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: await next()\n\t\t\t\t\treturn decode(definition.result, raw)\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t\treturn {\n\t\t\texec,\n\t\t\twithContext: (host: never) => ({\n\t\t\t\texec: (operation: string, input: unknown) => exec(operation, input, host),\n\t\t\t}),\n\t\t\texpose: (owner: symbol, operation: string) => {\n\t\t\t\tif (!Object.hasOwn(operations, operation))\n\t\t\t\t\tthrow Error('The selected operation is not configured')\n\t\t\t\treturn selectOperation(\n\t\t\t\t\towner,\n\t\t\t\t\tcommand ? 'mutation' : 'query',\n\t\t\t\t\toperation,\n\t\t\t\t\t// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n\t\t\t\t\toperations[operation] as RuntimeDefinition,\n\t\t\t\t)\n\t\t\t},\n\t\t}\n\t}\n\treturn { Command, Query, observability }\n}\n\nasync function decode(schema: NeutralSchema, value: unknown) {\n\tif ('kind' in schema && schema.kind !== 'contract')\n\t\tthrow Error('Effect contracts require the Effect registry')\n\tconst decoded = await decodeContract(schema, value)\n\tif (decoded.issues) throw Error(decoded.issues.map((issue) => issue.message).join('; '))\n\treturn decoded.value\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"foundation.mjs","names":["createFoundation","observability","Observability","options","Command","registry","configuration","Query","section","command","definitions","domainFactory","operationFactory","operations","snapshotOperations","exec","operation","definition","parsed","decode","input","permission","CommandPermissionError","host","context","run","enriched","guard","executeCommandLifecycle","promiseLifecycle","prepared","result","value","entry","called","next","raw","settings","selectOperation","owner","schema","decoded","decodeContract","issue"],"sources":["../../../src/modules/foundation/foundation.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns, anti-slop/no-unsafe-dictionary-type -- Private heterogeneous executor storage; public overloads restore schema-owned values and callbacks before dispatch. */\nimport type { AuditEntryInput } from '../../components/foundation/client'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Host registries share the deployed component's Effect-free interpreter.\nimport {\n\texecuteCommandLifecycle,\n\tpromiseLifecycle,\n\tCommandPermissionError,\n\ttype PromiseExecution,\n} from '../../components/foundation/modules/command/lifecycle'\n// oxlint-disable-next-line cvx/component-boundaries -- SAFETY: Host-only observability is shared without entering the deployment graph.\nimport {\n\tObservability,\n\ttype ObservabilityOptions,\n} from '../../components/foundation/modules/observability/observability'\nimport {\n\tdecodeContract,\n\ttype ContractInput,\n\ttype ContractOutput,\n\ttype NeutralSchema,\n} from '../contracts/contract'\nimport type { DomainContract, DomainAuditInput } from '../contracts/domain'\nimport { snapshotOperations, type BoundOperations } from '../contracts/binding'\nimport {\n\tselectOperation,\n\ttype SelectedOperation,\n\ttype OperationPublicResult,\n} from '../contracts/exposure'\nimport {\n\tdomainFactory,\n\toperationFactory,\n\ttype DomainFactory,\n\ttype DomainImplementations,\n\ttype InlineFactory,\n\ttype NormalEntry,\n\ttype Audit,\n\ttype CheckedOperation,\n\ttype ExactOperations,\n\ttype ValidatedOperations,\n} from './operation'\n\ntype Supported<Value> = Value | PromiseLike<Value>\ntype Resolver = (host: never) => unknown\ntype Domain<Resolve extends Resolver> = Awaited<ReturnType<Resolve>>\ntype Host<Resolve extends Resolver> = Parameters<Resolve>[0]\ntype CallbackHost<Callback> = Callback extends (host: infer Host, ...args: never[]) => unknown\n\t? Host\n\t: unknown\nexport type FoundationRegistryOptions = {\n\tobservability: ObservabilityOptions\n\twriteAudit: (host: never, entry: AuditEntryInput) => Supported<unknown>\n\tcheckPermission?: (\n\t\thost: never,\n\t\tinput: { operation: string; permission: string },\n\t) => Supported<void>\n}\ntype Registry<Context> = Readonly<\n\tRecord<\n\t\tstring,\n\t\tNormalEntry & { handler: (input: never, context: never) => unknown } & CheckedOperation<Context>\n\t>\n>\ntype AuditedRegistry<Context> = Registry<Context> &\n\tReadonly<Record<string, { audit: (resolution: never, context: never) => Supported<Audit> }>>\ntype Defaults<Context> = { guard?: (context: Context) => Supported<void>; metadata?: object }\nexport type FoundationRegistry<\n\tResolve extends Resolver,\n\tOperations extends Registry<Domain<Resolve>>,\n> = {\n\texec<Key extends Extract<keyof Operations, string>>(\n\t\toperation: Key,\n\t\tinput: ContractInput<Operations[Key]['input']>,\n\t\thost: Host<Resolve>,\n\t): Promise<ContractOutput<Operations[Key]['result']>>\n\twithContext(host: Host<Resolve>): {\n\t\texec<Key extends Extract<keyof Operations, string>>(\n\t\t\toperation: Key,\n\t\t\tinput: ContractInput<Operations[Key]['input']>,\n\t\t): Promise<ContractOutput<Operations[Key]['result']>>\n\t}\n\texpose<const Owner extends symbol, const Key extends Extract<keyof Operations, string>>(\n\t\towner: Owner,\n\t\toperation: Key,\n\t): SelectedOperation<Owner, Key, Operations[Key]['input'], OperationPublicResult<Operations[Key]>>\n}\ntype RuntimeDefinition = NormalEntry & {\n\tclassification?: string\n\tpermission?: string\n\tmetadata?: object\n\taggregates?: readonly string[]\n\thandler: (input: unknown, context: unknown) => Supported<unknown>\n\tguard?: (context: unknown, input: unknown) => Supported<void>\n\tprepare?: (\n\t\tcontext: unknown,\n\t\tinput: unknown,\n\t) => Supported<\n\t\t| { kind: 'replay'; result: unknown }\n\t\t| { kind: 'execute'; complete?: (result: unknown) => Supported<void> }\n\t>\n\taudit: (resolution: { command: unknown; result: unknown }, context: unknown) => Supported<Audit>\n\tmiddleware?: (input: {\n\t\toperation: string\n\t\tcommand: unknown\n\t\tinput: unknown\n\t\tcontext: unknown\n\t\tmetadata: object\n\t\tnext: (options?: { context?: object }) => Promise<unknown>\n\t}) => Supported<unknown>\n}\ntype RuntimeConfiguration = {\n\tcontext: Resolver\n\tcontract?: DomainContract\n\toperations: (definitions: never) => Readonly<Record<string, object>>\n\taudit?: (resolution: never, context: never) => Supported<Audit>\n\tdefaults?: Defaults<never>\n}\n\n// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n/** Promise-based registries share the same command protocol as the optional Effect adapter. */\nexport function createFoundation<const Options extends FoundationRegistryOptions>(\n\toptions: Options,\n) {\n\tconst observability = new Observability(options.observability)\n\ttype PolicyHost = CallbackHost<Options['writeAudit']> & CallbackHost<Options['checkPermission']>\n\ttype Compatible<Resolve extends Resolver> =\n\t\tHost<Resolve> extends PolicyHost ? unknown : { context: never }\n\tfunction Command<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & {\n\t\t\tcommands: Readonly<Record<string, NormalEntry & { classification: string }>>\n\t\t},\n\t\tconst Operations extends DomainImplementations<\n\t\t\tDomain<Resolve>,\n\t\t\tContract['commands'],\n\t\t\ttrue,\n\t\t\tfalse\n\t\t>,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract &\n\t\t\t\tNoInfer<\n\t\t\t\t\tOperations extends ExactOperations<Operations, Contract['commands']> &\n\t\t\t\t\t\tValidatedOperations<Operations>\n\t\t\t\t\t\t? unknown\n\t\t\t\t\t\t: never\n\t\t\t\t>\n\t\t\tcontext: Resolve\n\t\t\taudit: (\n\t\t\t\tresolution: DomainAuditInput<Contract['commands']>,\n\t\t\t\tcontext: Domain<Resolve>,\n\t\t\t) => Supported<Audit>\n\t\t\toperations: (\n\t\t\t\tdefinitions: DomainFactory<Domain<Resolve>, Contract['commands'], true, false>,\n\t\t\t) => Operations\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, BoundOperations<Operations, Contract['commands']>>\n\tfunction Command<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & {\n\t\t\tcommands: Readonly<Record<string, NormalEntry & { classification: string }>>\n\t\t},\n\t\tconst Operations extends DomainImplementations<\n\t\t\tDomain<Resolve>,\n\t\t\tContract['commands'],\n\t\t\ttrue,\n\t\t\ttrue\n\t\t>,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract &\n\t\t\t\tNoInfer<\n\t\t\t\t\tOperations extends ExactOperations<Operations, Contract['commands']> &\n\t\t\t\t\t\tValidatedOperations<Operations>\n\t\t\t\t\t\t? unknown\n\t\t\t\t\t\t: never\n\t\t\t\t>\n\t\t\tcontext: Resolve\n\t\t\taudit?: never\n\t\t\toperations: (\n\t\t\t\tdefinitions: DomainFactory<Domain<Resolve>, Contract['commands'], true, true>,\n\t\t\t) => Operations\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, BoundOperations<Operations, Contract['commands']>>\n\tfunction Command<Resolve extends Resolver, const Operations extends Registry<Domain<Resolve>>>(\n\t\tconfiguration: {\n\t\t\tcontract?: never\n\t\t\tcontext: Resolve\n\t\t\taudit: (\n\t\t\t\tresolution: DomainAuditInput<Operations>,\n\t\t\t\tcontext: Domain<Resolve>,\n\t\t\t) => Supported<Audit>\n\t\t\toperations: (\n\t\t\t\tdefinitions: InlineFactory<Domain<Resolve>, false>,\n\t\t\t) => Operations & NoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Command<\n\t\tResolve extends Resolver,\n\t\tconst Operations extends AuditedRegistry<Domain<Resolve>>,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract?: never\n\t\t\tcontext: Resolve\n\t\t\toperations: (\n\t\t\t\tdefinitions: InlineFactory<Domain<Resolve>, true>,\n\t\t\t) => Operations & NoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Command(configuration: RuntimeConfiguration): unknown {\n\t\treturn registry(configuration, true)\n\t}\n\tfunction Query<\n\t\tResolve extends Resolver,\n\t\tconst Contract extends DomainContract & { queries: Readonly<Record<string, NormalEntry>> },\n\t\tconst Operations extends DomainImplementations<\n\t\t\tDomain<Resolve>,\n\t\t\tContract['queries'],\n\t\t\tfalse,\n\t\t\ttrue\n\t\t>,\n\t>(\n\t\tconfiguration: {\n\t\t\tcontract: Contract &\n\t\t\t\tNoInfer<\n\t\t\t\t\tOperations extends ExactOperations<Operations, Contract['queries']> &\n\t\t\t\t\t\tValidatedOperations<Operations>\n\t\t\t\t\t\t? unknown\n\t\t\t\t\t\t: never\n\t\t\t\t>\n\t\t\tcontext: Resolve\n\t\t\toperations: (\n\t\t\t\tdefinitions: DomainFactory<Domain<Resolve>, Contract['queries'], false, true>,\n\t\t\t) => Operations\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, BoundOperations<Operations, Contract['queries']>>\n\tfunction Query<Resolve extends Resolver, const Operations extends Registry<Domain<Resolve>>>(\n\t\tconfiguration: {\n\t\t\tcontract?: never\n\t\t\tcontext: Resolve\n\t\t\toperations: (\n\t\t\t\tdefinitions: InlineFactory<Domain<Resolve>, true>,\n\t\t\t) => Operations & NoInfer<ValidatedOperations<Operations>>\n\t\t\tdefaults?: Defaults<Domain<Resolve>>\n\t\t} & Compatible<Resolve>,\n\t): FoundationRegistry<Resolve, Operations>\n\tfunction Query(configuration: RuntimeConfiguration): unknown {\n\t\treturn registry(configuration, false)\n\t}\n\tfunction registry(configuration: RuntimeConfiguration, command: boolean) {\n\t\tconst section = command ? 'commands' : 'queries'\n\t\t// SAFETY: public overloads restrict Promise registries to neutral schemas.\n\t\tconst definitions = configuration.contract\n\t\t\t? domainFactory(\n\t\t\t\t\t// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n\t\t\t\t\t(configuration.contract[section] as Readonly<Record<string, NormalEntry>>) ?? {},\n\t\t\t\t\tcommand,\n\t\t\t\t)\n\t\t\t: operationFactory()\n\t\t// SAFETY: helper overloads checked the selected callbacks; storage erases only their parameters.\n\t\tconst operations = snapshotOperations(\n\t\t\t// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n\t\t\tconfiguration.operations(definitions as never),\n\t\t\tconfiguration.contract,\n\t\t\tsection,\n\t\t\tconfiguration.audit,\n\t\t)\n\t\tasync function exec(operation: string, input: unknown, host: never) {\n\t\t\tif (!Object.hasOwn(operations, operation))\n\t\t\t\tthrow Error(`The selected ${command ? 'command' : 'query'} operation is not configured`)\n\t\t\t// SAFETY: helpers verified callbacks against these paired schemas; only the runtime storage erases values.\n\t\t\tconst definition = operations[operation] as RuntimeDefinition\n\t\t\tconst parsed = await decode(definition.input, input)\n\t\t\treturn observability.observe(\n\t\t\t\t{ operation, classification: definition.classification ?? 'query' },\n\t\t\t\tasync () => {\n\t\t\t\t\tconst permission = async () => {\n\t\t\t\t\t\tif (!definition.permission) return\n\t\t\t\t\t\tif (!options.checkPermission) throw new CommandPermissionError(operation)\n\t\t\t\t\t\tawait options.checkPermission(host, { operation, permission: definition.permission })\n\t\t\t\t\t}\n\t\t\t\t\tif (!command) await permission()\n\t\t\t\t\tconst context = await configuration.context(host)\n\t\t\t\t\tconst run = (enriched: unknown) => Promise.resolve(definition.handler(parsed, enriched))\n\t\t\t\t\tconst guard = async (enriched: unknown) => {\n\t\t\t\t\t\t// SAFETY: base resolver context is the public default guard context.\n\t\t\t\t\t\tawait configuration.defaults?.guard?.(enriched as never)\n\t\t\t\t\t\tawait definition.guard?.(enriched, parsed)\n\t\t\t\t\t}\n\t\t\t\t\tif (command)\n\t\t\t\t\t\treturn executeCommandLifecycle<PromiseExecution, unknown, unknown, unknown, unknown>(\n\t\t\t\t\t\t\tpromiseLifecycle,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\tclassification: definition.classification!,\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\tcommand: parsed,\n\t\t\t\t\t\t\t\tpermission,\n\t\t\t\t\t\t\t\tprepare: async () => {\n\t\t\t\t\t\t\t\t\tconst prepared = await definition.prepare?.(context, parsed)\n\t\t\t\t\t\t\t\t\treturn prepared?.kind === 'execute'\n\t\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t\t...prepared,\n\t\t\t\t\t\t\t\t\t\t\t\tcomplete: prepared.complete\n\t\t\t\t\t\t\t\t\t\t\t\t\t? async (result) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tawait prepared.complete!(result)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t: prepared\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tmiddleware: definition.middleware\n\t\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t\t(input) =>\n\t\t\t\t\t\t\t\t\t\t\t\tPromise.resolve(\n\t\t\t\t\t\t\t\t\t\t\t\t\tdefinition.middleware!({\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t...input,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tinput: parsed,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tmetadata: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...configuration.defaults?.metadata,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...definition.metadata,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t: [],\n\t\t\t\t\t\t\t\tdefaultGuard: async () => {},\n\t\t\t\t\t\t\t\tguard,\n\t\t\t\t\t\t\t\trun,\n\t\t\t\t\t\t\t\tdecodeReplay: (value) =>\n\t\t\t\t\t\t\t\t\tdecode(definition.replayResult ?? definition.result, value),\n\t\t\t\t\t\t\t\tdecodeResult: (value) => decode(definition.result, value),\n\t\t\t\t\t\t\t\taudit: async (result) => definition.audit({ command: parsed, result }, context),\n\t\t\t\t\t\t\t\twriteAudit: async (entry) => options.writeAudit(host, entry),\n\t\t\t\t\t\t\t\taggregates: definition.aggregates,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t)\n\t\t\t\t\tlet called = false\n\t\t\t\t\tconst next = async (enriched = context) => {\n\t\t\t\t\t\tif (called) throw Error('A query middleware called next() more than once')\n\t\t\t\t\t\tcalled = true\n\t\t\t\t\t\tawait guard(enriched)\n\t\t\t\t\t\treturn run(enriched)\n\t\t\t\t\t}\n\t\t\t\t\tconst raw = definition.middleware\n\t\t\t\t\t\t? await definition.middleware({\n\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\tcommand: parsed,\n\t\t\t\t\t\t\t\tinput: parsed,\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\tmetadata: { ...configuration.defaults?.metadata, ...definition.metadata },\n\t\t\t\t\t\t\t\tnext: (settings) =>\n\t\t\t\t\t\t\t\t\tnext(\n\t\t\t\t\t\t\t\t\t\t// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n\t\t\t\t\t\t\t\t\t\tsettings?.context ? { ...(context as object), ...settings.context } : context,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: await next()\n\t\t\t\t\treturn decode(definition.result, raw)\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t\treturn {\n\t\t\texec,\n\t\t\twithContext: (host: never) => ({\n\t\t\t\texec: (operation: string, input: unknown) => exec(operation, input, host),\n\t\t\t}),\n\t\t\texpose: (owner: symbol, operation: string) => {\n\t\t\t\tif (!Object.hasOwn(operations, operation))\n\t\t\t\t\tthrow Error('The selected operation is not configured')\n\t\t\t\treturn selectOperation(\n\t\t\t\t\towner,\n\t\t\t\t\tcommand ? 'mutation' : 'query',\n\t\t\t\t\toperation,\n\t\t\t\t\t// SAFETY: public helper signatures and the paired schema check this erased runtime invocation.\n\t\t\t\t\toperations[operation] as RuntimeDefinition,\n\t\t\t\t)\n\t\t\t},\n\t\t}\n\t}\n\treturn { Command, Query, observability }\n}\n\nasync function decode(schema: NeutralSchema, value: unknown) {\n\tif ('kind' in schema && schema.kind !== 'contract')\n\t\tthrow Error('Effect contracts require the Effect registry')\n\tconst decoded = await decodeContract(schema, value)\n\tif (decoded.issues) throw Error(decoded.issues.map((issue) => issue.message).join('; '))\n\treturn decoded.value\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ContractInput, ContractOutput, NeutralSchema } from "../contracts/contract.mjs";
|
|
2
2
|
import { AuditEntryInput } from "../../components/foundation/client.mjs";
|
|
3
3
|
import { DomainOperationContract, ExactOperationKeys } from "../contracts/domain.mjs";
|
|
4
|
+
import { DeclaredSchemas } from "../contracts/binding.mjs";
|
|
4
5
|
//#region src/modules/foundation/operation.d.ts
|
|
5
6
|
type Supported<A> = A | PromiseLike<A>;
|
|
6
7
|
export type Audit = Omit<AuditEntryInput, 'classification'> | null;
|
|
@@ -81,7 +82,25 @@ type Forbidden = {
|
|
|
81
82
|
replayResult?: never;
|
|
82
83
|
wire?: never;
|
|
83
84
|
};
|
|
84
|
-
|
|
85
|
+
type HandlerOptions<Context, Input extends NeutralSchema, Result extends NeutralSchema, Command extends boolean, Required extends boolean> = Omit<Definition<Context, {
|
|
86
|
+
input: Input;
|
|
87
|
+
result: Result;
|
|
88
|
+
}>, 'handler'> & Forbidden & {
|
|
89
|
+
handler?: never;
|
|
90
|
+
} & CommandRules<Context, {
|
|
91
|
+
input: Input;
|
|
92
|
+
result: Result;
|
|
93
|
+
}, Command, Required>;
|
|
94
|
+
type HandlerArguments<Options, Required extends boolean> = Required extends true ? [options: Options] : [options?: Options];
|
|
95
|
+
export type DomainFactory<Context, Entries extends Readonly<Record<string, NormalEntry>>, Command extends boolean, Required extends boolean> = { [Kind in Command extends true ? 'command' : 'query']: { [Key in keyof Entries]: <const Implementation extends object>(implementation: Implementation & Definition<Context, Entries[Key]> & Forbidden & CommandRules<Context, Entries[Key], Command, Required>) => DeclaredSchemas<Pick<Entries[Key], 'input' | 'result'>> & CheckedDefinition<Context, Entries[Key] & Implementation, Key>; } & {
|
|
96
|
+
handler: <const Input extends NeutralSchema, const Result extends NeutralSchema, Key extends keyof Entries, Handler extends Supported<ContractInput<Result>>, const Implementation extends object = Record<never, never>>(handler: (input: ContractOutput<Input>, context: Context) => Handler, ...options: HandlerArguments<Implementation & HandlerOptions<Context, Input, Result, Command, Required>, Command extends true ? Required : false>) => DeclaredSchemas<{
|
|
97
|
+
input: Input;
|
|
98
|
+
result: Result;
|
|
99
|
+
}> & CheckedDefinition<Context, NoInfer<Implementation> & {
|
|
100
|
+
handler: (input: ContractOutput<Input>, context: Context) => Handler;
|
|
101
|
+
}, Key>;
|
|
102
|
+
}; };
|
|
103
|
+
export type DomainImplementations<Context, Entries extends Readonly<Record<string, NormalEntry>>, Command extends boolean, Required extends boolean> = { [Key in keyof Entries]: DeclaredSchemas<Pick<Entries[Key], 'input' | 'result'>> & CheckedDefinition<Context, Definition<Context, Entries[Key]> & CommandRules<Context, Entries[Key], Command, Required>, Key>; };
|
|
85
104
|
export declare function domainFactory<Context, Entries extends Readonly<Record<string, NormalEntry>>, Command extends boolean, Required extends boolean>(entries: Entries, command: Command): DomainFactory<Context, Entries, Command, Required>;
|
|
86
105
|
export declare function operationFactory<Context, Required extends boolean = true>(): {
|
|
87
106
|
command: <const Input extends NeutralSchema, const Result extends NeutralSchema, const Wire extends NeutralSchema, const Replay extends NeutralSchema, const Implementation extends object>(implementation: Implementation & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operation.mjs","names":["domainFactory","helpers","domainHelpers","entries","command","operationFactory","implementation","query"],"sources":["../../../src/modules/foundation/operation.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-object-parameters -- Internal helper storage is heterogeneous; the exported mapped signatures validate the schema-paired implementation. */\nimport type { AuditEntryInput } from '../../components/foundation/client'\nimport type { ContractInput, ContractOutput, NeutralSchema } from '../contracts/contract'\nimport type { DomainOperationContract, ExactOperationKeys } from '../contracts/domain'\nimport { domainHelpers } from '../contracts/binding'\n\ntype Supported<A> = A | PromiseLike<A>\nexport type Audit = Omit<AuditEntryInput, 'classification'> | null\nexport type NormalEntry = DomainOperationContract & {\n\tinput: NeutralSchema\n\tresult: NeutralSchema\n\treplayResult?: NeutralSchema\n\twire?: { schema: NeutralSchema; project: Function }\n}\ndeclare const checkedOperation: unique symbol\nexport type CheckedDefinition<Context, Definition, Key = unknown> = NoInfer<Definition> & {\n\treadonly [checkedOperation]: {\n\t\tcontext: (context: Context) => void\n\t\tdefinition: Definition\n\t\tkey: Key\n\t}\n}\nexport type CheckedOperation<Context> = {\n\treadonly [checkedOperation]: {\n\t\tcontext: (context: Context) => void\n\t\tdefinition: unknown\n\t\tkey: unknown\n\t}\n}\nexport type ValidatedOperations<Operations> = {\n\t[Key in keyof Operations]: Operations[Key] extends {\n\t\treadonly [checkedOperation]: { definition: infer Definition }\n\t}\n\t\t? Operations[Key] extends Definition\n\t\t\t? Operations[Key]\n\t\t\t: never\n\t\t: never\n}\nexport type ExactOperations<Operations, Entries> = ExactOperationKeys<Operations, Entries> & {\n\t[Key in keyof Operations]: Operations[Key] extends { readonly [checkedOperation]: { key: Key } }\n\t\t? Operations[Key]\n\t\t: never\n}\ntype Definition<Context, Entry extends NormalEntry> = {\n\thandler: (\n\t\tinput: ContractOutput<Entry['input']>,\n\t\tcontext: Context,\n\t) => Supported<ContractInput<Entry['result']>>\n\tpermission?: string\n\tmetadata?: object\n\taggregates?: readonly string[]\n\tguard?: (context: Context, input: ContractOutput<Entry['input']>) => Supported<void>\n\tprepare?: (\n\t\tcontext: Context,\n\t\tinput: ContractOutput<Entry['input']>,\n\t) => Supported<\n\t\t| { kind: 'replay'; result: unknown }\n\t\t| { kind: 'execute'; complete?: (result: ContractOutput<Entry['result']>) => Supported<void> }\n\t>\n\taudit?: (\n\t\tresolution: {\n\t\t\tcommand: ContractOutput<Entry['input']>\n\t\t\tresult: ContractOutput<Entry['result']>\n\t\t},\n\t\tcontext: Context,\n\t) => Supported<Audit>\n\tmiddleware?: (input: {\n\t\toperation: string\n\t\tinput: ContractOutput<Entry['input']>\n\t\tcommand: ContractOutput<Entry['input']>\n\t\tcontext: Context\n\t\tmetadata: object\n\t\tnext: (options?: { context?: object }) => Promise<ContractInput<Entry['result']>>\n\t}) => Supported<ContractInput<Entry['result']>>\n}\ntype CommandRules<\n\tContext,\n\tEntry extends NormalEntry,\n\tCommand extends boolean,\n\tRequired extends boolean,\n> = Command extends false\n\t? { audit?: never; prepare?: never; aggregates?: never; replayResult?: never }\n\t: Required extends true\n\t\t? { audit: NonNullable<Definition<Context, Entry>['audit']> }\n\t\t: {}\ntype Forbidden = {\n\tinput?: never\n\tresult?: never\n\tclassification?: never\n\treplayResult?: never\n\twire?: never\n}\nexport type DomainFactory<\n\tContext,\n\tEntries extends Readonly<Record<string, NormalEntry>>,\n\tCommand extends boolean,\n\tRequired extends boolean,\n> = {\n\t[Kind in Command extends true ? 'command' : 'query']: {\n\t\t[Key in keyof Entries]: <const Implementation extends object>(\n\t\t\timplementation: Implementation &\n\t\t\t\tDefinition<Context, Entries[Key]> &\n\t\t\t\tForbidden &\n\t\t\t\tCommandRules<Context, Entries[Key], Command, Required>,\n\t\t) =>
|
|
1
|
+
{"version":3,"file":"operation.mjs","names":["domainFactory","helpers","domainHelpers","entries","command","operationFactory","implementation","query"],"sources":["../../../src/modules/foundation/operation.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-object-parameters -- Internal helper storage is heterogeneous; the exported mapped signatures validate the schema-paired implementation. */\nimport type { AuditEntryInput } from '../../components/foundation/client'\nimport type { ContractInput, ContractOutput, NeutralSchema } from '../contracts/contract'\nimport type { DomainOperationContract, ExactOperationKeys } from '../contracts/domain'\nimport { domainHelpers, type DeclaredSchemas } from '../contracts/binding'\n\ntype Supported<A> = A | PromiseLike<A>\nexport type Audit = Omit<AuditEntryInput, 'classification'> | null\nexport type NormalEntry = DomainOperationContract & {\n\tinput: NeutralSchema\n\tresult: NeutralSchema\n\treplayResult?: NeutralSchema\n\twire?: { schema: NeutralSchema; project: Function }\n}\ndeclare const checkedOperation: unique symbol\nexport type CheckedDefinition<Context, Definition, Key = unknown> = NoInfer<Definition> & {\n\treadonly [checkedOperation]: {\n\t\tcontext: (context: Context) => void\n\t\tdefinition: Definition\n\t\tkey: Key\n\t}\n}\nexport type CheckedOperation<Context> = {\n\treadonly [checkedOperation]: {\n\t\tcontext: (context: Context) => void\n\t\tdefinition: unknown\n\t\tkey: unknown\n\t}\n}\nexport type ValidatedOperations<Operations> = {\n\t[Key in keyof Operations]: Operations[Key] extends {\n\t\treadonly [checkedOperation]: { definition: infer Definition }\n\t}\n\t\t? Operations[Key] extends Definition\n\t\t\t? Operations[Key]\n\t\t\t: never\n\t\t: never\n}\nexport type ExactOperations<Operations, Entries> = ExactOperationKeys<Operations, Entries> & {\n\t[Key in keyof Operations]: Operations[Key] extends { readonly [checkedOperation]: { key: Key } }\n\t\t? Operations[Key]\n\t\t: never\n}\ntype Definition<Context, Entry extends NormalEntry> = {\n\thandler: (\n\t\tinput: ContractOutput<Entry['input']>,\n\t\tcontext: Context,\n\t) => Supported<ContractInput<Entry['result']>>\n\tpermission?: string\n\tmetadata?: object\n\taggregates?: readonly string[]\n\tguard?: (context: Context, input: ContractOutput<Entry['input']>) => Supported<void>\n\tprepare?: (\n\t\tcontext: Context,\n\t\tinput: ContractOutput<Entry['input']>,\n\t) => Supported<\n\t\t| { kind: 'replay'; result: unknown }\n\t\t| { kind: 'execute'; complete?: (result: ContractOutput<Entry['result']>) => Supported<void> }\n\t>\n\taudit?: (\n\t\tresolution: {\n\t\t\tcommand: ContractOutput<Entry['input']>\n\t\t\tresult: ContractOutput<Entry['result']>\n\t\t},\n\t\tcontext: Context,\n\t) => Supported<Audit>\n\tmiddleware?: (input: {\n\t\toperation: string\n\t\tinput: ContractOutput<Entry['input']>\n\t\tcommand: ContractOutput<Entry['input']>\n\t\tcontext: Context\n\t\tmetadata: object\n\t\tnext: (options?: { context?: object }) => Promise<ContractInput<Entry['result']>>\n\t}) => Supported<ContractInput<Entry['result']>>\n}\ntype CommandRules<\n\tContext,\n\tEntry extends NormalEntry,\n\tCommand extends boolean,\n\tRequired extends boolean,\n> = Command extends false\n\t? { audit?: never; prepare?: never; aggregates?: never; replayResult?: never }\n\t: Required extends true\n\t\t? { audit: NonNullable<Definition<Context, Entry>['audit']> }\n\t\t: {}\ntype Forbidden = {\n\tinput?: never\n\tresult?: never\n\tclassification?: never\n\treplayResult?: never\n\twire?: never\n}\ntype HandlerOptions<\n\tContext,\n\tInput extends NeutralSchema,\n\tResult extends NeutralSchema,\n\tCommand extends boolean,\n\tRequired extends boolean,\n> = Omit<Definition<Context, { input: Input; result: Result }>, 'handler'> &\n\tForbidden & { handler?: never } & CommandRules<\n\t\tContext,\n\t\t{ input: Input; result: Result },\n\t\tCommand,\n\t\tRequired\n\t>\ntype HandlerArguments<Options, Required extends boolean> = Required extends true\n\t? [options: Options]\n\t: [options?: Options]\n\nexport type DomainFactory<\n\tContext,\n\tEntries extends Readonly<Record<string, NormalEntry>>,\n\tCommand extends boolean,\n\tRequired extends boolean,\n> = {\n\t[Kind in Command extends true ? 'command' : 'query']: {\n\t\t[Key in keyof Entries]: <const Implementation extends object>(\n\t\t\timplementation: Implementation &\n\t\t\t\tDefinition<Context, Entries[Key]> &\n\t\t\t\tForbidden &\n\t\t\t\tCommandRules<Context, Entries[Key], Command, Required>,\n\t\t) => DeclaredSchemas<Pick<Entries[Key], 'input' | 'result'>> &\n\t\t\tCheckedDefinition<Context, Entries[Key] & Implementation, Key>\n\t} & {\n\t\thandler: <\n\t\t\tconst Input extends NeutralSchema,\n\t\t\tconst Result extends NeutralSchema,\n\t\t\tKey extends keyof Entries,\n\t\t\tHandler extends Supported<ContractInput<Result>>,\n\t\t\tconst Implementation extends object = Record<never, never>,\n\t\t>(\n\t\t\thandler: (input: ContractOutput<Input>, context: Context) => Handler,\n\t\t\t...options: HandlerArguments<\n\t\t\t\tImplementation & HandlerOptions<Context, Input, Result, Command, Required>,\n\t\t\t\tCommand extends true ? Required : false\n\t\t\t>\n\t\t) => DeclaredSchemas<{ input: Input; result: Result }> &\n\t\t\tCheckedDefinition<\n\t\t\t\tContext,\n\t\t\t\tNoInfer<Implementation> & {\n\t\t\t\t\thandler: (input: ContractOutput<Input>, context: Context) => Handler\n\t\t\t\t},\n\t\t\t\tKey\n\t\t\t>\n\t}\n}\nexport type DomainImplementations<\n\tContext,\n\tEntries extends Readonly<Record<string, NormalEntry>>,\n\tCommand extends boolean,\n\tRequired extends boolean,\n> = {\n\t[Key in keyof Entries]: DeclaredSchemas<Pick<Entries[Key], 'input' | 'result'>> &\n\t\tCheckedDefinition<\n\t\t\tContext,\n\t\t\tDefinition<Context, Entries[Key]> & CommandRules<Context, Entries[Key], Command, Required>,\n\t\t\tKey\n\t\t>\n}\nexport function domainFactory<\n\tContext,\n\tEntries extends Readonly<Record<string, NormalEntry>>,\n\tCommand extends boolean,\n\tRequired extends boolean,\n>(entries: Entries, command: Command): DomainFactory<Context, Entries, Command, Required> {\n\tconst helpers = domainHelpers(entries)\n\t// SAFETY: helper signatures check callbacks; registration pairs drafts with their declarations.\n\treturn { [command ? 'command' : 'query']: helpers } as DomainFactory<\n\t\tContext,\n\t\tEntries,\n\t\tCommand,\n\t\tRequired\n\t>\n}\nexport function operationFactory<Context, Required extends boolean = true>() {\n\tfunction command<\n\t\tconst Input extends NeutralSchema,\n\t\tconst Result extends NeutralSchema,\n\t\tconst Wire extends NeutralSchema,\n\t\tconst Replay extends NeutralSchema,\n\t\tconst Implementation extends object,\n\t>(\n\t\timplementation: Implementation & {\n\t\t\tinput: Input\n\t\t\tresult: Result\n\t\t\tclassification: string\n\t\t\treplayResult?: Replay &\n\t\t\t\t(ContractOutput<Replay> extends ContractOutput<Result> ? unknown : never)\n\t\t\twire?: { schema: Wire; project: (result: ContractOutput<Result>) => ContractInput<Wire> }\n\t\t} & Definition<Context, { input: Input; result: Result }> &\n\t\t\tCommandRules<Context, { input: Input; result: Result }, true, Required>,\n\t) {\n\t\t// SAFETY: this type-only evidence records the complete helper-checked definition.\n\t\treturn implementation as CheckedDefinition<Context, typeof implementation>\n\t}\n\tfunction query<\n\t\tconst Input extends NeutralSchema,\n\t\tconst Result extends NeutralSchema,\n\t\tconst Wire extends NeutralSchema,\n\t\tconst Implementation extends object,\n\t>(\n\t\timplementation: Implementation & {\n\t\t\tinput: Input\n\t\t\tresult: Result\n\t\t\tclassification?: string\n\t\t\twire?: { schema: Wire; project: (result: ContractOutput<Result>) => ContractInput<Wire> }\n\t\t} & Definition<Context, { input: Input; result: Result }> &\n\t\t\tCommandRules<Context, { input: Input; result: Result }, false, true>,\n\t) {\n\t\t// SAFETY: this type-only evidence records the complete helper-checked definition.\n\t\treturn implementation as CheckedDefinition<Context, typeof implementation>\n\t}\n\treturn { command, query }\n}\nexport type InlineFactory<Context, Required extends boolean> = ReturnType<\n\ttypeof operationFactory<Context, Required>\n>\n"],"mappings":"yDA+JA,SAAgBA,EAKd,EAAkB,EAAsE,CACzF,IAAMC,EAAUC,EAAcC,CAAO,EAErC,MAAO,EAAGC,EAAU,UAAY,SAAUH,CAAQ,CAMnD,CACA,SAAgBI,GAA6D,CAC5E,SAASD,EAOR,EASC,CAED,OAAOE,CACR,CACA,SAASC,EAMR,EAOC,CAED,OAAOD,CACR,CACA,MAAO,CAAE,UAAS,OAAM,CACzB"}
|
package/docs/domain-contracts.md
CHANGED
|
@@ -6,7 +6,7 @@ commands and queries. Either section and the error contract may be omitted.
|
|
|
6
6
|
|
|
7
7
|
The regular registry uses `createFoundation` from `cvx-kit`; the Effect registry
|
|
8
8
|
uses `createEffectFoundation` from `cvx-kit/effect`. Both accept the same contract
|
|
9
|
-
and
|
|
9
|
+
and handler-first implementation helpers. Existing inline Effect definitions and the
|
|
10
10
|
older `new Foundation(...)` constructors continue to work.
|
|
11
11
|
|
|
12
12
|
```ts
|
|
@@ -53,17 +53,14 @@ const commands = Command({
|
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
55
|
operations: ({ command }) => ({
|
|
56
|
-
'tasks.create': command
|
|
57
|
-
'tasks.close': command
|
|
58
|
-
handler: (input) => input.id.length > 0,
|
|
59
|
-
audit: () => null,
|
|
60
|
-
}),
|
|
56
|
+
'tasks.create': command.handler((input) => input + 1),
|
|
57
|
+
'tasks.close': command.handler((input) => input.id.length > 0, { audit: () => null }),
|
|
61
58
|
}),
|
|
62
59
|
})
|
|
63
60
|
const queries = Query({
|
|
64
61
|
contract,
|
|
65
62
|
context: (host: { actorId: string }) => host,
|
|
66
|
-
operations: ({ query }) => ({ 'tasks.get': query
|
|
63
|
+
operations: ({ query }) => ({ 'tasks.get': query.handler((input) => input) }),
|
|
67
64
|
})
|
|
68
65
|
const created = await commands.exec('tasks.create', '2', { actorId: 'actor' })
|
|
69
66
|
const count = await queries.withContext({ actorId: 'actor' }).exec('tasks.get', created.count)
|
|
@@ -71,15 +68,51 @@ void count
|
|
|
71
68
|
```
|
|
72
69
|
|
|
73
70
|
Each map must implement exactly its declared keys, including maps supplied through
|
|
74
|
-
variables.
|
|
71
|
+
variables. The object key selects the contract entry and infers the handler and
|
|
72
|
+
option callback types through `command.handler(fn, options?)` or
|
|
73
|
+
`query.handler(fn, options?)`. Keep the map directly in `operations` for contextual
|
|
74
|
+
inference. For separately assembled maps, the existing named helpers provide explicit
|
|
75
|
+
contract selection without relying on the enclosing object for inference. Input, result,
|
|
75
76
|
classification, replayResult, and wire come from the declaration and cannot be
|
|
76
77
|
overridden in the implementation. Construction snapshots operation records and
|
|
77
78
|
map membership without cloning validators or running user callbacks.
|
|
78
79
|
|
|
80
|
+
Options include guard, middleware, metadata, and permission; commands also allow
|
|
81
|
+
prepare, aggregates, and audit overrides. Options are optional when a root audit
|
|
82
|
+
is configured; commands without one require an audit in their options. Existing
|
|
83
|
+
`command['tasks.create']({ handler, ...options })` and named query helpers remain
|
|
84
|
+
supported. Named helpers retain their exact key binding.
|
|
85
|
+
|
|
79
86
|
The handler receives decoded input, returns the result schema's accepted input,
|
|
80
87
|
and execution returns its decoded result. Normal handlers and hooks return values
|
|
81
88
|
or Promises. Effect handlers and hooks may also return Effects; their error and
|
|
82
|
-
service channels remain part of the selected operation's type.
|
|
89
|
+
service channels remain part of the selected operation's type. For example, with
|
|
90
|
+
`Command` from `createEffectFoundation`:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { Effect } from 'effect'
|
|
94
|
+
import { createEffectFoundation } from 'cvx-kit/effect'
|
|
95
|
+
|
|
96
|
+
const effectFoundation = createEffectFoundation({
|
|
97
|
+
observability: {
|
|
98
|
+
enabled: false,
|
|
99
|
+
classifyError: () => ({ outcome: 'failed', errorCode: 'FAILED' }),
|
|
100
|
+
},
|
|
101
|
+
writeAudit: (_host: { actorId: string }) => undefined,
|
|
102
|
+
})
|
|
103
|
+
const effectCommands = effectFoundation.Command({
|
|
104
|
+
contract,
|
|
105
|
+
context: (host: { actorId: string }) => host,
|
|
106
|
+
audit: () => null,
|
|
107
|
+
operations: ({ command }) => ({
|
|
108
|
+
'tasks.create': command.handler((input) => Effect.succeed(input + 1)),
|
|
109
|
+
'tasks.close': command.handler((input) => Effect.succeed(input.id.length > 0)),
|
|
110
|
+
}),
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The same contract owns both implementations; selecting a different adapter does
|
|
115
|
+
not require repeating schemas.
|
|
83
116
|
|
|
84
117
|
For independent wire projections, use the existing `operationContract` helper
|
|
85
118
|
inside a domain declaration. It infers the projector's parameter from the result
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cvx-kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Reusable Convex application kit: foundation kernels, approvals component, zod table boundaries, WorkOS-backed auth function constructors, and audited command protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"component",
|
|
@@ -29,6 +29,7 @@ const extraTypeFixtures = [
|
|
|
29
29
|
join(root, 'README.md'),
|
|
30
30
|
join(root, 'src/docs/effect.md'),
|
|
31
31
|
join(root, 'src/docs/commands.md'),
|
|
32
|
+
join(root, 'src/docs/domain-contracts.md'),
|
|
32
33
|
join(root, 'src/docs/command-context.md'),
|
|
33
34
|
join(root, 'src/docs/commands-legacy.md'),
|
|
34
35
|
join(root, 'src/docs/auth.md'),
|
|
@@ -405,6 +406,7 @@ try {
|
|
|
405
406
|
for (const filename of [
|
|
406
407
|
'effect-foundation-types.ts',
|
|
407
408
|
'domain-effect-types.ts',
|
|
409
|
+
'domain-handler-types.ts',
|
|
408
410
|
'domain-exactness-types.ts',
|
|
409
411
|
'effect-api-types.ts',
|
|
410
412
|
'effect-api-zod-types.ts',
|