cvx-kit 0.0.1
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/LICENSE +21 -0
- package/README.md +200 -0
- package/dist/_virtual/_rolldown/runtime.mjs +1 -0
- package/dist/auth.d.mts +353 -0
- package/dist/auth.mjs +2 -0
- package/dist/auth.mjs.map +1 -0
- package/dist/components/approvals/_generated/api.d.mts +47 -0
- package/dist/components/approvals/_generated/api.mjs +2 -0
- package/dist/components/approvals/_generated/api.mjs.map +1 -0
- package/dist/components/approvals/_generated/component.d.mts +297 -0
- package/dist/components/approvals/_generated/component.mjs +1 -0
- package/dist/components/approvals/_generated/dataModel.d.mts +41 -0
- package/dist/components/approvals/_generated/dataModel.mjs +1 -0
- package/dist/components/approvals/_generated/server.d.mts +116 -0
- package/dist/components/approvals/_generated/server.mjs +2 -0
- package/dist/components/approvals/_generated/server.mjs.map +1 -0
- package/dist/components/approvals/audit.d.mts +40 -0
- package/dist/components/approvals/audit.mjs +2 -0
- package/dist/components/approvals/audit.mjs.map +1 -0
- package/dist/components/approvals/client.d.mts +98 -0
- package/dist/components/approvals/client.mjs +2 -0
- package/dist/components/approvals/client.mjs.map +1 -0
- package/dist/components/approvals/constants.d.mts +31 -0
- package/dist/components/approvals/constants.mjs +2 -0
- package/dist/components/approvals/constants.mjs.map +1 -0
- package/dist/components/approvals/convex.config.d.mts +5 -0
- package/dist/components/approvals/convex.config.mjs +2 -0
- package/dist/components/approvals/convex.config.mjs.map +1 -0
- package/dist/components/approvals/decisions.d.mts +61 -0
- package/dist/components/approvals/decisions.mjs +2 -0
- package/dist/components/approvals/decisions.mjs.map +1 -0
- package/dist/components/approvals/functions.d.mts +9 -0
- package/dist/components/approvals/functions.mjs +2 -0
- package/dist/components/approvals/functions.mjs.map +1 -0
- package/dist/components/approvals/requests.d.mts +323 -0
- package/dist/components/approvals/requests.mjs +2 -0
- package/dist/components/approvals/requests.mjs.map +1 -0
- package/dist/components/approvals/schema.d.mts +376 -0
- package/dist/components/approvals/schema.mjs +2 -0
- package/dist/components/approvals/schema.mjs.map +1 -0
- package/dist/components/approvals/validators.d.mts +302 -0
- package/dist/components/approvals/validators.mjs +2 -0
- package/dist/components/approvals/validators.mjs.map +1 -0
- package/dist/components/approvals/workflow.d.mts +11 -0
- package/dist/components/approvals/workflow.mjs +2 -0
- package/dist/components/approvals/workflow.mjs.map +1 -0
- package/dist/components/approvals/workflow_steps.d.mts +83 -0
- package/dist/components/approvals/workflow_steps.mjs +2 -0
- package/dist/components/approvals/workflow_steps.mjs.map +1 -0
- package/dist/components/foundation/_generated/api.d.mts +40 -0
- package/dist/components/foundation/_generated/api.mjs +2 -0
- package/dist/components/foundation/_generated/api.mjs.map +1 -0
- package/dist/components/foundation/_generated/component.d.mts +21 -0
- package/dist/components/foundation/_generated/component.mjs +1 -0
- package/dist/components/foundation/_generated/dataModel.d.mts +41 -0
- package/dist/components/foundation/_generated/dataModel.mjs +1 -0
- package/dist/components/foundation/_generated/server.d.mts +116 -0
- package/dist/components/foundation/_generated/server.mjs +2 -0
- package/dist/components/foundation/_generated/server.mjs.map +1 -0
- package/dist/components/foundation/client.d.mts +93 -0
- package/dist/components/foundation/client.mjs +2 -0
- package/dist/components/foundation/client.mjs.map +1 -0
- package/dist/components/foundation/convex.config.d.mts +5 -0
- package/dist/components/foundation/convex.config.mjs +2 -0
- package/dist/components/foundation/convex.config.mjs.map +1 -0
- package/dist/components/foundation/functions.d.mts +8 -0
- package/dist/components/foundation/functions.mjs +2 -0
- package/dist/components/foundation/functions.mjs.map +1 -0
- package/dist/components/foundation/modules/command/command.d.mts +47 -0
- package/dist/components/foundation/modules/command/command.mjs +2 -0
- package/dist/components/foundation/modules/command/command.mjs.map +1 -0
- package/dist/components/foundation/modules/observability/observability.d.mts +31 -0
- package/dist/components/foundation/modules/observability/observability.mjs +2 -0
- package/dist/components/foundation/modules/observability/observability.mjs.map +1 -0
- package/dist/components/foundation/modules/query/query.d.mts +24 -0
- package/dist/components/foundation/modules/query/query.mjs +2 -0
- package/dist/components/foundation/modules/query/query.mjs.map +1 -0
- package/dist/components/foundation/result.d.mts +27 -0
- package/dist/components/foundation/result.mjs +2 -0
- package/dist/components/foundation/result.mjs.map +1 -0
- package/dist/components/foundation/schema.d.mts +6 -0
- package/dist/components/foundation/schema.mjs +2 -0
- package/dist/components/foundation/schema.mjs.map +1 -0
- package/dist/components/foundation/telemetry.d.mts +9 -0
- package/dist/components/foundation/telemetry.mjs +2 -0
- package/dist/components/foundation/telemetry.mjs.map +1 -0
- package/dist/errors.d.mts +24 -0
- package/dist/errors.mjs +2 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +1 -0
- package/dist/triggers.d.mts +27 -0
- package/dist/triggers.mjs +2 -0
- package/dist/triggers.mjs.map +1 -0
- package/dist/zod-table.d.mts +124 -0
- package/dist/zod-table.mjs +2 -0
- package/dist/zod-table.mjs.map +1 -0
- package/package.json +108 -0
- package/src/auth.ts +360 -0
- package/src/components/approvals/_generated/api.ts +69 -0
- package/src/components/approvals/_generated/component.ts +335 -0
- package/src/components/approvals/_generated/dataModel.ts +60 -0
- package/src/components/approvals/_generated/server.ts +156 -0
- package/src/components/approvals/audit.ts +148 -0
- package/src/components/approvals/client.ts +321 -0
- package/src/components/approvals/constants.ts +51 -0
- package/src/components/approvals/convex.config.ts +10 -0
- package/src/components/approvals/decisions.ts +376 -0
- package/src/components/approvals/functions.ts +27 -0
- package/src/components/approvals/requests.ts +240 -0
- package/src/components/approvals/schema.ts +23 -0
- package/src/components/approvals/validators.ts +272 -0
- package/src/components/approvals/workflow.ts +204 -0
- package/src/components/approvals/workflow_steps.ts +189 -0
- package/src/components/foundation/_generated/api.ts +62 -0
- package/src/components/foundation/_generated/component.ts +29 -0
- package/src/components/foundation/_generated/dataModel.ts +60 -0
- package/src/components/foundation/_generated/server.ts +156 -0
- package/src/components/foundation/client.ts +190 -0
- package/src/components/foundation/convex.config.ts +3 -0
- package/src/components/foundation/functions.ts +10 -0
- package/src/components/foundation/modules/command/__tests__/command.test.ts +106 -0
- package/src/components/foundation/modules/command/command.ts +154 -0
- package/src/components/foundation/modules/observability/__tests__/observability.test.ts +79 -0
- package/src/components/foundation/modules/observability/observability.ts +95 -0
- package/src/components/foundation/modules/query/__tests__/query.test.ts +25 -0
- package/src/components/foundation/modules/query/query.ts +47 -0
- package/src/components/foundation/result.ts +77 -0
- package/src/components/foundation/schema.ts +4 -0
- package/src/components/foundation/telemetry.ts +23 -0
- package/src/errors.ts +25 -0
- package/src/index.ts +41 -0
- package/src/test.ts +36 -0
- package/src/triggers.ts +90 -0
- package/src/zod-table.ts +197 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
declare namespace command_d_exports {
|
|
2
|
+
export { Command, CommandExecution, CommandInput, CommandRegistry, CommandResult, Parseable };
|
|
3
|
+
}
|
|
4
|
+
type Parseable<Output> = Readonly<{
|
|
5
|
+
parse: (value: unknown) => Output;
|
|
6
|
+
}>;
|
|
7
|
+
type CommandRegistry = Readonly<Record<string, CommandDefinition>>;
|
|
8
|
+
type CommandInput<Registry extends CommandRegistry, Key extends Operation<Registry>> = Parsed<Registry[Key]['command']>;
|
|
9
|
+
type CommandResult<Registry extends CommandRegistry, Key extends Operation<Registry>> = Parsed<Registry[Key]['result']>;
|
|
10
|
+
type CommandExecution<Context, Registry extends CommandRegistry, Key extends Operation<Registry>> = Readonly<{
|
|
11
|
+
context: Context;
|
|
12
|
+
operation: Key;
|
|
13
|
+
definition: Registry[Key];
|
|
14
|
+
command: CommandInput<Registry, Key>;
|
|
15
|
+
parseResult: (value: unknown) => CommandResult<Registry, Key>;
|
|
16
|
+
run: () => Promise<CommandResult<Registry, Key>>;
|
|
17
|
+
}>;
|
|
18
|
+
type CommandDefinition = Readonly<{
|
|
19
|
+
command: Parseable<unknown>;
|
|
20
|
+
result: Parseable<unknown>;
|
|
21
|
+
}>;
|
|
22
|
+
type Operation<Registry extends CommandRegistry> = Extract<keyof Registry, string>;
|
|
23
|
+
type Parsed<Schema> = Schema extends Parseable<infer Output> ? Output : never;
|
|
24
|
+
type MaybePromise<Value> = Value | Promise<Value>;
|
|
25
|
+
type Execute<Context, Registry extends CommandRegistry> = <Key extends Operation<Registry>>(execution: CommandExecution<Context, Registry, Key>) => Promise<CommandResult<Registry, Key>>;
|
|
26
|
+
type FixedExecutor<Context, Registry extends CommandRegistry, Key extends Operation<Registry>> = Readonly<{
|
|
27
|
+
operation: Key;
|
|
28
|
+
handler: (context: Context, command: CommandInput<Registry, Key>) => MaybePromise<CommandResult<Registry, Key>>;
|
|
29
|
+
}>;
|
|
30
|
+
type DynamicExecutor<Context, Registry extends CommandRegistry, Dispatcher, Key extends Operation<Registry>> = Readonly<{
|
|
31
|
+
dispatcher: Parseable<Dispatcher>;
|
|
32
|
+
select: (dispatcher: Dispatcher) => Key;
|
|
33
|
+
handler: (context: Context, command: CommandInput<Registry, Key>) => MaybePromise<CommandResult<Registry, Key>>;
|
|
34
|
+
}>;
|
|
35
|
+
/** Generic command kernel. Host policy is injected by the owning domain. */
|
|
36
|
+
declare class Command<Context, const Registry extends CommandRegistry> {
|
|
37
|
+
#private;
|
|
38
|
+
constructor(configuration: {
|
|
39
|
+
readonly operations: Registry;
|
|
40
|
+
readonly execute: Execute<Context, Registry>;
|
|
41
|
+
});
|
|
42
|
+
exec<const Key extends Operation<Registry>>(executor: FixedExecutor<Context, Registry, Key>): (context: Context, command: CommandInput<Registry, Key>) => Promise<CommandResult<Registry, Key>>;
|
|
43
|
+
exec<Dispatcher, const Key extends Operation<Registry>>(executor: DynamicExecutor<Context, Registry, Dispatcher, Key>): (context: Context, command: Dispatcher) => Promise<CommandResult<Registry, Key>>;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { Command, CommandExecution, CommandInput, CommandRegistry, CommandResult, Parseable, command_d_exports };
|
|
47
|
+
//# sourceMappingURL=command.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=class extends Error{code=`COMMAND_OPERATION_NOT_CONFIGURED`;name=`CommandConfigurationError`;constructor(){super(`The selected command operation is not configured`)}},t=class{#e;#t;constructor(e){this.#e=e.operations,this.#t=e.execute}exec(t){return async(n,r)=>{let i=`operation`in t?{operation:t.operation,value:r}:(()=>{let e=t.dispatcher.parse(r);return{operation:t.select(e),value:e}})();if(!Object.prototype.hasOwnProperty.call(this.#e,i.operation))throw new e;let a=i.operation,o=this.#e[a],s=o.command.parse(i.value),c=e=>o.result.parse(e),l=t.handler;return this.#t({context:n,operation:a,definition:o,command:s,parseResult:c,run:async()=>c(await l(n,s))})}}};export{t as Command};
|
|
2
|
+
//# sourceMappingURL=command.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.mjs","names":["#operations","#execute"],"sources":["../../../../../src/components/foundation/modules/command/command.ts"],"sourcesContent":["export type Parseable<Output> = Readonly<{ parse: (value: unknown) => Output }>\n\nexport type CommandRegistry = Readonly<Record<string, CommandDefinition>>\n\nexport type CommandInput<\n\tRegistry extends CommandRegistry,\n\tKey extends Operation<Registry>,\n> = Parsed<Registry[Key]['command']>\n\nexport type CommandResult<\n\tRegistry extends CommandRegistry,\n\tKey extends Operation<Registry>,\n> = Parsed<Registry[Key]['result']>\n\nexport type CommandExecution<\n\tContext,\n\tRegistry extends CommandRegistry,\n\tKey extends Operation<Registry>,\n> = Readonly<{\n\tcontext: Context\n\toperation: Key\n\tdefinition: Registry[Key]\n\tcommand: CommandInput<Registry, Key>\n\tparseResult: (value: unknown) => CommandResult<Registry, Key>\n\trun: () => Promise<CommandResult<Registry, Key>>\n}>\n\ntype CommandDefinition = Readonly<{\n\tcommand: Parseable<unknown>\n\tresult: Parseable<unknown>\n}>\n\ntype Operation<Registry extends CommandRegistry> = Extract<\n\tkeyof Registry,\n\tstring\n>\ntype Parsed<Schema> = Schema extends Parseable<infer Output> ? Output : never\ntype MaybePromise<Value> = Value | Promise<Value>\ntype Execute<Context, Registry extends CommandRegistry> = <\n\tKey extends Operation<Registry>,\n>(\n\texecution: CommandExecution<Context, Registry, Key>,\n) => Promise<CommandResult<Registry, Key>>\n\ntype FixedExecutor<\n\tContext,\n\tRegistry extends CommandRegistry,\n\tKey extends Operation<Registry>,\n> = Readonly<{\n\toperation: Key\n\thandler: (\n\t\tcontext: Context,\n\t\tcommand: CommandInput<Registry, Key>,\n\t) => MaybePromise<CommandResult<Registry, Key>>\n}>\n\ntype DynamicExecutor<\n\tContext,\n\tRegistry extends CommandRegistry,\n\tDispatcher,\n\tKey extends Operation<Registry>,\n> = Readonly<{\n\tdispatcher: Parseable<Dispatcher>\n\tselect: (dispatcher: Dispatcher) => Key\n\thandler: (\n\t\tcontext: Context,\n\t\tcommand: CommandInput<Registry, Key>,\n\t) => MaybePromise<CommandResult<Registry, Key>>\n}>\n\nclass CommandConfigurationError extends Error {\n\treadonly code = 'COMMAND_OPERATION_NOT_CONFIGURED'\n\treadonly name = 'CommandConfigurationError'\n\n\tconstructor() {\n\t\tsuper('The selected command operation is not configured')\n\t}\n}\n\n/** Generic command kernel. Host policy is injected by the owning domain. */\nexport class Command<Context, const Registry extends CommandRegistry> {\n\treadonly #operations: Registry\n\treadonly #execute: Execute<Context, Registry>\n\n\tconstructor(configuration: {\n\t\treadonly operations: Registry\n\t\treadonly execute: Execute<Context, Registry>\n\t}) {\n\t\tthis.#operations = configuration.operations\n\t\tthis.#execute = configuration.execute\n\t}\n\n\texec<const Key extends Operation<Registry>>(\n\t\texecutor: FixedExecutor<Context, Registry, Key>,\n\t): (\n\t\tcontext: Context,\n\t\tcommand: CommandInput<Registry, Key>,\n\t) => Promise<CommandResult<Registry, Key>>\n\texec<Dispatcher, const Key extends Operation<Registry>>(\n\t\texecutor: DynamicExecutor<Context, Registry, Dispatcher, Key>,\n\t): (\n\t\tcontext: Context,\n\t\tcommand: Dispatcher,\n\t) => Promise<CommandResult<Registry, Key>>\n\texec(\n\t\texecutor:\n\t\t\t| FixedExecutor<Context, Registry, Operation<Registry>>\n\t\t\t| DynamicExecutor<Context, Registry, unknown, Operation<Registry>>,\n\t) {\n\t\treturn async (context: Context, value: unknown) => {\n\t\t\tconst selected =\n\t\t\t\t'operation' in executor\n\t\t\t\t\t? { operation: executor.operation, value }\n\t\t\t\t\t: (() => {\n\t\t\t\t\t\t\tconst dispatcher = executor.dispatcher.parse(value)\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\toperation: executor.select(dispatcher),\n\t\t\t\t\t\t\t\tvalue: dispatcher,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})()\n\t\t\tif (\n\t\t\t\t!Object.prototype.hasOwnProperty.call(\n\t\t\t\t\tthis.#operations,\n\t\t\t\t\tselected.operation,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthrow new CommandConfigurationError()\n\t\t\t}\n\t\t\tconst operation = selected.operation as Operation<Registry>\n\t\t\tconst definition = this.#operations[operation]\n\t\t\tconst command = definition.command.parse(selected.value) as CommandInput<\n\t\t\t\tRegistry,\n\t\t\t\tOperation<Registry>\n\t\t\t>\n\t\t\tconst parseResult = (result: unknown) =>\n\t\t\t\tdefinition.result.parse(result) as CommandResult<\n\t\t\t\t\tRegistry,\n\t\t\t\t\tOperation<Registry>\n\t\t\t\t>\n\t\t\tconst handler = executor.handler as (\n\t\t\t\tcontext: Context,\n\t\t\t\tcommand: CommandInput<Registry, Operation<Registry>>,\n\t\t\t) => MaybePromise<CommandResult<Registry, Operation<Registry>>>\n\t\t\treturn this.#execute({\n\t\t\t\tcontext,\n\t\t\t\toperation,\n\t\t\t\tdefinition,\n\t\t\t\tcommand,\n\t\t\t\tparseResult,\n\t\t\t\trun: async () => parseResult(await handler(context, command)),\n\t\t\t})\n\t\t}\n\t}\n}\n"],"mappings":"AAsEA,IAAM,EAAN,cAAwC,KAAM,CAC7C,KAAgB,mCAChB,KAAgB,4BAEhB,aAAc,CACb,MAAM,kDAAkD,CACzD,CACD,EAGa,EAAb,KAAsE,CACrE,GACA,GAEA,YAAY,EAGT,CACF,KAAKA,GAAc,EAAc,WACjC,KAAKC,GAAW,EAAc,OAC/B,CAcA,KACC,EAGC,CACD,OAAO,MAAO,EAAkB,IAAmB,CAClD,IAAM,EACL,cAAe,EACZ,CAAE,UAAW,EAAS,UAAW,OAAM,OAChC,CACP,IAAM,EAAa,EAAS,WAAW,MAAM,CAAK,EAClD,MAAO,CACN,UAAW,EAAS,OAAO,CAAU,EACrC,MAAO,CACR,CACD,EAAA,CAAG,EACN,GACC,CAAC,OAAO,UAAU,eAAe,KAChC,KAAKD,GACL,EAAS,SACV,EAEA,MAAM,IAAI,EAEX,IAAM,EAAY,EAAS,UACrB,EAAa,KAAKA,GAAY,GAC9B,EAAU,EAAW,QAAQ,MAAM,EAAS,KAAK,EAIjD,EAAe,GACpB,EAAW,OAAO,MAAM,CAAM,EAIzB,EAAU,EAAS,QAIzB,OAAO,KAAKC,GAAS,CACpB,UACA,YACA,aACA,UACA,cACA,IAAK,SAAY,EAAY,MAAM,EAAQ,EAAS,CAAO,CAAC,CAC7D,CAAC,CACF,CACD,CACD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
declare namespace observability_d_exports {
|
|
2
|
+
export { CommandObservation, Observability, ObservabilityOptions };
|
|
3
|
+
}
|
|
4
|
+
type CommandObservation = Readonly<{
|
|
5
|
+
operation: string;
|
|
6
|
+
classification: string;
|
|
7
|
+
outcome: 'completed' | 'denied' | 'failed';
|
|
8
|
+
errorCode?: string;
|
|
9
|
+
durationMs: number;
|
|
10
|
+
}>;
|
|
11
|
+
type ObservabilityOptions = Readonly<{
|
|
12
|
+
enabled?: boolean | (() => boolean);
|
|
13
|
+
classifyError: (error: unknown) => Readonly<{
|
|
14
|
+
outcome: 'denied' | 'failed';
|
|
15
|
+
errorCode: string;
|
|
16
|
+
}>;
|
|
17
|
+
emit?: (observation: CommandObservation) => void;
|
|
18
|
+
clock?: () => number;
|
|
19
|
+
}>;
|
|
20
|
+
/** Payload-free command telemetry that cannot change command behavior. */
|
|
21
|
+
declare class Observability {
|
|
22
|
+
#private;
|
|
23
|
+
constructor(options: ObservabilityOptions);
|
|
24
|
+
observe<Result>(activation: Readonly<{
|
|
25
|
+
operation: string;
|
|
26
|
+
classification: string;
|
|
27
|
+
}>, execute: () => Result | Promise<Result>): Promise<Result>;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { CommandObservation, Observability, ObservabilityOptions, observability_d_exports };
|
|
31
|
+
//# sourceMappingURL=observability.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=/^[A-Za-z][A-Za-z0-9_.-]{0,159}$/,t=/^[A-Z][A-Z0-9_]{0,95}$/;var n=class{#e;constructor(e){this.#e=e}async observe(e,t){let n=this.#n();try{let r=await t();return this.#t({...e,outcome:`completed`,durationMs:this.#r(n)}),r}catch(t){try{this.#t({...e,...this.#e.classifyError(t),durationMs:this.#r(n)})}catch{}throw t}}#t(n){try{if((typeof this.#e.enabled==`function`?this.#e.enabled():this.#e.enabled)!==!0||!e.test(n.operation)||!e.test(n.classification)||n.errorCode!==void 0&&!t.test(n.errorCode))return;if(this.#e.emit){this.#e.emit(Object.freeze(n));return}console.info(JSON.stringify({event:`command.execution`,...n}))}catch{}}#n(){try{return this.#e.clock?.()??Date.now()}catch{return Date.now()}}#r(e){return Math.max(0,Math.min(6e5,this.#n()-e))}};export{n as Observability};
|
|
2
|
+
//# sourceMappingURL=observability.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observability.mjs","names":["#options","#now","#emit","#duration"],"sources":["../../../../../src/components/foundation/modules/observability/observability.ts"],"sourcesContent":["export type CommandObservation = Readonly<{\n\toperation: string\n\tclassification: string\n\toutcome: 'completed' | 'denied' | 'failed'\n\terrorCode?: string\n\tdurationMs: number\n}>\n\nexport type ObservabilityOptions = Readonly<{\n\tenabled?: boolean | (() => boolean)\n\tclassifyError: (error: unknown) => Readonly<{\n\t\toutcome: 'denied' | 'failed'\n\t\terrorCode: string\n\t}>\n\temit?: (observation: CommandObservation) => void\n\tclock?: () => number\n}>\n\nconst identifier = /^[A-Za-z][A-Za-z0-9_.-]{0,159}$/\nconst errorCode = /^[A-Z][A-Z0-9_]{0,95}$/\n\n/** Payload-free command telemetry that cannot change command behavior. */\nexport class Observability {\n\treadonly #options: ObservabilityOptions\n\n\tconstructor(options: ObservabilityOptions) {\n\t\tthis.#options = options\n\t}\n\n\tasync observe<Result>(\n\t\tactivation: Readonly<{ operation: string; classification: string }>,\n\t\texecute: () => Result | Promise<Result>,\n\t): Promise<Result> {\n\t\tconst started = this.#now()\n\t\ttry {\n\t\t\tconst result = await execute()\n\t\t\tthis.#emit({\n\t\t\t\t...activation,\n\t\t\t\toutcome: 'completed',\n\t\t\t\tdurationMs: this.#duration(started),\n\t\t\t})\n\t\t\treturn result\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tthis.#emit({\n\t\t\t\t\t...activation,\n\t\t\t\t\t...this.#options.classifyError(error),\n\t\t\t\t\tdurationMs: this.#duration(started),\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\t// Preserve the original command failure when telemetry fails.\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t#emit(observation: CommandObservation): void {\n\t\ttry {\n\t\t\tconst enabled =\n\t\t\t\ttypeof this.#options.enabled === 'function'\n\t\t\t\t\t? this.#options.enabled()\n\t\t\t\t\t: this.#options.enabled\n\t\t\tif (\n\t\t\t\tenabled !== true ||\n\t\t\t\t!identifier.test(observation.operation) ||\n\t\t\t\t!identifier.test(observation.classification) ||\n\t\t\t\t(observation.errorCode !== undefined &&\n\t\t\t\t\t!errorCode.test(observation.errorCode))\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.#options.emit) {\n\t\t\t\tthis.#options.emit(Object.freeze(observation))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconsole.info(\n\t\t\t\tJSON.stringify({ event: 'command.execution', ...observation }),\n\t\t\t)\n\t\t} catch {\n\t\t\t// Observability is intentionally behaviorally inert.\n\t\t}\n\t}\n\n\t#now(): number {\n\t\ttry {\n\t\t\treturn this.#options.clock?.() ?? Date.now()\n\t\t} catch {\n\t\t\treturn Date.now()\n\t\t}\n\t}\n\n\t#duration(started: number): number {\n\t\treturn Math.max(0, Math.min(600_000, this.#now() - started))\n\t}\n}\n"],"mappings":"AAkBA,MAAM,EAAa,kCACb,EAAY,yBAGlB,IAAa,EAAb,KAA2B,CAC1B,GAEA,YAAY,EAA+B,CAC1C,KAAKA,GAAW,CACjB,CAEA,MAAM,QACL,EACA,EACkB,CAClB,IAAM,EAAU,KAAKC,GAAK,EAC1B,GAAI,CACH,IAAM,EAAS,MAAM,EAAQ,EAM7B,OALA,KAAKC,GAAM,CACV,GAAG,EACH,QAAS,YACT,WAAY,KAAKC,GAAU,CAAO,CACnC,CAAC,EACM,CACR,OAAS,EAAO,CACf,GAAI,CACH,KAAKD,GAAM,CACV,GAAG,EACH,GAAG,KAAKF,GAAS,cAAc,CAAK,EACpC,WAAY,KAAKG,GAAU,CAAO,CACnC,CAAC,CACF,MAAQ,CAER,CACA,MAAM,CACP,CACD,CAEA,GAAM,EAAuC,CAC5C,GAAI,CAKH,IAHC,OAAO,KAAKH,GAAS,SAAY,WAC9B,KAAKA,GAAS,QAAQ,EACtB,KAAKA,GAAS,WAEL,IACZ,CAAC,EAAW,KAAK,EAAY,SAAS,GACtC,CAAC,EAAW,KAAK,EAAY,cAAc,GAC1C,EAAY,YAAc,IAAA,IAC1B,CAAC,EAAU,KAAK,EAAY,SAAS,EAEtC,OAED,GAAI,KAAKA,GAAS,KAAM,CACvB,KAAKA,GAAS,KAAK,OAAO,OAAO,CAAW,CAAC,EAC7C,MACD,CACA,QAAQ,KACP,KAAK,UAAU,CAAE,MAAO,oBAAqB,GAAG,CAAY,CAAC,CAC9D,CACD,MAAQ,CAER,CACD,CAEA,IAAe,CACd,GAAI,CACH,OAAO,KAAKA,GAAS,QAAQ,GAAK,KAAK,IAAI,CAC5C,MAAQ,CACP,OAAO,KAAK,IAAI,CACjB,CACD,CAEA,GAAU,EAAyB,CAClC,OAAO,KAAK,IAAI,EAAG,KAAK,IAAI,IAAS,KAAKC,GAAK,EAAI,CAAO,CAAC,CAC5D,CACD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare namespace query_d_exports {
|
|
2
|
+
export { Query, QueryExecution };
|
|
3
|
+
}
|
|
4
|
+
type QueryExecution<Context, Metadata, Result> = Readonly<{
|
|
5
|
+
context: Context;
|
|
6
|
+
metadata: Metadata;
|
|
7
|
+
run: () => Promise<Result>;
|
|
8
|
+
}>;
|
|
9
|
+
type MaybePromise<Value> = Value | Promise<Value>;
|
|
10
|
+
/** Generic query kernel. Authorization remains an injected host policy. */
|
|
11
|
+
declare class Query<Context, Defaults extends object> {
|
|
12
|
+
#private;
|
|
13
|
+
constructor(configuration: {
|
|
14
|
+
readonly defaults: Defaults;
|
|
15
|
+
readonly execute: <Metadata extends object, Result>(execution: QueryExecution<Context, Defaults & Metadata, Result>) => Promise<Result>;
|
|
16
|
+
});
|
|
17
|
+
exec<Arguments extends readonly unknown[], Result, Metadata extends object = object>(executor: {
|
|
18
|
+
readonly metadata?: Metadata;
|
|
19
|
+
readonly handler: (context: Context, ...args: Arguments) => MaybePromise<Result>;
|
|
20
|
+
}): (context: Context, ...args: Arguments) => Promise<Result>;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { Query, QueryExecution, query_d_exports };
|
|
24
|
+
//# sourceMappingURL=query.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.mjs","names":["#defaults","#execute"],"sources":["../../../../../src/components/foundation/modules/query/query.ts"],"sourcesContent":["export type QueryExecution<Context, Metadata, Result> = Readonly<{\n\tcontext: Context\n\tmetadata: Metadata\n\trun: () => Promise<Result>\n}>\n\ntype MaybePromise<Value> = Value | Promise<Value>\n\n/** Generic query kernel. Authorization remains an injected host policy. */\nexport class Query<Context, Defaults extends object> {\n\treadonly #defaults: Defaults\n\treadonly #execute: <Metadata extends object, Result>(\n\t\texecution: QueryExecution<Context, Defaults & Metadata, Result>,\n\t) => Promise<Result>\n\n\tconstructor(configuration: {\n\t\treadonly defaults: Defaults\n\t\treadonly execute: <Metadata extends object, Result>(\n\t\t\texecution: QueryExecution<Context, Defaults & Metadata, Result>,\n\t\t) => Promise<Result>\n\t}) {\n\t\tthis.#defaults = configuration.defaults\n\t\tthis.#execute = configuration.execute\n\t}\n\n\texec<\n\t\tArguments extends readonly unknown[],\n\t\tResult,\n\t\tMetadata extends object = object,\n\t>(executor: {\n\t\treadonly metadata?: Metadata\n\t\treadonly handler: (\n\t\t\tcontext: Context,\n\t\t\t...args: Arguments\n\t\t) => MaybePromise<Result>\n\t}): (context: Context, ...args: Arguments) => Promise<Result> {\n\t\treturn (context, ...args) =>\n\t\t\tthis.#execute({\n\t\t\t\tcontext,\n\t\t\t\tmetadata: {\n\t\t\t\t\t...this.#defaults,\n\t\t\t\t\t...(executor.metadata ?? ({} as Metadata)),\n\t\t\t\t},\n\t\t\t\trun: async () => executor.handler(context, ...args),\n\t\t\t})\n\t}\n}\n"],"mappings":"AASA,IAAa,EAAb,KAAqD,CACpD,GACA,GAIA,YAAY,EAKT,CACF,KAAKA,GAAY,EAAc,SAC/B,KAAKC,GAAW,EAAc,OAC/B,CAEA,KAIE,EAM4D,CAC7D,OAAQ,EAAS,GAAG,IACnB,KAAKA,GAAS,CACb,UACA,SAAU,CACT,GAAG,KAAKD,GACR,GAAI,EAAS,UAAa,CAAC,CAC5B,EACA,IAAK,SAAY,EAAS,QAAQ,EAAS,GAAG,CAAI,CACnD,CAAC,CACH,CACD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TransactionMetrics } from "convex/server";
|
|
2
|
+
declare namespace result_d_exports {
|
|
3
|
+
export { Result, ResultBoundary, TransactionMetricsContext, executeResultBoundary, projectResult };
|
|
4
|
+
}
|
|
5
|
+
type TransactionMetricsContext = Readonly<{
|
|
6
|
+
meta: Readonly<{
|
|
7
|
+
getTransactionMetrics: () => Promise<TransactionMetrics>;
|
|
8
|
+
}>;
|
|
9
|
+
}>;
|
|
10
|
+
type Result<Value, Failure> = Readonly<{
|
|
11
|
+
ok: true;
|
|
12
|
+
value: Value;
|
|
13
|
+
}> | Readonly<{
|
|
14
|
+
ok: false;
|
|
15
|
+
error: Failure;
|
|
16
|
+
}>;
|
|
17
|
+
type ResultBoundary<Failure> = Readonly<{
|
|
18
|
+
ok: <Value>(value: Value) => Result<Value, Failure>;
|
|
19
|
+
handledError: <Value = never>(failure: Failure) => Result<Value, Failure>;
|
|
20
|
+
dataOf: (error: unknown) => Failure | undefined;
|
|
21
|
+
}>;
|
|
22
|
+
/** Return handled failures only before effects; otherwise rethrow for rollback. */
|
|
23
|
+
declare function executeResultBoundary<Value, Failure>(ctx: TransactionMetricsContext, operation: () => Promise<Value>, boundary: ResultBoundary<Failure>): Promise<Result<Value, Failure>>;
|
|
24
|
+
declare function projectResult<Value, Failure>(result: Result<Value, Failure>, projectFailure: (failure: Failure) => never): Value;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { Result, ResultBoundary, TransactionMetricsContext, executeResultBoundary, projectResult, result_d_exports };
|
|
27
|
+
//# sourceMappingURL=result.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=[`bytesRead`,`bytesWritten`,`databaseQueries`,`documentsRead`,`documentsWritten`,`functionsScheduled`,`scheduledFunctionArgsBytes`],t=[`bytesWritten`,`documentsWritten`,`functionsScheduled`,`scheduledFunctionArgsBytes`];async function n(e,t,n){try{return n.ok(await t())}catch(t){let r=n.dataOf(t);if(r===void 0)throw t;try{if(i(await e.meta.getTransactionMetrics()))throw t}catch{throw t}return n.handledError(r)}}function r(e,t){return e.ok?e.value:t(e.error)}function i(n){for(let t of e){let e=n[t];if(!e||!Number.isFinite(e.used)||e.used<0||!Number.isFinite(e.remaining)||e.remaining<0)throw Error(`Unreadable transaction metrics`)}return t.some(e=>n[e].used>0)}export{n as executeResultBoundary,r as projectResult};
|
|
2
|
+
//# sourceMappingURL=result.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.mjs","names":[],"sources":["../../../src/components/foundation/result.ts"],"sourcesContent":["import type { TransactionMetrics } from 'convex/server'\n\nexport type TransactionMetricsContext = Readonly<{\n\tmeta: Readonly<{\n\t\tgetTransactionMetrics: () => Promise<TransactionMetrics>\n\t}>\n}>\n\nexport type Result<Value, Failure> =\n\t| Readonly<{ ok: true; value: Value }>\n\t| Readonly<{ ok: false; error: Failure }>\n\nexport type ResultBoundary<Failure> = Readonly<{\n\tok: <Value>(value: Value) => Result<Value, Failure>\n\thandledError: <Value = never>(failure: Failure) => Result<Value, Failure>\n\tdataOf: (error: unknown) => Failure | undefined\n}>\n\nconst metricNames = [\n\t'bytesRead',\n\t'bytesWritten',\n\t'databaseQueries',\n\t'documentsRead',\n\t'documentsWritten',\n\t'functionsScheduled',\n\t'scheduledFunctionArgsBytes',\n] as const satisfies readonly (keyof TransactionMetrics)[]\n\nconst effectMetricNames = [\n\t'bytesWritten',\n\t'documentsWritten',\n\t'functionsScheduled',\n\t'scheduledFunctionArgsBytes',\n] as const satisfies readonly (keyof TransactionMetrics)[]\n\n/** Return handled failures only before effects; otherwise rethrow for rollback. */\nexport async function executeResultBoundary<Value, Failure>(\n\tctx: TransactionMetricsContext,\n\toperation: () => Promise<Value>,\n\tboundary: ResultBoundary<Failure>,\n): Promise<Result<Value, Failure>> {\n\ttry {\n\t\treturn boundary.ok(await operation())\n\t} catch (error) {\n\t\tconst handled = boundary.dataOf(error)\n\t\tif (handled === undefined) throw error\n\t\ttry {\n\t\t\tif (hasEffects(await ctx.meta.getTransactionMetrics())) throw error\n\t\t} catch {\n\t\t\tthrow error\n\t\t}\n\t\treturn boundary.handledError(handled)\n\t}\n}\n\nexport function projectResult<Value, Failure>(\n\tresult: Result<Value, Failure>,\n\tprojectFailure: (failure: Failure) => never,\n): Value {\n\treturn result.ok ? result.value : projectFailure(result.error)\n}\n\nfunction hasEffects(metrics: TransactionMetrics): boolean {\n\tfor (const name of metricNames) {\n\t\tconst metric = metrics[name]\n\t\tif (\n\t\t\t!metric ||\n\t\t\t!Number.isFinite(metric.used) ||\n\t\t\tmetric.used < 0 ||\n\t\t\t!Number.isFinite(metric.remaining) ||\n\t\t\tmetric.remaining < 0\n\t\t) {\n\t\t\tthrow new Error('Unreadable transaction metrics')\n\t\t}\n\t}\n\treturn effectMetricNames.some((name) => metrics[name].used > 0)\n}\n"],"mappings":"AAkBA,MAAM,EAAc,CACnB,YACA,eACA,kBACA,gBACA,mBACA,qBACA,4BACD,EAEM,EAAoB,CACzB,eACA,mBACA,qBACA,4BACD,EAGA,eAAsB,EACrB,EACA,EACA,EACkC,CAClC,GAAI,CACH,OAAO,EAAS,GAAG,MAAM,EAAU,CAAC,CACrC,OAAS,EAAO,CACf,IAAM,EAAU,EAAS,OAAO,CAAK,EACrC,GAAI,IAAY,IAAA,GAAW,MAAM,EACjC,GAAI,CACH,GAAI,EAAW,MAAM,EAAI,KAAK,sBAAsB,CAAC,EAAG,MAAM,CAC/D,MAAQ,CACP,MAAM,CACP,CACA,OAAO,EAAS,aAAa,CAAO,CACrC,CACD,CAEA,SAAgB,EACf,EACA,EACQ,CACR,OAAO,EAAO,GAAK,EAAO,MAAQ,EAAe,EAAO,KAAK,CAC9D,CAEA,SAAS,EAAW,EAAsC,CACzD,IAAK,IAAM,KAAQ,EAAa,CAC/B,IAAM,EAAS,EAAQ,GACvB,GACC,CAAC,GACD,CAAC,OAAO,SAAS,EAAO,IAAI,GAC5B,EAAO,KAAO,GACd,CAAC,OAAO,SAAS,EAAO,SAAS,GACjC,EAAO,UAAY,EAEnB,MAAU,MAAM,gCAAgC,CAElD,CACA,OAAO,EAAkB,KAAM,GAAS,EAAQ,EAAK,CAAC,KAAO,CAAC,CAC/D"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/components/foundation/schema.d.ts
|
|
2
|
+
/** Foundation is a capability-free in-process kernel and owns no business data. */
|
|
3
|
+
declare const _default: import("convex/server").SchemaDefinition<{}, true>;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { _default as default };
|
|
6
|
+
//# sourceMappingURL=schema.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.mjs","names":[],"sources":["../../../src/components/foundation/schema.ts"],"sourcesContent":["import { defineSchema } from 'convex/server'\n\n/** Foundation is a capability-free in-process kernel and owns no business data. */\nexport default defineSchema({})\n"],"mappings":"6CAGA,IAAA,EAAe,EAAa,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare namespace telemetry_d_exports {
|
|
2
|
+
export { emitSemanticEvent };
|
|
3
|
+
}
|
|
4
|
+
type SemanticValue = string | number | boolean;
|
|
5
|
+
/** Emit bounded semantic fields only; free-form payloads and identifiers drop. */
|
|
6
|
+
declare function emitSemanticEvent(event: string, fields?: Readonly<Record<string, SemanticValue | undefined>>): void;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { emitSemanticEvent, telemetry_d_exports };
|
|
9
|
+
//# sourceMappingURL=telemetry.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=/^[A-Za-z][A-Za-z0-9_.-]{0,159}$/;function t(t,n={}){try{if(!e.test(t))return;let r={event:t};for(let[t,i]of Object.entries(n))!e.test(t)||i===void 0||typeof i==`string`&&!e.test(i)||typeof i==`number`&&!Number.isFinite(i)||(r[t]=i);console.info(JSON.stringify(r))}catch{}}export{t as emitSemanticEvent};
|
|
2
|
+
//# sourceMappingURL=telemetry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.mjs","names":[],"sources":["../../../src/components/foundation/telemetry.ts"],"sourcesContent":["type SemanticValue = string | number | boolean\n\nconst semanticToken = /^[A-Za-z][A-Za-z0-9_.-]{0,159}$/\n\n/** Emit bounded semantic fields only; free-form payloads and identifiers drop. */\nexport function emitSemanticEvent(\n\tevent: string,\n\tfields: Readonly<Record<string, SemanticValue | undefined>> = {},\n): void {\n\ttry {\n\t\tif (!semanticToken.test(event)) return\n\t\tconst safe: Record<string, SemanticValue> = { event }\n\t\tfor (const [key, value] of Object.entries(fields)) {\n\t\t\tif (!semanticToken.test(key) || value === undefined) continue\n\t\t\tif (typeof value === 'string' && !semanticToken.test(value)) continue\n\t\t\tif (typeof value === 'number' && !Number.isFinite(value)) continue\n\t\t\tsafe[key] = value\n\t\t}\n\t\tconsole.info(JSON.stringify(safe))\n\t} catch {\n\t\t// Telemetry must never change command behavior.\n\t}\n}\n"],"mappings":"AAEA,MAAM,EAAgB,kCAGtB,SAAgB,EACf,EACA,EAA8D,CAAC,EACxD,CACP,GAAI,CACH,GAAI,CAAC,EAAc,KAAK,CAAK,EAAG,OAChC,IAAM,EAAsC,CAAE,OAAM,EACpD,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAM,EAC3C,CAAC,EAAc,KAAK,CAAG,GAAK,IAAU,IAAA,IACtC,OAAO,GAAU,UAAY,CAAC,EAAc,KAAK,CAAK,GACtD,OAAO,GAAU,UAAY,CAAC,OAAO,SAAS,CAAK,IACvD,EAAK,GAAO,GAEb,QAAQ,KAAK,KAAK,UAAU,CAAI,CAAC,CAClC,MAAQ,CAER,CACD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/errors.d.ts
|
|
2
|
+
/** Structured application error carried across Convex function boundaries. */
|
|
3
|
+
declare class KitError extends Error {
|
|
4
|
+
readonly code: string;
|
|
5
|
+
constructor(input: {
|
|
6
|
+
code: string;
|
|
7
|
+
message?: string;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Injection seam for host error policy. Hosts with their own error taxonomy
|
|
12
|
+
* (e.g. an App.errors singleton) adapt it to this shape; everyone else uses
|
|
13
|
+
* the default factory below.
|
|
14
|
+
*/
|
|
15
|
+
type ErrorFactory = {
|
|
16
|
+
throw(input: {
|
|
17
|
+
code: string;
|
|
18
|
+
message?: string;
|
|
19
|
+
}): never;
|
|
20
|
+
};
|
|
21
|
+
declare const defaultErrors: ErrorFactory;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ErrorFactory, KitError, defaultErrors };
|
|
24
|
+
//# sourceMappingURL=errors.d.mts.map
|
package/dist/errors.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Structured application error carried across Convex function boundaries. */\nexport class KitError extends Error {\n\treadonly code: string\n\n\tconstructor(input: { code: string; message?: string }) {\n\t\tsuper(input.message ?? input.code)\n\t\tthis.name = 'KitError'\n\t\tthis.code = input.code\n\t}\n}\n\n/**\n * Injection seam for host error policy. Hosts with their own error taxonomy\n * (e.g. an App.errors singleton) adapt it to this shape; everyone else uses\n * the default factory below.\n */\nexport type ErrorFactory = {\n\tthrow(input: { code: string; message?: string }): never\n}\n\nexport const defaultErrors: ErrorFactory = {\n\tthrow(input) {\n\t\tthrow new KitError(input)\n\t},\n}\n"],"mappings":"AACA,IAAa,EAAb,cAA8B,KAAM,CACnC,KAEA,YAAY,EAA2C,CACtD,MAAM,EAAM,SAAW,EAAM,IAAI,EACjC,KAAK,KAAO,WACZ,KAAK,KAAO,EAAM,IACnB,CACD,EAWA,MAAa,EAA8B,CAC1C,MAAM,EAAO,CACZ,MAAM,IAAI,EAAS,CAAK,CACzB,CACD"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ErrorFactory, KitError, defaultErrors } from "./errors.mjs";
|
|
2
|
+
import { Actor, AuthBundle, AuthFunctionsConfig, DefaultRole, Include, IncludedQuery, createAuthFunctions, createInclude, defaultRoleMap } from "./auth.mjs";
|
|
3
|
+
import { ApplicationCommand, AuditEntryInput, AuditWriter, AuditedOperation, AuditedRegistry, Foundation, FoundationOptions } from "./components/foundation/client.mjs";
|
|
4
|
+
import { TIMESTAMP_FIELDS, TableBoundaryOptions, jsonSafeZid, zodTable, zodVariantTable } from "./zod-table.mjs";
|
|
5
|
+
import { Change, Trigger, Triggers, appendOnly, createTriggers, noDelete, timestamps } from "./triggers.mjs";
|
|
6
|
+
export { type Actor, type ApplicationCommand, type AuditEntryInput, type AuditWriter, type AuditedOperation, type AuditedRegistry, type AuthBundle, type AuthFunctionsConfig, type Change, type DefaultRole, type ErrorFactory, Foundation, type FoundationOptions, type Include, type IncludedQuery, KitError, TIMESTAMP_FIELDS, type TableBoundaryOptions, type Trigger, Triggers, appendOnly, createAuthFunctions, createInclude, createTriggers, defaultErrors, defaultRoleMap, jsonSafeZid, noDelete, timestamps, zodTable, zodVariantTable };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{KitError as e,defaultErrors as t}from"./errors.mjs";import{createAuthFunctions as n,createInclude as r,defaultRoleMap as i}from"./auth.mjs";import{TIMESTAMP_FIELDS as a,jsonSafeZid as o,zodTable as s,zodVariantTable as c}from"./zod-table.mjs";import{Triggers as l,appendOnly as u,createTriggers as d,noDelete as f,timestamps as p}from"./triggers.mjs";import{Foundation as m}from"./components/foundation/client.mjs";export{m as Foundation,e as KitError,a as TIMESTAMP_FIELDS,l as Triggers,u as appendOnly,n as createAuthFunctions,r as createInclude,d as createTriggers,t as defaultErrors,i as defaultRoleMap,o as jsonSafeZid,f as noDelete,p as timestamps,s as zodTable,c as zodVariantTable};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { GenericDataModel, TableNamesInDataModel } from "convex/server";
|
|
2
|
+
import { Change, Trigger, Triggers } from "convex-helpers/server/triggers";
|
|
3
|
+
//#region src/triggers.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* One application-wide mutation interceptor registry. Pass it to
|
|
6
|
+
* createAuthFunctions({ triggers }) so every authMutation/roleMutation/
|
|
7
|
+
* systemMutation runs writes through it — trigger enforcement becomes
|
|
8
|
+
* structural, not a convention.
|
|
9
|
+
*/
|
|
10
|
+
declare function createTriggers<DataModel extends GenericDataModel>(): Triggers<DataModel>;
|
|
11
|
+
/**
|
|
12
|
+
* Marks tables as append-only evidence tables: inserts pass, every update or
|
|
13
|
+
* delete throws. The ontology pattern for votes/history/audit-style tables.
|
|
14
|
+
*/
|
|
15
|
+
declare function appendOnly<DataModel extends GenericDataModel>(triggers: Triggers<DataModel>, ...tables: readonly TableNamesInDataModel<DataModel>[]): void;
|
|
16
|
+
/** Forbids hard deletes on the given tables (soft-delete discipline). */
|
|
17
|
+
declare function noDelete<DataModel extends GenericDataModel>(triggers: Triggers<DataModel>, ...tables: readonly TableNamesInDataModel<DataModel>[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Maintains zod-table's opinionated lifecycle timestamps: createdAt and
|
|
20
|
+
* updatedAt on insert, updatedAt on every update. archivedAt stays under
|
|
21
|
+
* application control. Register once per table; writes made through the
|
|
22
|
+
* auth constructors keep these fields correct automatically.
|
|
23
|
+
*/
|
|
24
|
+
declare function timestamps<DataModel extends GenericDataModel>(triggers: Triggers<DataModel>, ...tables: readonly TableNamesInDataModel<DataModel>[]): void;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { type Change, type Trigger, Triggers, appendOnly, createTriggers, noDelete, timestamps };
|
|
27
|
+
//# sourceMappingURL=triggers.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Triggers as e}from"convex-helpers/server/triggers";function t(){return new e}function n(e,...t){for(let n of t)e.register(n,async(e,t)=>{if(t.operation!==`insert`)throw Error(`${n} is append-only`)})}function r(e,...t){for(let n of t)e.register(n,async(e,t)=>{if(t.operation===`delete`)throw Error(`${n} rows cannot be deleted`)})}function i(e,...t){for(let n of t)e.register(n,async(e,t)=>{if(t.operation===`delete`)return;let n=Date.now();if(t.operation===`insert`){t.newDoc.createdAt===void 0&&await e.innerDb.patch(t.id,{createdAt:n,updatedAt:n});return}let r=t.oldDoc;t.newDoc.updatedAt===r.updatedAt&&await e.innerDb.patch(t.id,{updatedAt:n})})}export{e as Triggers,n as appendOnly,t as createTriggers,r as noDelete,i as timestamps};
|
|
2
|
+
//# sourceMappingURL=triggers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triggers.mjs","names":[],"sources":["../src/triggers.ts"],"sourcesContent":["import {\n\tTriggers,\n\ttype Change,\n\ttype Trigger,\n} from 'convex-helpers/server/triggers'\nimport type {\n\tGenericDataModel,\n\tTableNamesInDataModel,\n} from 'convex/server'\n\nexport { Triggers }\nexport type { Change, Trigger }\n\n/**\n * One application-wide mutation interceptor registry. Pass it to\n * createAuthFunctions({ triggers }) so every authMutation/roleMutation/\n * systemMutation runs writes through it — trigger enforcement becomes\n * structural, not a convention.\n */\nexport function createTriggers<\n\tDataModel extends GenericDataModel,\n>(): Triggers<DataModel> {\n\treturn new Triggers<DataModel>()\n}\n\n/**\n * Marks tables as append-only evidence tables: inserts pass, every update or\n * delete throws. The ontology pattern for votes/history/audit-style tables.\n */\nexport function appendOnly<DataModel extends GenericDataModel>(\n\ttriggers: Triggers<DataModel>,\n\t...tables: readonly TableNamesInDataModel<DataModel>[]\n) {\n\tfor (const table of tables) {\n\t\ttriggers.register(table, async (_ctx, change) => {\n\t\t\tif (change.operation !== 'insert') {\n\t\t\t\tthrow new Error(`${table} is append-only`)\n\t\t\t}\n\t\t})\n\t}\n}\n\n/** Forbids hard deletes on the given tables (soft-delete discipline). */\nexport function noDelete<DataModel extends GenericDataModel>(\n\ttriggers: Triggers<DataModel>,\n\t...tables: readonly TableNamesInDataModel<DataModel>[]\n) {\n\tfor (const table of tables) {\n\t\ttriggers.register(table, async (_ctx, change) => {\n\t\t\tif (change.operation === 'delete') {\n\t\t\t\tthrow new Error(`${table} rows cannot be deleted`)\n\t\t\t}\n\t\t})\n\t}\n}\n\n/**\n * Maintains zod-table's opinionated lifecycle timestamps: createdAt and\n * updatedAt on insert, updatedAt on every update. archivedAt stays under\n * application control. Register once per table; writes made through the\n * auth constructors keep these fields correct automatically.\n */\nexport function timestamps<DataModel extends GenericDataModel>(\n\ttriggers: Triggers<DataModel>,\n\t...tables: readonly TableNamesInDataModel<DataModel>[]\n) {\n\tfor (const table of tables) {\n\t\ttriggers.register(table, async (ctx, change) => {\n\t\t\tif (change.operation === 'delete') return\n\t\t\tconst now = Date.now()\n\t\t\tif (change.operation === 'insert') {\n\t\t\t\tconst document = change.newDoc as { createdAt?: number }\n\t\t\t\tif (document.createdAt === undefined) {\n\t\t\t\t\tawait ctx.innerDb.patch(change.id, {\n\t\t\t\t\t\tcreatedAt: now,\n\t\t\t\t\t\tupdatedAt: now,\n\t\t\t\t\t} as never)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = change.oldDoc as { updatedAt?: number }\n\t\t\tconst current = change.newDoc as { updatedAt?: number }\n\t\t\t// A write that already moved updatedAt (including our own patch)\n\t\t\t// is left alone — this is the recursion guard.\n\t\t\tif (current.updatedAt === previous.updatedAt) {\n\t\t\t\tawait ctx.innerDb.patch(change.id, { updatedAt: now } as never)\n\t\t\t}\n\t\t})\n\t}\n}\n"],"mappings":"0DAmBA,SAAgB,GAES,CACxB,OAAO,IAAI,CACZ,CAMA,SAAgB,EACf,EACA,GAAG,EACF,CACD,IAAK,IAAM,KAAS,EACnB,EAAS,SAAS,EAAO,MAAO,EAAM,IAAW,CAChD,GAAI,EAAO,YAAc,SACxB,MAAU,MAAM,GAAG,EAAM,gBAAgB,CAE3C,CAAC,CAEH,CAGA,SAAgB,EACf,EACA,GAAG,EACF,CACD,IAAK,IAAM,KAAS,EACnB,EAAS,SAAS,EAAO,MAAO,EAAM,IAAW,CAChD,GAAI,EAAO,YAAc,SACxB,MAAU,MAAM,GAAG,EAAM,wBAAwB,CAEnD,CAAC,CAEH,CAQA,SAAgB,EACf,EACA,GAAG,EACF,CACD,IAAK,IAAM,KAAS,EACnB,EAAS,SAAS,EAAO,MAAO,EAAK,IAAW,CAC/C,GAAI,EAAO,YAAc,SAAU,OACnC,IAAM,EAAM,KAAK,IAAI,EACrB,GAAI,EAAO,YAAc,SAAU,CACjB,EAAO,OACX,YAAc,IAAA,IAC1B,MAAM,EAAI,QAAQ,MAAM,EAAO,GAAI,CAClC,UAAW,EACX,UAAW,CACZ,CAAU,EAEX,MACD,CACA,IAAM,EAAW,EAAO,OACR,EAAO,OAGX,YAAc,EAAS,WAClC,MAAM,EAAI,QAAQ,MAAM,EAAO,GAAI,CAAE,UAAW,CAAI,CAAU,CAEhE,CAAC,CAEH"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { ConvexValidatorFromZod, zid } from "convex-helpers/server/zod4";
|
|
2
|
+
import { TableDefinition } from "convex/server";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { GenericId } from "convex/values";
|
|
5
|
+
//#region src/zod-table.d.ts
|
|
6
|
+
type Shape = Record<string, z.ZodType>;
|
|
7
|
+
type ShapeKey<Fields extends Shape> = Extract<keyof Fields, string>;
|
|
8
|
+
/**
|
|
9
|
+
* Opinionated lifecycle timestamps — every table has them, server-owned,
|
|
10
|
+
* always excluded from insert/command boundaries. Maintained by the
|
|
11
|
+
* `timestamps` trigger helper (see cvx-kit/triggers).
|
|
12
|
+
*/
|
|
13
|
+
declare const timestampShape: {
|
|
14
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
};
|
|
18
|
+
type TimestampShape = typeof timestampShape;
|
|
19
|
+
declare const TIMESTAMP_FIELDS: readonly ['createdAt', 'updatedAt', 'archivedAt'];
|
|
20
|
+
type TableBoundaryOptions<Fields extends Shape, ServerFields extends readonly ShapeKey<Fields>[], CommandFields extends readonly ShapeKey<Fields>[], PublicFields extends readonly ShapeKey<Fields & TimestampShape>[]> = {
|
|
21
|
+
serverFields?: ServerFields;
|
|
22
|
+
commandFields?: CommandFields;
|
|
23
|
+
publicFields?: PublicFields;
|
|
24
|
+
};
|
|
25
|
+
/** Defines one table and derives its storage, document, write, and DTO boundaries. */
|
|
26
|
+
declare function zodTable<Table extends string, Fields extends Shape, const ServerFields extends readonly ShapeKey<Fields>[] = readonly [], const CommandFields extends readonly ShapeKey<Fields>[] = readonly [], const PublicFields extends readonly ShapeKey<Fields & TimestampShape>[] = readonly []>(tableName: Table, fields: (id: typeof zid) => Fields, options?: TableBoundaryOptions<Fields, ServerFields, CommandFields, PublicFields>): {
|
|
27
|
+
tableName: Table;
|
|
28
|
+
schema: z.ZodObject<((keyof Fields & "_creationTime") | (keyof Fields & "_id") extends never ? (Fields & {
|
|
29
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
} extends (infer T_1) ? { -readonly [P in keyof T_1]: T_1[P]; } : never) & {
|
|
33
|
+
_id: import("convex-helpers/server/zod4").Zid<Table>;
|
|
34
|
+
_creationTime: z.ZodNumber;
|
|
35
|
+
} : ((Fields & {
|
|
36
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
39
|
+
} extends (infer T_1) ? { -readonly [P in keyof T_1]: T_1[P]; } : never) extends (infer T_2 extends z.util.SomeObject) ? { [K in keyof T_2 as K extends "_creationTime" | "_id" ? never : K]: T_2[K]; } : never) & {
|
|
40
|
+
_id: import("convex-helpers/server/zod4").Zid<Table>;
|
|
41
|
+
_creationTime: z.ZodNumber;
|
|
42
|
+
}) extends (infer T) ? { [k in keyof T]: T[k]; } : never, z.core.$strict>;
|
|
43
|
+
storage: z.ZodObject<Fields & {
|
|
44
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
45
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
46
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
47
|
+
} extends (infer T_1) ? { -readonly [P in keyof T_1]: T_1[P]; } : never, z.core.$strict>;
|
|
48
|
+
insertSchema: z.ZodObject<Omit<Fields, "archivedAt" | "createdAt" | "updatedAt" | ServerFields[number]>, z.core.$strip>;
|
|
49
|
+
updateSchema: z.ZodObject<Omit<Fields, "archivedAt" | "createdAt" | "updatedAt" | ServerFields[number]> extends (infer T_3 extends Readonly<{
|
|
50
|
+
[k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
51
|
+
}>) ? { -readonly [k in keyof T_3]: z.ZodOptional<T_3[k]>; } : never, z.core.$strip>;
|
|
52
|
+
commandInput: z.ZodObject<Pick<Fields & {
|
|
53
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
54
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
55
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
56
|
+
}, CommandFields[number]> extends (infer T_4) ? { -readonly [P in keyof T_4]: T_4[P]; } : never, z.core.$strict>;
|
|
57
|
+
publicDto: z.ZodObject<Pick<Fields & {
|
|
58
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
59
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
61
|
+
}, PublicFields[number]> extends (infer T_5) ? { -readonly [P in keyof T_5]: T_5[P]; } : never, z.core.$strict>;
|
|
62
|
+
toPublicDto: (row: z.input<z.ZodObject<Fields & {
|
|
63
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
64
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
65
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
66
|
+
} extends (infer T_1) ? { -readonly [P in keyof T_1]: T_1[P]; } : never, z.core.$strict>>) => z.core.$InferObjectOutput<Pick<Fields & {
|
|
67
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
69
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
70
|
+
}, PublicFields[number]> extends (infer T_5) ? { -readonly [P in keyof T_5]: T_5[P]; } : never, {}>;
|
|
71
|
+
table: TableDefinition<ConvexValidatorFromZod<z.ZodObject<Fields & {
|
|
72
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
73
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
74
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
75
|
+
} extends (infer T_1) ? { -readonly [P in keyof T_1]: T_1[P]; } : never, z.core.$strict>, 'required'>>;
|
|
76
|
+
insert: {
|
|
77
|
+
(): z.ZodObject<Omit<Fields, "archivedAt" | "createdAt" | "updatedAt" | ServerFields[number]>, z.core.$strip>;
|
|
78
|
+
<OmitMask extends z.util.Mask<Exclude<keyof Fields, "archivedAt" | "createdAt" | "updatedAt" | ServerFields[number]>>>(omit: OmitMask): ZodObjectOmit<z.ZodObject<Omit<Fields, "archivedAt" | "createdAt" | "updatedAt" | ServerFields[number]>, z.core.$strip>, OmitMask>;
|
|
79
|
+
};
|
|
80
|
+
update: {
|
|
81
|
+
(): z.ZodObject<Omit<Fields, "archivedAt" | "createdAt" | "updatedAt" | ServerFields[number]> extends (infer T_3 extends Readonly<{
|
|
82
|
+
[k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
83
|
+
}>) ? { -readonly [k in keyof T_3]: z.ZodOptional<T_3[k]>; } : never, z.core.$strip>;
|
|
84
|
+
<OmitMask extends z.util.Mask<Exclude<keyof Fields, "archivedAt" | "createdAt" | "updatedAt" | ServerFields[number]>>>(omit: OmitMask): ZodObjectOmit<z.ZodObject<Omit<Fields, "archivedAt" | "createdAt" | "updatedAt" | ServerFields[number]> extends (infer T_3 extends Readonly<{
|
|
85
|
+
[k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
86
|
+
}>) ? { -readonly [k in keyof T_3]: z.ZodOptional<T_3[k]>; } : never, z.core.$strip>, OmitMask>;
|
|
87
|
+
};
|
|
88
|
+
tools: {
|
|
89
|
+
insert: z.ZodObject<Pick<Fields & {
|
|
90
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
91
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
92
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
93
|
+
}, CommandFields[number]> extends (infer T_4) ? { -readonly [P in keyof T_4]: T_4[P]; } : never, z.core.$strict>;
|
|
94
|
+
update: z.ZodObject<{
|
|
95
|
+
data: z.ZodObject<(Pick<Fields & {
|
|
96
|
+
createdAt: z.ZodOptional<z.ZodNumber>;
|
|
97
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
98
|
+
archivedAt: z.ZodOptional<z.ZodNumber>;
|
|
99
|
+
}, CommandFields[number]> extends (infer T_4) ? { -readonly [P in keyof T_4]: T_4[P]; } : never) extends (infer T_6 extends Readonly<{
|
|
100
|
+
[k: string]: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
101
|
+
}>) ? { -readonly [k in keyof T_6]: z.ZodOptional<T_6[k]>; } : never, z.core.$strict>;
|
|
102
|
+
id: import("convex-helpers/server/zod4").Zid<Table>;
|
|
103
|
+
}, z.core.$strict>;
|
|
104
|
+
id: z.ZodObject<{
|
|
105
|
+
id: import("convex-helpers/server/zod4").Zid<Table>;
|
|
106
|
+
}, z.core.$strict>;
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
/** Preserves discriminated-union storage while retaining the same table owner. */
|
|
110
|
+
declare function zodVariantTable<Table extends string, Schema extends z.ZodType>(tableName: Table, storage: Schema): {
|
|
111
|
+
tableName: Table;
|
|
112
|
+
storage: Schema;
|
|
113
|
+
insertSchema: Schema;
|
|
114
|
+
table: TableDefinition<ConvexValidatorFromZod<Schema, "required">, {}, {}, {}>;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* A zid that presents as a plain string in generated JSON schemas so
|
|
118
|
+
* LLM-tool inputs stay primitive, while keeping the Id type at compile time.
|
|
119
|
+
*/
|
|
120
|
+
declare function jsonSafeZid<Table extends string>(tableName: Table): z.ZodType<GenericId<Table>, string>;
|
|
121
|
+
type ZodObjectOmit<Schema extends z.ZodObject<any, any>, OmitMask extends z.util.Mask<keyof Schema['shape']>> = Schema extends z.ZodObject<infer ObjectShape, infer Config> ? z.ZodObject<z.util.Flatten<Omit<ObjectShape, Extract<keyof ObjectShape, keyof OmitMask>>>, Config> : never;
|
|
122
|
+
//#endregion
|
|
123
|
+
export { TIMESTAMP_FIELDS, TableBoundaryOptions, jsonSafeZid, zodTable, zodVariantTable };
|
|
124
|
+
//# sourceMappingURL=zod-table.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{zid as e,zodToConvex as t}from"convex-helpers/server/zod4";import{defineTable as n}from"convex/server";import{z as r}from"zod";const i={createdAt:r.number().optional(),updatedAt:r.number().optional(),archivedAt:r.number().optional()},a=[`createdAt`,`updatedAt`,`archivedAt`];function o(o,s,c={}){let d={...s(e),...i},f=r.object(d).strict(),p=f.extend({_id:e(o),_creationTime:r.number()}),m=r.object(u(d,[...a,...c.serverFields??[]])).strict(),h=m.partial(),g=r.object(l(d,c.commandFields??[])).strict(),_=r.object(l(d,c.publicFields??[])).strict(),v=e=>_.parse(Object.fromEntries(Object.keys(_.shape).map(t=>[t,e[t]])));function y(e){return e?m.omit(e):m}function b(e){return e?h.omit(e):h}return{tableName:o,schema:p,storage:f,insertSchema:m,updateSchema:h,commandInput:g,publicDto:_,toPublicDto:v,table:n(t(f)),insert:y,update:b,tools:{insert:g,update:r.object({data:g.partial(),id:e(o)}).strict(),id:r.object({id:e(o)}).strict()}}}function s(e,r){return{tableName:e,storage:r,insertSchema:r,table:n(t(r))}}function c(e){return r.string().describe(`Convex document id for table "${e}"`)}function l(e,t){return Object.fromEntries(t.map(t=>[t,e[t]]))}function u(e,t){let n=new Set(t);return Object.fromEntries(Object.entries(e).filter(([e])=>!n.has(e)))}export{a as TIMESTAMP_FIELDS,c as jsonSafeZid,o as zodTable,s as zodVariantTable};
|
|
2
|
+
//# sourceMappingURL=zod-table.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-table.mjs","names":[],"sources":["../src/zod-table.ts"],"sourcesContent":["import {\n\ttype ConvexValidatorFromZod,\n\tzid,\n\tzodToConvex,\n} from 'convex-helpers/server/zod4'\nimport { defineTable, type TableDefinition } from 'convex/server'\nimport type { GenericId } from 'convex/values'\nimport { z } from 'zod'\n\ntype Shape = Record<string, z.ZodType>\ntype ShapeKey<Fields extends Shape> = Extract<keyof Fields, string>\n\n/**\n * Opinionated lifecycle timestamps — every table has them, server-owned,\n * always excluded from insert/command boundaries. Maintained by the\n * `timestamps` trigger helper (see cvx-kit/triggers).\n */\nconst timestampShape = {\n\tcreatedAt: z.number().optional(),\n\tupdatedAt: z.number().optional(),\n\tarchivedAt: z.number().optional(),\n} satisfies Shape\n\ntype TimestampShape = typeof timestampShape\n\nexport const TIMESTAMP_FIELDS = [\n\t'createdAt',\n\t'updatedAt',\n\t'archivedAt',\n] as const\n\nexport type TableBoundaryOptions<\n\tFields extends Shape,\n\tServerFields extends readonly ShapeKey<Fields>[],\n\tCommandFields extends readonly ShapeKey<Fields>[],\n\tPublicFields extends readonly ShapeKey<Fields & TimestampShape>[],\n> = {\n\tserverFields?: ServerFields\n\tcommandFields?: CommandFields\n\tpublicFields?: PublicFields\n}\n\n/** Defines one table and derives its storage, document, write, and DTO boundaries. */\nexport function zodTable<\n\tTable extends string,\n\tFields extends Shape,\n\tconst ServerFields extends readonly ShapeKey<Fields>[] = readonly [],\n\tconst CommandFields extends readonly ShapeKey<Fields>[] = readonly [],\n\tconst PublicFields extends readonly ShapeKey<\n\t\tFields & TimestampShape\n\t>[] = readonly [],\n>(\n\ttableName: Table,\n\tfields: (id: typeof zid) => Fields,\n\toptions: TableBoundaryOptions<\n\t\tFields,\n\t\tServerFields,\n\t\tCommandFields,\n\t\tPublicFields\n\t> = {},\n) {\n\tconst shape = { ...fields(zid), ...timestampShape } as Fields &\n\t\tTimestampShape\n\tconst storage = z.object(shape).strict()\n\tconst schema = storage.extend({\n\t\t_id: zid(tableName),\n\t\t_creationTime: z.number(),\n\t})\n\tconst insertSchema = z\n\t\t.object(\n\t\t\tomitShape(shape, [\n\t\t\t\t...TIMESTAMP_FIELDS,\n\t\t\t\t...(options.serverFields ?? ([] as never)),\n\t\t\t] as never),\n\t\t)\n\t\t.strict() as z.ZodObject<\n\t\tOmit<Fields, ServerFields[number] | (typeof TIMESTAMP_FIELDS)[number]>\n\t>\n\tconst updateSchema = insertSchema.partial()\n\tconst commandInput = z\n\t\t.object(pickShape(shape, options.commandFields ?? ([] as never)))\n\t\t.strict()\n\tconst publicDto = z\n\t\t.object(pickShape(shape, options.publicFields ?? ([] as never)))\n\t\t.strict()\n\tconst toPublicDto = (row: z.input<typeof storage>) =>\n\t\tpublicDto.parse(\n\t\t\tObject.fromEntries(\n\t\t\t\tObject.keys(publicDto.shape).map((key) => [\n\t\t\t\t\tkey,\n\t\t\t\t\t(row as Record<string, unknown>)[key],\n\t\t\t\t]),\n\t\t\t),\n\t\t)\n\n\ttype InsertSchema = typeof insertSchema\n\ttype UpdateSchema = typeof updateSchema\n\ttype InsertMask = z.util.Mask<keyof InsertSchema['shape']>\n\ttype UpdateMask = z.util.Mask<keyof UpdateSchema['shape']>\n\n\tfunction insert(): InsertSchema\n\tfunction insert<OmitMask extends InsertMask>(\n\t\tomit: OmitMask,\n\t): ZodObjectOmit<InsertSchema, OmitMask>\n\tfunction insert(omit?: InsertMask) {\n\t\treturn omit ? insertSchema.omit(omit as never) : insertSchema\n\t}\n\n\tfunction update(): UpdateSchema\n\tfunction update<OmitMask extends UpdateMask>(\n\t\tomit: OmitMask,\n\t): ZodObjectOmit<UpdateSchema, OmitMask>\n\tfunction update(omit?: UpdateMask) {\n\t\treturn omit ? updateSchema.omit(omit as never) : updateSchema\n\t}\n\n\treturn {\n\t\ttableName,\n\t\tschema,\n\t\tstorage,\n\t\tinsertSchema,\n\t\tupdateSchema,\n\t\tcommandInput,\n\t\tpublicDto,\n\t\ttoPublicDto,\n\t\ttable: defineTable(zodToConvex(storage)) as TableDefinition<\n\t\t\tConvexValidatorFromZod<typeof storage, 'required'>\n\t\t>,\n\t\tinsert,\n\t\tupdate,\n\t\ttools: {\n\t\t\tinsert: commandInput,\n\t\t\tupdate: z\n\t\t\t\t.object({ data: commandInput.partial(), id: zid(tableName) })\n\t\t\t\t.strict(),\n\t\t\tid: z.object({ id: zid(tableName) }).strict(),\n\t\t},\n\t}\n}\n\n/** Preserves discriminated-union storage while retaining the same table owner. */\nexport function zodVariantTable<Table extends string, Schema extends z.ZodType>(\n\ttableName: Table,\n\tstorage: Schema,\n) {\n\treturn {\n\t\ttableName,\n\t\tstorage,\n\t\tinsertSchema: storage,\n\t\ttable: defineTable(zodToConvex(storage)),\n\t}\n}\n\n/**\n * A zid that presents as a plain string in generated JSON schemas so\n * LLM-tool inputs stay primitive, while keeping the Id type at compile time.\n */\nexport function jsonSafeZid<Table extends string>(tableName: Table) {\n\treturn z\n\t\t.string()\n\t\t.describe(\n\t\t\t`Convex document id for table \"${tableName}\"`,\n\t\t) as unknown as z.ZodType<GenericId<Table>, string>\n}\n\ntype ZodObjectOmit<\n\tSchema extends z.ZodObject<any, any>,\n\tOmitMask extends z.util.Mask<keyof Schema['shape']>,\n> =\n\tSchema extends z.ZodObject<infer ObjectShape, infer Config>\n\t\t? z.ZodObject<\n\t\t\t\tz.util.Flatten<\n\t\t\t\t\tOmit<ObjectShape, Extract<keyof ObjectShape, keyof OmitMask>>\n\t\t\t\t>,\n\t\t\t\tConfig\n\t\t\t>\n\t\t: never\n\nfunction pickShape<\n\tFields extends Shape,\n\tconst Keys extends readonly ShapeKey<Fields>[],\n>(fields: Fields, keys: Keys) {\n\treturn Object.fromEntries(keys.map((key) => [key, fields[key]])) as Pick<\n\t\tFields,\n\t\tKeys[number]\n\t>\n}\n\nfunction omitShape<\n\tFields extends Shape,\n\tconst Keys extends readonly ShapeKey<Fields>[],\n>(fields: Fields, keys: Keys) {\n\tconst omitted = new Set<string>(keys)\n\treturn Object.fromEntries(\n\t\tObject.entries(fields).filter(([key]) => !omitted.has(key)),\n\t) as Omit<Fields, Keys[number]>\n}\n"],"mappings":"sIAiBA,MAAM,EAAiB,CACtB,UAAW,EAAE,OAAO,CAAC,CAAC,SAAS,EAC/B,UAAW,EAAE,OAAO,CAAC,CAAC,SAAS,EAC/B,WAAY,EAAE,OAAO,CAAC,CAAC,SAAS,CACjC,EAIa,EAAmB,CAC/B,YACA,YACA,YACD,EAcA,SAAgB,EASf,EACA,EACA,EAKI,CAAC,EACJ,CACD,IAAM,EAAQ,CAAE,GAAG,EAAO,CAAG,EAAG,GAAG,CAAe,EAE5C,EAAU,EAAE,OAAO,CAAK,CAAC,CAAC,OAAO,EACjC,EAAS,EAAQ,OAAO,CAC7B,IAAK,EAAI,CAAS,EAClB,cAAe,EAAE,OAAO,CACzB,CAAC,EACK,EAAe,EACnB,OACA,EAAU,EAAO,CAChB,GAAG,EACH,GAAI,EAAQ,cAAiB,CAAC,CAC/B,CAAU,CACX,CAAC,CACA,OAAO,EAGH,EAAe,EAAa,QAAQ,EACpC,EAAe,EACnB,OAAO,EAAU,EAAO,EAAQ,eAAkB,CAAC,CAAW,CAAC,CAAC,CAChE,OAAO,EACH,EAAY,EAChB,OAAO,EAAU,EAAO,EAAQ,cAAiB,CAAC,CAAW,CAAC,CAAC,CAC/D,OAAO,EACH,EAAe,GACpB,EAAU,MACT,OAAO,YACN,OAAO,KAAK,EAAU,KAAK,CAAC,CAAC,IAAK,GAAQ,CACzC,EACC,EAAgC,EAClC,CAAC,CACF,CACD,EAWD,SAAS,EAAO,EAAmB,CAClC,OAAO,EAAO,EAAa,KAAK,CAAa,EAAI,CAClD,CAMA,SAAS,EAAO,EAAmB,CAClC,OAAO,EAAO,EAAa,KAAK,CAAa,EAAI,CAClD,CAEA,MAAO,CACN,YACA,SACA,UACA,eACA,eACA,eACA,YACA,cACA,MAAO,EAAY,EAAY,CAAO,CAAC,EAGvC,SACA,SACA,MAAO,CACN,OAAQ,EACR,OAAQ,EACN,OAAO,CAAE,KAAM,EAAa,QAAQ,EAAG,GAAI,EAAI,CAAS,CAAE,CAAC,CAAC,CAC5D,OAAO,EACT,GAAI,EAAE,OAAO,CAAE,GAAI,EAAI,CAAS,CAAE,CAAC,CAAC,CAAC,OAAO,CAC7C,CACD,CACD,CAGA,SAAgB,EACf,EACA,EACC,CACD,MAAO,CACN,YACA,UACA,aAAc,EACd,MAAO,EAAY,EAAY,CAAO,CAAC,CACxC,CACD,CAMA,SAAgB,EAAkC,EAAkB,CACnE,OAAO,EACL,OAAO,CAAC,CACR,SACA,iCAAiC,EAAU,EAC5C,CACF,CAeA,SAAS,EAGP,EAAgB,EAAY,CAC7B,OAAO,OAAO,YAAY,EAAK,IAAK,GAAQ,CAAC,EAAK,EAAO,EAAI,CAAC,CAAC,CAIhE,CAEA,SAAS,EAGP,EAAgB,EAAY,CAC7B,IAAM,EAAU,IAAI,IAAY,CAAI,EACpC,OAAO,OAAO,YACb,OAAO,QAAQ,CAAM,CAAC,CAAC,QAAQ,CAAC,KAAS,CAAC,EAAQ,IAAI,CAAG,CAAC,CAC3D,CACD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cvx-kit",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Reusable Convex application kit: foundation kernels, approvals component, zod table boundaries, WorkOS-backed auth function constructors, and audited command protocol.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.mts",
|
|
16
|
+
"import": "./dist/index.mjs"
|
|
17
|
+
},
|
|
18
|
+
"./zod-table": {
|
|
19
|
+
"types": "./dist/zod-table.d.mts",
|
|
20
|
+
"import": "./dist/zod-table.mjs"
|
|
21
|
+
},
|
|
22
|
+
"./auth": {
|
|
23
|
+
"types": "./dist/auth.d.mts",
|
|
24
|
+
"import": "./dist/auth.mjs"
|
|
25
|
+
},
|
|
26
|
+
"./triggers": {
|
|
27
|
+
"types": "./dist/triggers.d.mts",
|
|
28
|
+
"import": "./dist/triggers.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./errors": {
|
|
31
|
+
"types": "./dist/errors.d.mts",
|
|
32
|
+
"import": "./dist/errors.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./test": "./src/test.ts",
|
|
35
|
+
"./components/foundation": {
|
|
36
|
+
"types": "./dist/components/foundation/client.d.mts",
|
|
37
|
+
"import": "./dist/components/foundation/client.mjs"
|
|
38
|
+
},
|
|
39
|
+
"./components/foundation/convex.config": {
|
|
40
|
+
"types": "./dist/components/foundation/convex.config.d.mts",
|
|
41
|
+
"import": "./dist/components/foundation/convex.config.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./components/foundation/convex.config.js": {
|
|
44
|
+
"types": "./dist/components/foundation/convex.config.d.mts",
|
|
45
|
+
"import": "./dist/components/foundation/convex.config.mjs"
|
|
46
|
+
},
|
|
47
|
+
"./components/foundation/_generated/component": {
|
|
48
|
+
"types": "./dist/components/foundation/_generated/component.d.mts"
|
|
49
|
+
},
|
|
50
|
+
"./components/approvals": {
|
|
51
|
+
"types": "./dist/components/approvals/client.d.mts",
|
|
52
|
+
"import": "./dist/components/approvals/client.mjs"
|
|
53
|
+
},
|
|
54
|
+
"./components/approvals/convex.config": {
|
|
55
|
+
"types": "./dist/components/approvals/convex.config.d.mts",
|
|
56
|
+
"import": "./dist/components/approvals/convex.config.mjs"
|
|
57
|
+
},
|
|
58
|
+
"./components/approvals/convex.config.js": {
|
|
59
|
+
"types": "./dist/components/approvals/convex.config.d.mts",
|
|
60
|
+
"import": "./dist/components/approvals/convex.config.mjs"
|
|
61
|
+
},
|
|
62
|
+
"./components/approvals/_generated/component": {
|
|
63
|
+
"types": "./dist/components/approvals/_generated/component.d.mts"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "vp pack",
|
|
68
|
+
"typecheck": "tsc --noEmit",
|
|
69
|
+
"test": "vp test run",
|
|
70
|
+
"prepublishOnly": "bun run typecheck && bun run test && bun run build",
|
|
71
|
+
"build:codegen": "convex codegen --component-dir ./src/components/foundation && convex codegen --component-dir ./src/components/approvals && vp pack",
|
|
72
|
+
"release": "npm version patch && git push --follow-tags",
|
|
73
|
+
"release:minor": "npm version minor && git push --follow-tags"
|
|
74
|
+
},
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"@convex-dev/workflow": "0.4.4",
|
|
77
|
+
"convex-audit-log": "^0.2.0",
|
|
78
|
+
"convex-helpers": "0.1.122"
|
|
79
|
+
},
|
|
80
|
+
"peerDependencies": {
|
|
81
|
+
"convex": "^1.43.0",
|
|
82
|
+
"zod": "^4.0.0"
|
|
83
|
+
},
|
|
84
|
+
"devDependencies": {
|
|
85
|
+
"@edge-runtime/vm": "^5.0.0",
|
|
86
|
+
"convex": "1.43.0",
|
|
87
|
+
"convex-test": "^0.0.55",
|
|
88
|
+
"publint": "^0.3.23",
|
|
89
|
+
"typescript": "7.0.2",
|
|
90
|
+
"vite-plus": "0.2.8",
|
|
91
|
+
"zod": "4.4.3"
|
|
92
|
+
},
|
|
93
|
+
"keywords": [
|
|
94
|
+
"convex",
|
|
95
|
+
"component",
|
|
96
|
+
"workos",
|
|
97
|
+
"zod"
|
|
98
|
+
],
|
|
99
|
+
"author": "Angel Lopez",
|
|
100
|
+
"repository": {
|
|
101
|
+
"type": "git",
|
|
102
|
+
"url": "git+https://github.com/ImRLopezAG/cvx-kit.git"
|
|
103
|
+
},
|
|
104
|
+
"homepage": "https://github.com/ImRLopezAG/cvx-kit#readme",
|
|
105
|
+
"bugs": {
|
|
106
|
+
"url": "https://github.com/ImRLopezAG/cvx-kit/issues"
|
|
107
|
+
}
|
|
108
|
+
}
|