cvx-kit 0.1.8 → 0.1.11

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.
Files changed (155) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +28 -28
  3. package/dist/agent-tools.d.mts +5 -5
  4. package/dist/agent-tools.mjs.map +1 -1
  5. package/dist/auth.d.mts +39 -289
  6. package/dist/auth.mjs.map +1 -1
  7. package/dist/components/approvals/_generated/api.d.mts +3 -4
  8. package/dist/components/approvals/_generated/api.mjs.map +1 -1
  9. package/dist/components/approvals/_generated/component.d.mts +1 -2
  10. package/dist/components/approvals/_generated/dataModel.d.mts +4 -5
  11. package/dist/components/approvals/_generated/server.d.mts +12 -13
  12. package/dist/components/approvals/_generated/server.mjs.map +1 -1
  13. package/dist/components/approvals/audit.d.mts +8 -8
  14. package/dist/components/approvals/audit.mjs +1 -1
  15. package/dist/components/approvals/audit.mjs.map +1 -1
  16. package/dist/components/approvals/client.d.mts +10 -10
  17. package/dist/components/approvals/client.mjs.map +1 -1
  18. package/dist/components/approvals/constants.d.mts +30 -30
  19. package/dist/components/approvals/constants.mjs.map +1 -1
  20. package/dist/components/approvals/convex.config.mjs.map +1 -1
  21. package/dist/components/approvals/decisions.d.mts +6 -6
  22. package/dist/components/approvals/decisions.mjs.map +1 -1
  23. package/dist/components/approvals/functions.d.mts +3 -3
  24. package/dist/components/approvals/functions.mjs.map +1 -1
  25. package/dist/components/approvals/health.d.mts +2 -2
  26. package/dist/components/approvals/health.mjs.map +1 -1
  27. package/dist/components/approvals/requests.d.mts +8 -8
  28. package/dist/components/approvals/requests.mjs.map +1 -1
  29. package/dist/components/approvals/validators.d.mts +29 -29
  30. package/dist/components/approvals/validators.mjs +1 -1
  31. package/dist/components/approvals/validators.mjs.map +1 -1
  32. package/dist/components/approvals/workflow.d.mts +3 -3
  33. package/dist/components/approvals/workflow.mjs.map +1 -1
  34. package/dist/components/approvals/workflow_steps.d.mts +15 -15
  35. package/dist/components/approvals/workflow_steps.mjs.map +1 -1
  36. package/dist/components/foundation/_generated/api.d.mts +3 -4
  37. package/dist/components/foundation/_generated/api.mjs.map +1 -1
  38. package/dist/components/foundation/_generated/component.d.mts +1 -2
  39. package/dist/components/foundation/_generated/dataModel.d.mts +4 -5
  40. package/dist/components/foundation/_generated/server.d.mts +12 -13
  41. package/dist/components/foundation/_generated/server.mjs.map +1 -1
  42. package/dist/components/foundation/client.d.mts +13 -13
  43. package/dist/components/foundation/client.mjs.map +1 -1
  44. package/dist/components/foundation/convex.config.mjs.map +1 -1
  45. package/dist/components/foundation/functions.d.mts +2 -2
  46. package/dist/components/foundation/functions.mjs.map +1 -1
  47. package/dist/components/foundation/modules/command/command.d.mts +14 -14
  48. package/dist/components/foundation/modules/command/command.mjs.map +1 -1
  49. package/dist/components/foundation/modules/command/lifecycle.d.mts +12 -13
  50. package/dist/components/foundation/modules/command/lifecycle.mjs.map +1 -1
  51. package/dist/components/foundation/modules/observability/observability.d.mts +4 -4
  52. package/dist/components/foundation/modules/observability/observability.mjs.map +1 -1
  53. package/dist/components/foundation/modules/query/query.d.mts +5 -5
  54. package/dist/components/foundation/modules/query/query.mjs.map +1 -1
  55. package/dist/components/foundation/operation.d.mts +5 -6
  56. package/dist/components/foundation/operation.mjs.map +1 -1
  57. package/dist/components/foundation/result.d.mts +6 -6
  58. package/dist/components/foundation/result.mjs.map +1 -1
  59. package/dist/components/foundation/telemetry.d.mts +2 -2
  60. package/dist/components/foundation/telemetry.mjs.map +1 -1
  61. package/dist/crud.d.mts +6 -5
  62. package/dist/crud.mjs.map +1 -1
  63. package/dist/effect.d.mts +3 -2
  64. package/dist/effect.mjs +1 -1
  65. package/dist/errors.d.mts +4 -4
  66. package/dist/errors.mjs.map +1 -1
  67. package/dist/index.d.mts +2 -2
  68. package/dist/middleware.d.mts +2 -3
  69. package/dist/middleware.mjs.map +1 -1
  70. package/dist/modules/contracts/contract.d.mts +12 -13
  71. package/dist/modules/contracts/contract.mjs.map +1 -1
  72. package/dist/modules/contracts/convex.d.mts +3 -5
  73. package/dist/modules/contracts/convex.mjs.map +1 -1
  74. package/dist/modules/contracts/errors.d.mts +8 -9
  75. package/dist/modules/contracts/errors.mjs +1 -1
  76. package/dist/modules/contracts/errors.mjs.map +1 -1
  77. package/dist/modules/contracts/exposure.d.mts +13 -14
  78. package/dist/modules/contracts/exposure.mjs +1 -1
  79. package/dist/modules/contracts/exposure.mjs.map +1 -1
  80. package/dist/modules/contracts/idempotency.d.mts +15 -16
  81. package/dist/modules/contracts/idempotency.mjs +1 -1
  82. package/dist/modules/contracts/idempotency.mjs.map +1 -1
  83. package/dist/modules/contracts/standard.d.mts +2 -3
  84. package/dist/modules/contracts/standard.mjs.map +1 -1
  85. package/dist/modules/contracts/workflow.d.mts +26 -27
  86. package/dist/modules/contracts/workflow.mjs.map +1 -1
  87. package/dist/modules/effect/api-runtime.d.mts +10 -11
  88. package/dist/modules/effect/api-runtime.mjs +1 -1
  89. package/dist/modules/effect/api-runtime.mjs.map +1 -1
  90. package/dist/modules/effect/api-zod.d.mts +2 -3
  91. package/dist/modules/effect/api-zod.mjs.map +1 -1
  92. package/dist/modules/effect/api.d.mts +4 -5
  93. package/dist/modules/effect/api.mjs.map +1 -1
  94. package/dist/modules/effect/auth.d.mts +43 -0
  95. package/dist/modules/effect/auth.mjs +2 -0
  96. package/dist/modules/effect/auth.mjs.map +1 -0
  97. package/dist/modules/effect/client.d.mts +1 -1
  98. package/dist/modules/effect/client.mjs +1 -1
  99. package/dist/modules/effect/command.d.mts +4 -5
  100. package/dist/modules/effect/command.mjs +1 -1
  101. package/dist/modules/effect/command.mjs.map +1 -1
  102. package/dist/modules/effect/crud.d.mts +7 -8
  103. package/dist/modules/effect/crud.mjs +1 -1
  104. package/dist/modules/effect/crud.mjs.map +1 -1
  105. package/dist/modules/effect/errors.d.mts +1 -2
  106. package/dist/modules/effect/errors.mjs.map +1 -1
  107. package/dist/modules/effect/foundation.d.mts +3 -4
  108. package/dist/modules/effect/foundation.mjs.map +1 -1
  109. package/dist/modules/effect/idempotency.d.mts +2 -3
  110. package/dist/modules/effect/idempotency.mjs.map +1 -1
  111. package/dist/modules/effect/normalize.d.mts +2 -3
  112. package/dist/modules/effect/normalize.mjs.map +1 -1
  113. package/dist/modules/effect/operation.d.mts +17 -18
  114. package/dist/modules/effect/operation.mjs.map +1 -1
  115. package/dist/modules/effect/query.d.mts +3 -4
  116. package/dist/modules/effect/query.mjs +1 -1
  117. package/dist/modules/effect/query.mjs.map +1 -1
  118. package/dist/modules/effect/schema.d.mts +8 -9
  119. package/dist/modules/effect/schema.mjs.map +1 -1
  120. package/dist/modules/effect/workflow.d.mts +5 -6
  121. package/dist/modules/effect/workflow.mjs +1 -1
  122. package/dist/modules/effect/workflow.mjs.map +1 -1
  123. package/dist/oxlint/architecture.d.mts +6 -7
  124. package/dist/oxlint/architecture.mjs +1 -1
  125. package/dist/oxlint/architecture.mjs.map +1 -1
  126. package/dist/oxlint/ast.d.mts +22 -23
  127. package/dist/oxlint/ast.mjs +1 -1
  128. package/dist/oxlint/ast.mjs.map +1 -1
  129. package/dist/oxlint/ownership.d.mts +2 -3
  130. package/dist/oxlint/ownership.mjs +1 -1
  131. package/dist/oxlint/ownership.mjs.map +1 -1
  132. package/dist/oxlint.d.mts +4 -4
  133. package/dist/oxlint.mjs +1 -1
  134. package/dist/oxlint.mjs.map +1 -1
  135. package/dist/state-machine.d.mts +1 -2
  136. package/dist/state-machine.mjs.map +1 -1
  137. package/dist/tenancy.d.mts +6 -6
  138. package/dist/tenancy.mjs.map +1 -1
  139. package/dist/triggers.d.mts +6 -6
  140. package/dist/triggers.mjs.map +1 -1
  141. package/dist/webhooks.d.mts +5 -6
  142. package/dist/webhooks.mjs.map +1 -1
  143. package/dist/zod-table.d.mts +10 -10
  144. package/dist/zod-table.mjs.map +1 -1
  145. package/docs/auth.md +131 -1
  146. package/docs/effect.md +8 -2
  147. package/docs/llms.md +41 -20
  148. package/docs/oxlint.md +1 -1
  149. package/docs/upgrading.md +9 -1
  150. package/docs/zod-table.md +1 -1
  151. package/package.json +21 -15
  152. package/scripts/test-packed-auth.mjs +72 -0
  153. package/scripts/test-packed-effect.mjs +2 -1
  154. package/scripts/test-packed-ids.mjs +2 -2
  155. package/dist/node_modules/@standard-schema/spec/dist/index.d.mts +0 -79
@@ -2,26 +2,26 @@ import { TransactionMetrics } from "convex/server";
2
2
  declare namespace result_d_exports {
3
3
  export { Result, ResultBoundary, TransactionMetricsContext, executeResultBoundary, projectResult };
4
4
  }
5
- type TransactionMetricsContext = Readonly<{
5
+ export type TransactionMetricsContext = Readonly<{
6
6
  meta: Readonly<{
7
7
  getTransactionMetrics: () => Promise<TransactionMetrics>;
8
8
  }>;
9
9
  }>;
10
- type Result<Value, Failure> = Readonly<{
10
+ export type Result<Value, Failure> = Readonly<{
11
11
  ok: true;
12
12
  value: Value;
13
13
  }> | Readonly<{
14
14
  ok: false;
15
15
  error: Failure;
16
16
  }>;
17
- type ResultBoundary<Failure> = Readonly<{
17
+ export type ResultBoundary<Failure> = Readonly<{
18
18
  ok: <Value>(value: Value) => Result<Value, Failure>;
19
19
  handledError: <Value = never>(failure: Failure) => Result<Value, Failure>;
20
20
  dataOf: (cause: unknown) => Failure | undefined;
21
21
  }>;
22
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;
23
+ export declare function executeResultBoundary<Value, Failure>(ctx: TransactionMetricsContext, operation: () => Promise<Value>, boundary: ResultBoundary<Failure>): Promise<Result<Value, Failure>>;
24
+ export declare function projectResult<Value, Failure>(result: Result<Value, Failure>, projectFailure: (failure: Failure) => never): Value;
25
25
  //#endregion
26
- export { Result, ResultBoundary, TransactionMetricsContext, executeResultBoundary, projectResult, result_d_exports };
26
+ export { result_d_exports };
27
27
  //# sourceMappingURL=result.d.mts.map
@@ -1 +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: (cause: 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"}
1
+ {"version":3,"file":"result.mjs","names":["metricNames","effectMetricNames","executeResultBoundary","boundary","operation","error","handled","hasEffects","ctx","projectResult","result","projectFailure","name","metric","metrics"],"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: (cause: 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,MAAMA,EAAc,CACnB,YACA,eACA,kBACA,gBACA,mBACA,qBACA,4BACD,EAEMC,EAAoB,CACzB,eACA,mBACA,qBACA,4BACD,EAGA,eAAsBC,EACrB,EACA,EACA,EACkC,CAClC,GAAI,CACH,OAAOC,EAAS,GAAG,MAAMC,EAAU,CAAC,CACrC,OAASC,EAAO,CACf,IAAMC,EAAUH,EAAS,OAAOE,CAAK,EACrC,GAAIC,IAAY,IAAA,GAAW,MAAMD,EACjC,GAAI,CACH,GAAIE,EAAW,MAAMC,EAAI,KAAK,sBAAsB,CAAC,EAAG,MAAMH,CAC/D,MAAQ,CACP,MAAMA,CACP,CACA,OAAOF,EAAS,aAAaG,CAAO,CACrC,CACD,CAEA,SAAgBG,EACf,EACA,EACQ,CACR,OAAOC,EAAO,GAAKA,EAAO,MAAQC,EAAeD,EAAO,KAAK,CAC9D,CAEA,SAASH,EAAW,EAAsC,CACzD,IAAK,IAAMK,KAAQZ,EAAa,CAC/B,IAAMa,EAASC,EAAQF,GACvB,GACC,CAACC,GACD,CAAC,OAAO,SAASA,EAAO,IAAI,GAC5BA,EAAO,KAAO,GACd,CAAC,OAAO,SAASA,EAAO,SAAS,GACjCA,EAAO,UAAY,EAEnB,MAAU,MAAM,gCAAgC,CAElD,CACA,OAAOZ,EAAkB,KAAM,GAASa,EAAQF,EAAK,CAAC,KAAO,CAAC,CAC/D"}
@@ -3,7 +3,7 @@ declare namespace telemetry_d_exports {
3
3
  }
4
4
  type SemanticValue = string | number | boolean;
5
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;
6
+ export declare function emitSemanticEvent(event: string, fields?: Readonly<Record<string, SemanticValue | undefined>>): void;
7
7
  //#endregion
8
- export { emitSemanticEvent, telemetry_d_exports };
8
+ export { telemetry_d_exports };
9
9
  //# sourceMappingURL=telemetry.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"telemetry.mjs","names":[],"sources":["../../../src/components/foundation/telemetry.ts"],"sourcesContent":["import { z } from 'zod'\n\ntype SemanticValue = string | number | boolean\n\nconst semanticToken = /^[A-Za-z][A-Za-z0-9_.-]{0,159}$/\nconst semanticValue = z.union([z.string().regex(semanticToken), z.number().finite(), z.boolean()])\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 = Object.fromEntries(\n\t\t\tObject.entries(fields).filter(\n\t\t\t\t([key, value]) => semanticToken.test(key) && semanticValue.safeParse(value).success,\n\t\t\t),\n\t\t)\n\t\tconsole.info(JSON.stringify({ event, ...safe }))\n\t} catch {\n\t\t// Telemetry must never change command behavior.\n\t}\n}\n"],"mappings":"wBAIA,MAAM,EAAgB,kCAChB,EAAgB,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,CAAa,EAAG,EAAE,OAAO,CAAC,CAAC,OAAO,EAAG,EAAE,QAAQ,CAAC,CAAC,EAGjG,SAAgB,EACf,EACA,EAA8D,CAAC,EACxD,CACP,GAAI,CACH,GAAI,CAAC,EAAc,KAAK,CAAK,EAAG,OAChC,IAAM,EAAO,OAAO,YACnB,OAAO,QAAQ,CAAM,CAAC,CAAC,QACrB,CAAC,EAAK,KAAW,EAAc,KAAK,CAAG,GAAK,EAAc,UAAU,CAAK,CAAC,CAAC,OAC7E,CACD,EACA,QAAQ,KAAK,KAAK,UAAU,CAAE,QAAO,GAAG,CAAK,CAAC,CAAC,CAChD,MAAQ,CAER,CACD"}
1
+ {"version":3,"file":"telemetry.mjs","names":["semanticToken","semanticValue","z","emitSemanticEvent","event","safe","fields","key","value"],"sources":["../../../src/components/foundation/telemetry.ts"],"sourcesContent":["import { z } from 'zod'\n\ntype SemanticValue = string | number | boolean\n\nconst semanticToken = /^[A-Za-z][A-Za-z0-9_.-]{0,159}$/\nconst semanticValue = z.union([z.string().regex(semanticToken), z.number().finite(), z.boolean()])\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 = Object.fromEntries(\n\t\t\tObject.entries(fields).filter(\n\t\t\t\t([key, value]) => semanticToken.test(key) && semanticValue.safeParse(value).success,\n\t\t\t),\n\t\t)\n\t\tconsole.info(JSON.stringify({ event, ...safe }))\n\t} catch {\n\t\t// Telemetry must never change command behavior.\n\t}\n}\n"],"mappings":"wBAIA,MAAMA,EAAgB,kCAChBC,EAAgBC,EAAE,MAAM,CAACA,EAAE,OAAO,CAAC,CAAC,MAAMF,CAAa,EAAGE,EAAE,OAAO,CAAC,CAAC,OAAO,EAAGA,EAAE,QAAQ,CAAC,CAAC,EAGjG,SAAgBC,EACf,EACA,EAA8D,CAAC,EACxD,CACP,GAAI,CACH,GAAI,CAACH,EAAc,KAAKI,CAAK,EAAG,OAChC,IAAMC,EAAO,OAAO,YACnB,OAAO,QAAQC,CAAM,CAAC,CAAC,QACrB,CAACC,EAAKC,KAAWR,EAAc,KAAKO,CAAG,GAAKN,EAAc,UAAUO,CAAK,CAAC,CAAC,OAC7E,CACD,EACA,QAAQ,KAAK,KAAK,UAAU,CAAE,QAAO,GAAGH,CAAK,CAAC,CAAC,CAChD,MAAQ,CAER,CACD"}
package/dist/crud.d.mts CHANGED
@@ -18,7 +18,7 @@ type CrudContext = {
18
18
  db: Pick<GenericMutationCtx<GenericDataModel>['db'], 'insert' | 'patch'>;
19
19
  };
20
20
  type MaybePromise<Value> = Value | Promise<Value>;
21
- type CrudConfig<Context extends CrudContext, Table extends CrudTable = CrudTable> = {
21
+ export type CrudConfig<Context extends CrudContext, Table extends CrudTable = CrudTable> = {
22
22
  /** The Foundation-bound Command class (destructured from the facade). */
23
23
  Command: CommandConstructor;
24
24
  table: Table;
@@ -55,8 +55,8 @@ type CrudConfig<Context extends CrudContext, Table extends CrudTable = CrudTable
55
55
  * used — it bypasses the command pipeline (no audits, no guards, and hard
56
56
  * deletes). See docs/crud.md.
57
57
  */
58
- type CrudCommands<Context extends CrudContext, Table extends CrudTable = CrudTable> = ReturnType<typeof createCrudCommands<Context, Table>>;
59
- declare function createCrudCommands<Context extends CrudContext, Table extends CrudTable = CrudTable>(config: CrudConfig<Context, Table>): {
58
+ export type CrudCommands<Context extends CrudContext, Table extends CrudTable = CrudTable> = ReturnType<typeof createCrudCommands<Context, Table>>;
59
+ export declare function createCrudCommands<Context extends CrudContext, Table extends CrudTable = CrudTable>(config: CrudConfig<Context, Table>): {
60
60
  commands: ApplicationCommand<Context, NamedOperation<`${string}.create`, {
61
61
  command: Table["commandInput"];
62
62
  result: z.ZodObject<{
@@ -224,7 +224,9 @@ declare function createCrudCommands<Context extends CrudContext, Table extends C
224
224
  }>;
225
225
  executeUpdate: (context: Context, command: {
226
226
  id: string;
227
- data: Record<string, unknown>;
227
+ data: {
228
+ [x: string]: unknown;
229
+ };
228
230
  }) => Promise<{
229
231
  ok: true;
230
232
  }>;
@@ -236,5 +238,4 @@ declare function createCrudCommands<Context extends CrudContext, Table extends C
236
238
  };
237
239
  type NamedOperation<Name extends string, Definition extends AuditedOperation> = { [Key in Name]: Definition; };
238
240
  //#endregion
239
- export { CrudCommands, CrudConfig, createCrudCommands };
240
241
  //# sourceMappingURL=crud.d.mts.map
package/dist/crud.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"crud.mjs","names":[],"sources":["../src/crud.ts"],"sourcesContent":["import { zid } from 'convex-helpers/server/zod4'\nimport { z } from 'zod'\nimport type { Value } from 'convex/values'\nimport type { GenericDataModel, GenericMutationCtx } from 'convex/server'\nimport type {\n\tAnyCommandMiddleware,\n\tApplicationCommand,\n\tAuditedOperation,\n\tCommandConstructor,\n\tSchemaOutput,\n} from './components/foundation/client'\nimport { defaultErrors, type ErrorFactory } from './errors'\n\n/**\n * The zodTable surface the factory consumes — structural, so any zodTable /\n * tenantTable return satisfies it.\n */\ntype CrudTable = {\n\ttableName: string\n\tcommandInput: z.ZodObject<Record<string, z.ZodType<Value | undefined>>>\n\tstorage: z.ZodObject<Record<string, z.ZodType<Value | undefined>>>\n}\n\ntype CrudContext = { db: Pick<GenericMutationCtx<GenericDataModel>['db'], 'insert' | 'patch'> }\n\ntype MaybePromise<Value> = Value | Promise<Value>\n\nexport type CrudConfig<Context extends CrudContext, Table extends CrudTable = CrudTable> = {\n\t/** The Foundation-bound Command class (destructured from the facade). */\n\tCommand: CommandConstructor\n\ttable: Table\n\t/** Audit aggregate type; enforced by the aggregates allowlist. */\n\taggregateType: string\n\t/** Observability/audit classification. Default 'business'. */\n\tclassification?: string\n\t/** Derives the audited actor id from the ctx (usually ctx.actor.userId). */\n\tactor: (context: Context) => string\n\t/**\n\t * Stamps server-owned fields onto creates (tenant, denormalized ids...).\n\t * REQUIRED when the table is a tenantTable — forgetting it would insert\n\t * untenanted rows; the factory fails fast at construction instead.\n\t */\n\tenrich?: (\n\t\tcontext: Context,\n\t\tcommand: SchemaOutput<Table['commandInput']>,\n\t) => MaybePromise<Partial<z.input<Table['storage']>>>\n\t/** Per-operation preconditions; run before the handlers. */\n\tguards?: {\n\t\tcreate?: (context: Context, command: never) => MaybePromise<void>\n\t\tupdate?: (context: Context, command: never) => MaybePromise<void>\n\t\tarchive?: (context: Context, command: never) => MaybePromise<void>\n\t}\n\t/** Per-operation middleware applied to all three generated operations. */\n\tmiddleware?: readonly AnyCommandMiddleware[]\n\terrors?: ErrorFactory\n}\n\n/**\n * Generates the standard create/update/archive operations from one zodTable\n * declaration, fully inside the audited command pipeline: strict command\n * inputs from `commandFields`, mandatory audit with the declared aggregate\n * type, soft delete only (archive sets `archivedAt` — no hard-delete\n * operation is generated, per kit doctrine).\n *\n * convex-helpers ships a same-named `crud` helper; it was deliberately not\n * used — it bypasses the command pipeline (no audits, no guards, and hard\n * deletes). See docs/crud.md.\n */\nexport type CrudCommands<\n\tContext extends CrudContext,\n\tTable extends CrudTable = CrudTable,\n> = ReturnType<typeof createCrudCommands<Context, Table>>\n\nexport function createCrudCommands<\n\tContext extends CrudContext,\n\tTable extends CrudTable = CrudTable,\n>(config: CrudConfig<Context, Table>) {\n\tconst errors = config.errors ?? defaultErrors\n\tconst name = config.table.tableName\n\tconst classification = config.classification ?? 'business'\n\tconst isTenantTable = 'tenant' in config.table.storage.shape\n\tif (isTenantTable && !config.enrich) {\n\t\treturn errors.throw({\n\t\t\tcode: 'CRUD_ENRICH_REQUIRED',\n\t\t\tmessage: `Table \"${name}\" is a tenantTable: createCrudCommands requires an enrich callback that stamps ctx.tenant`,\n\t\t})\n\t}\n\n\tconst commandSchema: Table['commandInput'] = config.table.commandInput\n\tconst id = zid(name)\n\tconst createResult = z.object({ id }).strict()\n\tconst okResult = z.object({ ok: z.literal(true) }).strict()\n\tconst updateInput = z.object({ id, data: commandSchema.partial().strict() }).strict()\n\tconst archiveInput = z.object({ id }).strict()\n\n\tconst createName = `${name}.create` as const\n\tconst updateName = `${name}.update` as const\n\tconst archiveName = `${name}.archive` as const\n\tconst operations = Object.assign(\n\t\t{},\n\t\tnamedOperation(createName, {\n\t\t\tcommand: commandSchema,\n\t\t\tresult: createResult,\n\t\t\tclassification,\n\t\t\taggregates: [config.aggregateType],\n\t\t\tmiddleware: config.middleware,\n\t\t\tguard: config.guards?.create,\n\t\t\taudit: (resolution: { result: z.output<typeof createResult> }, context: Context) => ({\n\t\t\t\toperation: createName,\n\t\t\t\tactorId: config.actor(context),\n\t\t\t\taggregate: { type: config.aggregateType, id: resolution.result.id },\n\t\t\t}),\n\t\t}),\n\t\tnamedOperation(updateName, {\n\t\t\tcommand: updateInput,\n\t\t\tresult: okResult,\n\t\t\tclassification,\n\t\t\taggregates: [config.aggregateType],\n\t\t\tmiddleware: config.middleware,\n\t\t\tguard: config.guards?.update,\n\t\t\taudit: (resolution: { command: z.output<typeof updateInput> }, context: Context) => ({\n\t\t\t\toperation: updateName,\n\t\t\t\tactorId: config.actor(context),\n\t\t\t\taggregate: { type: config.aggregateType, id: resolution.command.id },\n\t\t\t}),\n\t\t}),\n\t\tnamedOperation(archiveName, {\n\t\t\tcommand: archiveInput,\n\t\t\tresult: okResult,\n\t\t\tclassification,\n\t\t\taggregates: [config.aggregateType],\n\t\t\tmiddleware: config.middleware,\n\t\t\tguard: config.guards?.archive,\n\t\t\taudit: (resolution: { command: z.output<typeof archiveInput> }, context: Context) => ({\n\t\t\t\toperation: archiveName,\n\t\t\t\tactorId: config.actor(context),\n\t\t\t\taggregate: { type: config.aggregateType, id: resolution.command.id },\n\t\t\t}),\n\t\t}),\n\t)\n\tconst commands: ApplicationCommand<Context, typeof operations> = new config.Command<\n\t\tContext,\n\t\ttypeof operations\n\t>(operations)\n\tconst executeCreate = commands.exec({\n\t\toperation: createName,\n\t\thandler: async (context, command) => {\n\t\t\tconst enrichment = config.enrich ? await config.enrich(context, command) : {}\n\t\t\tconst values: Record<string, Value> = {}\n\t\t\tfor (const [field, value] of Object.entries({ ...command, ...enrichment })) {\n\t\t\t\tif (value !== undefined) values[field] = value\n\t\t\t}\n\t\t\tconst inserted = await context.db.insert(name, values)\n\t\t\treturn { id: inserted }\n\t\t},\n\t})\n\tconst executeUpdate = commands.exec({\n\t\toperation: updateName,\n\t\thandler: async (context, command) => {\n\t\t\tawait context.db.patch(command.id, command.data)\n\t\t\treturn { ok: true }\n\t\t},\n\t})\n\tconst executeArchive = commands.exec({\n\t\toperation: archiveName,\n\t\thandler: async (context, command) => {\n\t\t\tawait context.db.patch(command.id, { archivedAt: Date.now() })\n\t\t\treturn { ok: true }\n\t\t},\n\t})\n\n\treturn {\n\t\tcommands,\n\t\toperations,\n\t\texecuteCreate,\n\t\texecuteUpdate,\n\t\texecuteArchive,\n\t}\n}\n\nfunction namedOperation<Name extends string, Definition extends AuditedOperation>(\n\tname: Name,\n\tdefinition: Definition,\n) {\n\t// SAFETY: this object contains exactly the computed name and its corresponding definition.\n\treturn { [name]: definition } as NamedOperation<Name, Definition>\n}\n\ntype NamedOperation<Name extends string, Definition extends AuditedOperation> = {\n\t[Key in Name]: Definition\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"crud.mjs","names":["createCrudCommands","errors","config","defaultErrors","name","classification","commandSchema","id","zid","createResult","z","okResult","updateInput","archiveInput","createName","updateName","archiveName","operations","namedOperation","context","resolution","commands","enrichment","command","values","field","value","definition"],"sources":["../src/crud.ts"],"sourcesContent":["import { zid } from 'convex-helpers/server/zod4'\nimport { z } from 'zod'\nimport type { Value } from 'convex/values'\nimport type { GenericDataModel, GenericMutationCtx } from 'convex/server'\nimport type {\n\tAnyCommandMiddleware,\n\tApplicationCommand,\n\tAuditedOperation,\n\tCommandConstructor,\n\tSchemaOutput,\n} from './components/foundation/client'\nimport { defaultErrors, type ErrorFactory } from './errors'\n\n/**\n * The zodTable surface the factory consumes — structural, so any zodTable /\n * tenantTable return satisfies it.\n */\ntype CrudTable = {\n\ttableName: string\n\tcommandInput: z.ZodObject<Record<string, z.ZodType<Value | undefined>>>\n\tstorage: z.ZodObject<Record<string, z.ZodType<Value | undefined>>>\n}\n\ntype CrudContext = { db: Pick<GenericMutationCtx<GenericDataModel>['db'], 'insert' | 'patch'> }\n\ntype MaybePromise<Value> = Value | Promise<Value>\n\nexport type CrudConfig<Context extends CrudContext, Table extends CrudTable = CrudTable> = {\n\t/** The Foundation-bound Command class (destructured from the facade). */\n\tCommand: CommandConstructor\n\ttable: Table\n\t/** Audit aggregate type; enforced by the aggregates allowlist. */\n\taggregateType: string\n\t/** Observability/audit classification. Default 'business'. */\n\tclassification?: string\n\t/** Derives the audited actor id from the ctx (usually ctx.actor.userId). */\n\tactor: (context: Context) => string\n\t/**\n\t * Stamps server-owned fields onto creates (tenant, denormalized ids...).\n\t * REQUIRED when the table is a tenantTable — forgetting it would insert\n\t * untenanted rows; the factory fails fast at construction instead.\n\t */\n\tenrich?: (\n\t\tcontext: Context,\n\t\tcommand: SchemaOutput<Table['commandInput']>,\n\t) => MaybePromise<Partial<z.input<Table['storage']>>>\n\t/** Per-operation preconditions; run before the handlers. */\n\tguards?: {\n\t\tcreate?: (context: Context, command: never) => MaybePromise<void>\n\t\tupdate?: (context: Context, command: never) => MaybePromise<void>\n\t\tarchive?: (context: Context, command: never) => MaybePromise<void>\n\t}\n\t/** Per-operation middleware applied to all three generated operations. */\n\tmiddleware?: readonly AnyCommandMiddleware[]\n\terrors?: ErrorFactory\n}\n\n/**\n * Generates the standard create/update/archive operations from one zodTable\n * declaration, fully inside the audited command pipeline: strict command\n * inputs from `commandFields`, mandatory audit with the declared aggregate\n * type, soft delete only (archive sets `archivedAt` — no hard-delete\n * operation is generated, per kit doctrine).\n *\n * convex-helpers ships a same-named `crud` helper; it was deliberately not\n * used — it bypasses the command pipeline (no audits, no guards, and hard\n * deletes). See docs/crud.md.\n */\nexport type CrudCommands<\n\tContext extends CrudContext,\n\tTable extends CrudTable = CrudTable,\n> = ReturnType<typeof createCrudCommands<Context, Table>>\n\nexport function createCrudCommands<\n\tContext extends CrudContext,\n\tTable extends CrudTable = CrudTable,\n>(config: CrudConfig<Context, Table>) {\n\tconst errors = config.errors ?? defaultErrors\n\tconst name = config.table.tableName\n\tconst classification = config.classification ?? 'business'\n\tconst isTenantTable = 'tenant' in config.table.storage.shape\n\tif (isTenantTable && !config.enrich) {\n\t\treturn errors.throw({\n\t\t\tcode: 'CRUD_ENRICH_REQUIRED',\n\t\t\tmessage: `Table \"${name}\" is a tenantTable: createCrudCommands requires an enrich callback that stamps ctx.tenant`,\n\t\t})\n\t}\n\n\tconst commandSchema: Table['commandInput'] = config.table.commandInput\n\tconst id = zid(name)\n\tconst createResult = z.object({ id }).strict()\n\tconst okResult = z.object({ ok: z.literal(true) }).strict()\n\tconst updateInput = z.object({ id, data: commandSchema.partial().strict() }).strict()\n\tconst archiveInput = z.object({ id }).strict()\n\n\tconst createName = `${name}.create` as const\n\tconst updateName = `${name}.update` as const\n\tconst archiveName = `${name}.archive` as const\n\tconst operations = Object.assign(\n\t\t{},\n\t\tnamedOperation(createName, {\n\t\t\tcommand: commandSchema,\n\t\t\tresult: createResult,\n\t\t\tclassification,\n\t\t\taggregates: [config.aggregateType],\n\t\t\tmiddleware: config.middleware,\n\t\t\tguard: config.guards?.create,\n\t\t\taudit: (resolution: { result: z.output<typeof createResult> }, context: Context) => ({\n\t\t\t\toperation: createName,\n\t\t\t\tactorId: config.actor(context),\n\t\t\t\taggregate: { type: config.aggregateType, id: resolution.result.id },\n\t\t\t}),\n\t\t}),\n\t\tnamedOperation(updateName, {\n\t\t\tcommand: updateInput,\n\t\t\tresult: okResult,\n\t\t\tclassification,\n\t\t\taggregates: [config.aggregateType],\n\t\t\tmiddleware: config.middleware,\n\t\t\tguard: config.guards?.update,\n\t\t\taudit: (resolution: { command: z.output<typeof updateInput> }, context: Context) => ({\n\t\t\t\toperation: updateName,\n\t\t\t\tactorId: config.actor(context),\n\t\t\t\taggregate: { type: config.aggregateType, id: resolution.command.id },\n\t\t\t}),\n\t\t}),\n\t\tnamedOperation(archiveName, {\n\t\t\tcommand: archiveInput,\n\t\t\tresult: okResult,\n\t\t\tclassification,\n\t\t\taggregates: [config.aggregateType],\n\t\t\tmiddleware: config.middleware,\n\t\t\tguard: config.guards?.archive,\n\t\t\taudit: (resolution: { command: z.output<typeof archiveInput> }, context: Context) => ({\n\t\t\t\toperation: archiveName,\n\t\t\t\tactorId: config.actor(context),\n\t\t\t\taggregate: { type: config.aggregateType, id: resolution.command.id },\n\t\t\t}),\n\t\t}),\n\t)\n\tconst commands: ApplicationCommand<Context, typeof operations> = new config.Command<\n\t\tContext,\n\t\ttypeof operations\n\t>(operations)\n\tconst executeCreate = commands.exec({\n\t\toperation: createName,\n\t\thandler: async (context, command) => {\n\t\t\tconst enrichment = config.enrich ? await config.enrich(context, command) : {}\n\t\t\tconst values: Record<string, Value> = {}\n\t\t\tfor (const [field, value] of Object.entries({ ...command, ...enrichment })) {\n\t\t\t\tif (value !== undefined) values[field] = value\n\t\t\t}\n\t\t\tconst inserted = await context.db.insert(name, values)\n\t\t\treturn { id: inserted }\n\t\t},\n\t})\n\tconst executeUpdate = commands.exec({\n\t\toperation: updateName,\n\t\thandler: async (context, command) => {\n\t\t\tawait context.db.patch(command.id, command.data)\n\t\t\treturn { ok: true }\n\t\t},\n\t})\n\tconst executeArchive = commands.exec({\n\t\toperation: archiveName,\n\t\thandler: async (context, command) => {\n\t\t\tawait context.db.patch(command.id, { archivedAt: Date.now() })\n\t\t\treturn { ok: true }\n\t\t},\n\t})\n\n\treturn {\n\t\tcommands,\n\t\toperations,\n\t\texecuteCreate,\n\t\texecuteUpdate,\n\t\texecuteArchive,\n\t}\n}\n\nfunction namedOperation<Name extends string, Definition extends AuditedOperation>(\n\tname: Name,\n\tdefinition: Definition,\n) {\n\t// SAFETY: this object contains exactly the computed name and its corresponding definition.\n\treturn { [name]: definition } as NamedOperation<Name, Definition>\n}\n\ntype NamedOperation<Name extends string, Definition extends AuditedOperation> = {\n\t[Key in Name]: Definition\n}\n"],"mappings":"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"}
package/dist/effect.d.mts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { OperationExecutor, OperationPublicResult, OperationTool, OperationToolConverter, OperationToolDefinition, OperationToolJsonSchema, OperationToolOutcome, SelectedOperation, bindOperationExecutor, createOperationTools, operationToolDialect, selectOperation } from "./modules/contracts/exposure.mjs";
2
2
  import { ContractDecoderError, ContractDecoderRequirements, ContractValidationError, EffectDecoder, decodeEffectContract, effectContract, effectSchema, effectStandardSchema } from "./modules/effect/schema.mjs";
3
3
  import { CallbackError, CallbackRequirements, EffectMiddlewareInput, EffectOperationArgument, EffectOperationError, EffectOperationHandlerResult, EffectOperationInput, EffectOperationRequirements, EffectOperationResult, EffectPreparation, EffectValue, effectOperationFactory } from "./modules/effect/operation.mjs";
4
+ import { EffectZodApiBuilder, effectZodApiBuilder } from "./modules/effect/api-zod.mjs";
5
+ import { EffectAuthFunctions, createEffectAuthFunctions } from "./modules/effect/auth.mjs";
4
6
  import { EffectFoundationOptions, createEffectFoundation } from "./modules/effect/foundation.mjs";
5
7
  import { EffectIdempotencyPreparation, effectTransactionalIdempotency } from "./modules/effect/idempotency.mjs";
6
8
  import { EffectCrudConfig, EffectCrudContext, EffectCrudPage, EffectCrudPagination, EffectCrudRepository, EffectCrudTable, createEffectCrud } from "./modules/effect/crud.mjs";
7
9
  import { EffectApiBuilder, effectApiBuilder } from "./modules/effect/api.mjs";
8
- import { EffectZodApiBuilder, effectZodApiBuilder } from "./modules/effect/api-zod.mjs";
9
10
  import { projectErrorCause } from "./modules/effect/errors.mjs";
10
11
  import { EffectReceiptProtectedWorkflowMutation, effectReceiptWorkflowMutation, effectTerminalWorkflowAttempt, effectWorkflowAttempt, effectWorkflowStatusBindings } from "./modules/effect/workflow.mjs";
11
12
  import "./modules/effect/client.mjs";
12
- export { type CallbackError, type CallbackRequirements, type ContractDecoderError, type ContractDecoderRequirements, ContractValidationError, type EffectApiBuilder, type EffectCrudConfig, type EffectCrudContext, type EffectCrudPage, type EffectCrudPagination, type EffectCrudRepository, type EffectCrudTable, type EffectDecoder, type EffectFoundationOptions, type EffectIdempotencyPreparation, type EffectMiddlewareInput, type EffectOperationArgument, type EffectOperationError, type EffectOperationHandlerResult, type EffectOperationInput, type EffectOperationRequirements, type EffectOperationResult, type EffectPreparation, type EffectReceiptProtectedWorkflowMutation, type EffectValue, type EffectZodApiBuilder, type OperationExecutor, type OperationPublicResult, type OperationTool, type OperationToolConverter, type OperationToolDefinition, type OperationToolJsonSchema, type OperationToolOutcome, type SelectedOperation, bindOperationExecutor, createEffectCrud, createEffectFoundation, createOperationTools, decodeEffectContract, effectApiBuilder, effectContract, effectOperationFactory, effectReceiptWorkflowMutation, effectSchema, effectStandardSchema, effectTerminalWorkflowAttempt, effectTransactionalIdempotency, effectWorkflowAttempt, effectWorkflowStatusBindings, effectZodApiBuilder, operationToolDialect, projectErrorCause, selectOperation };
13
+ export { type CallbackError, type CallbackRequirements, type ContractDecoderError, type ContractDecoderRequirements, ContractValidationError, type EffectApiBuilder, type EffectAuthFunctions, type EffectCrudConfig, type EffectCrudContext, type EffectCrudPage, type EffectCrudPagination, type EffectCrudRepository, type EffectCrudTable, type EffectDecoder, type EffectFoundationOptions, type EffectIdempotencyPreparation, type EffectMiddlewareInput, type EffectOperationArgument, type EffectOperationError, type EffectOperationHandlerResult, type EffectOperationInput, type EffectOperationRequirements, type EffectOperationResult, type EffectPreparation, type EffectReceiptProtectedWorkflowMutation, type EffectValue, type EffectZodApiBuilder, type OperationExecutor, type OperationPublicResult, type OperationTool, type OperationToolConverter, type OperationToolDefinition, type OperationToolJsonSchema, type OperationToolOutcome, type SelectedOperation, bindOperationExecutor, createEffectAuthFunctions, createEffectCrud, createEffectFoundation, createOperationTools, decodeEffectContract, effectApiBuilder, effectContract, effectOperationFactory, effectReceiptWorkflowMutation, effectSchema, effectStandardSchema, effectTerminalWorkflowAttempt, effectTransactionalIdempotency, effectWorkflowAttempt, effectWorkflowStatusBindings, effectZodApiBuilder, operationToolDialect, projectErrorCause, selectOperation };
package/dist/effect.mjs CHANGED
@@ -1 +1 @@
1
- import{bindOperationExecutor as e,createOperationTools as t,operationToolDialect as n,selectOperation as r}from"./modules/contracts/exposure.mjs";import{effectOperationFactory as i}from"./modules/effect/operation.mjs";import{ContractValidationError as a,decodeEffectContract as o,effectContract as s,effectSchema as c,effectStandardSchema as l}from"./modules/effect/schema.mjs";import{createEffectFoundation as u}from"./modules/effect/foundation.mjs";import{effectTransactionalIdempotency as d}from"./modules/effect/idempotency.mjs";import{createEffectCrud as f}from"./modules/effect/crud.mjs";import{projectErrorCause as p}from"./modules/effect/errors.mjs";import{effectApiBuilder as m}from"./modules/effect/api.mjs";import{effectZodApiBuilder as h}from"./modules/effect/api-zod.mjs";import{effectReceiptWorkflowMutation as g,effectTerminalWorkflowAttempt as _,effectWorkflowAttempt as v,effectWorkflowStatusBindings as y}from"./modules/effect/workflow.mjs";export{a as ContractValidationError,e as bindOperationExecutor,f as createEffectCrud,u as createEffectFoundation,t as createOperationTools,o as decodeEffectContract,m as effectApiBuilder,s as effectContract,i as effectOperationFactory,g as effectReceiptWorkflowMutation,c as effectSchema,l as effectStandardSchema,_ as effectTerminalWorkflowAttempt,d as effectTransactionalIdempotency,v as effectWorkflowAttempt,y as effectWorkflowStatusBindings,h as effectZodApiBuilder,n as operationToolDialect,p as projectErrorCause,r as selectOperation};
1
+ import{bindOperationExecutor as e,createOperationTools as t,operationToolDialect as n,selectOperation as r}from"./modules/contracts/exposure.mjs";import{projectErrorCause as i}from"./modules/effect/errors.mjs";import{effectZodApiBuilder as a}from"./modules/effect/api-zod.mjs";import{createEffectAuthFunctions as o}from"./modules/effect/auth.mjs";import{effectOperationFactory as s}from"./modules/effect/operation.mjs";import{ContractValidationError as c,decodeEffectContract as l,effectContract as u,effectSchema as d,effectStandardSchema as f}from"./modules/effect/schema.mjs";import{createEffectFoundation as p}from"./modules/effect/foundation.mjs";import{effectTransactionalIdempotency as m}from"./modules/effect/idempotency.mjs";import{createEffectCrud as h}from"./modules/effect/crud.mjs";import{effectApiBuilder as g}from"./modules/effect/api.mjs";import{effectReceiptWorkflowMutation as _,effectTerminalWorkflowAttempt as v,effectWorkflowAttempt as y,effectWorkflowStatusBindings as b}from"./modules/effect/workflow.mjs";export{c as ContractValidationError,e as bindOperationExecutor,o as createEffectAuthFunctions,h as createEffectCrud,p as createEffectFoundation,t as createOperationTools,l as decodeEffectContract,g as effectApiBuilder,u as effectContract,s as effectOperationFactory,_ as effectReceiptWorkflowMutation,d as effectSchema,f as effectStandardSchema,v as effectTerminalWorkflowAttempt,m as effectTransactionalIdempotency,y as effectWorkflowAttempt,b as effectWorkflowStatusBindings,a as effectZodApiBuilder,n as operationToolDialect,i as projectErrorCause,r as selectOperation};
package/dist/errors.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { DeclaredError, DeclaredFailure, DecodedFailure, ErrorContract, ErrorDefinitions, ErrorDetailParser, UnknownFailure, defineErrorContract } from "./modules/contracts/errors.mjs";
2
2
  //#region src/errors.d.ts
3
3
  /** Structured application error carried across Convex function boundaries. */
4
- declare class KitError extends Error {
4
+ export declare class KitError extends Error {
5
5
  readonly code: string;
6
6
  constructor(input: {
7
7
  code: string;
@@ -13,13 +13,13 @@ declare class KitError extends Error {
13
13
  * (e.g. an App.errors singleton) adapt it to this shape; everyone else uses
14
14
  * the default factory below.
15
15
  */
16
- type ErrorFactory = {
16
+ export type ErrorFactory = {
17
17
  throw(input: {
18
18
  code: string;
19
19
  message?: string;
20
20
  }): never;
21
21
  };
22
- declare const defaultErrors: ErrorFactory;
22
+ export declare const defaultErrors: ErrorFactory;
23
23
  //#endregion
24
- export { type DeclaredError, type DeclaredFailure, type DecodedFailure, type ErrorContract, type ErrorDefinitions, type ErrorDetailParser, ErrorFactory, KitError, type UnknownFailure, defaultErrors, defineErrorContract };
24
+ export { type DeclaredError, type DeclaredFailure, type DecodedFailure, type ErrorContract, type ErrorDefinitions, type ErrorDetailParser, type UnknownFailure, defineErrorContract };
25
25
  //# sourceMappingURL=errors.d.mts.map
@@ -1 +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\nexport {\n\tdefineErrorContract,\n\ttype ErrorContract,\n\ttype ErrorDefinitions,\n\ttype ErrorDetailParser,\n\ttype DeclaredError,\n\ttype DeclaredFailure,\n\ttype DecodedFailure,\n\ttype UnknownFailure,\n} from './modules/contracts/errors'\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":"qEACA,IAAa,EAAb,cAA8B,KAAM,CACnC,KAEA,YAAY,EAA2C,CACtD,MAAM,EAAM,SAAW,EAAM,IAAI,EACjC,KAAK,KAAO,WACZ,KAAK,KAAO,EAAM,IACnB,CACD,EAsBA,MAAa,EAA8B,CAC1C,MAAM,EAAO,CACZ,MAAM,IAAI,EAAS,CAAK,CACzB,CACD"}
1
+ {"version":3,"file":"errors.mjs","names":["KitError","input","defaultErrors","defineErrorContract"],"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\nexport {\n\tdefineErrorContract,\n\ttype ErrorContract,\n\ttype ErrorDefinitions,\n\ttype ErrorDetailParser,\n\ttype DeclaredError,\n\ttype DeclaredFailure,\n\ttype DecodedFailure,\n\ttype UnknownFailure,\n} from './modules/contracts/errors'\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":"qEACA,IAAaA,EAAb,cAA8B,KAAM,CACnC,KAEA,YAAY,EAA2C,CACtD,MAAMC,EAAM,SAAWA,EAAM,IAAI,EACjC,KAAK,KAAO,WACZ,KAAK,KAAOA,EAAM,IACnB,CACD,EAsBA,MAAaC,EAA8B,CAC1C,MAAM,EAAO,CACZ,MAAM,IAAIF,EAASC,CAAK,CACzB,CACD"}
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AgentToolHandlers, AgentToolRecord, createAgentTools } from "./agent-tools.mjs";
2
2
  import { ErrorFactory, KitError, defaultErrors } from "./errors.mjs";
3
3
  import { RLSConfig, Rules, TENANT_FIELD, assertTenantOwned, composeRules, createTenantRules, requireTenantReference } from "./tenancy.mjs";
4
- import { Actor, AuthBundle, AuthFunctionsConfig, DefaultRole, Include, IncludedQuery, SecurityConfig, createAuthFunctions, createInclude, defaultRoleMap } from "./auth.mjs";
4
+ import { Actor, AuthBundle, AuthFunctions, AuthFunctionsConfig, DefaultRole, Include, IncludedQuery, SecurityConfig, createAuthFunctions, createInclude, defaultRoleMap } from "./auth.mjs";
5
5
  import { AnyQueryMiddleware, QueryMiddleware } from "./components/foundation/modules/query/query.mjs";
6
6
  import { AnyCommandMiddleware, ApplicationCommand, AuditEntryInput, AuditWriter, AuditedOperation, AuditedRegistry, CommandConstructor, CommandDefaults, CommandMiddleware, Foundation, FoundationOptions, PermissionChecker } from "./components/foundation/client.mjs";
7
7
  import { CrudConfig, createCrudCommands } from "./crud.mjs";
@@ -10,4 +10,4 @@ import { RateLimiterLike, rateLimit } from "./middleware.mjs";
10
10
  import { WebhookBoundaryConfig, createWebhookBoundary, recordWebhookEvent, webhookEventsTable } from "./webhooks.mjs";
11
11
  import { createStateMachine } from "./state-machine.mjs";
12
12
  import { Change, Trigger, Triggers, appendOnly, createTriggers, noDelete, tenantOwnership, timestamps } from "./triggers.mjs";
13
- export { type Actor, type AgentToolHandlers, type AgentToolRecord, type AnyCommandMiddleware, type AnyQueryMiddleware, type ApplicationCommand, type AuditEntryInput, type AuditWriter, type AuditedOperation, type AuditedRegistry, type AuthBundle, type AuthFunctionsConfig, type Change, type CommandConstructor, type CommandDefaults, type CommandMiddleware, type CrudConfig, type DefaultRole, type ErrorFactory, Foundation, type FoundationOptions, type Include, type IncludedQuery, KitError, type PermissionChecker, type QueryMiddleware, type RLSConfig, type RateLimiterLike, type Rules, type SecurityConfig, TENANT_FIELD, TIMESTAMP_FIELDS, type TableBoundaryOptions, type Trigger, Triggers, type WebhookBoundaryConfig, appendOnly, assertTenantOwned, composeRules, createAgentTools, createAuthFunctions, createCrudCommands, createInclude, createModule, createStateMachine, createTenantRules, createTriggers, createWebhookBoundary, defaultErrors, defaultRoleMap, jsonSafeZid, noDelete, paginated, rateLimit, recordWebhookEvent, requireTenantReference, tenantOwnership, tenantTable, timestamps, webhookEventsTable, zodTable, zodVariantTable };
13
+ export { type Actor, type AgentToolHandlers, type AgentToolRecord, type AnyCommandMiddleware, type AnyQueryMiddleware, type ApplicationCommand, type AuditEntryInput, type AuditWriter, type AuditedOperation, type AuditedRegistry, type AuthBundle, type AuthFunctions, type AuthFunctionsConfig, type Change, type CommandConstructor, type CommandDefaults, type CommandMiddleware, type CrudConfig, type DefaultRole, type ErrorFactory, Foundation, type FoundationOptions, type Include, type IncludedQuery, KitError, type PermissionChecker, type QueryMiddleware, type RLSConfig, type RateLimiterLike, type Rules, type SecurityConfig, TENANT_FIELD, TIMESTAMP_FIELDS, type TableBoundaryOptions, type Trigger, Triggers, type WebhookBoundaryConfig, appendOnly, assertTenantOwned, composeRules, createAgentTools, createAuthFunctions, createCrudCommands, createInclude, createModule, createStateMachine, createTenantRules, createTriggers, createWebhookBoundary, defaultErrors, defaultRoleMap, jsonSafeZid, noDelete, paginated, rateLimit, recordWebhookEvent, requireTenantReference, tenantOwnership, tenantTable, timestamps, webhookEventsTable, zodTable, zodVariantTable };
@@ -6,7 +6,7 @@ import { ErrorFactory } from "./errors.mjs";
6
6
  * constructs the limiter; the kit only ever receives the instance —
7
7
  * injection keeps the kit dependency-free.
8
8
  */
9
- type RateLimiterLike = {
9
+ export type RateLimiterLike = {
10
10
  limit: (ctx: never, name: string, options?: {
11
11
  key?: string;
12
12
  }) => Promise<{
@@ -24,7 +24,7 @@ type RateLimiterLike = {
24
24
  * The returned middleware is shape-compatible with both AnyCommandMiddleware
25
25
  * and AnyQueryMiddleware.
26
26
  */
27
- declare function rateLimit<Context = never>(config: {
27
+ export declare function rateLimit<Context = never>(config: {
28
28
  limiter: RateLimiterLike;
29
29
  name: string;
30
30
  /** Defaults to ctx.tenant. */
@@ -42,5 +42,4 @@ declare function rateLimit<Context = never>(config: {
42
42
  }) => Promise<Result>;
43
43
  }) => Promise<Result>;
44
44
  //#endregion
45
- export { RateLimiterLike, rateLimit };
46
45
  //# sourceMappingURL=middleware.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.mjs","names":[],"sources":["../src/middleware.ts"],"sourcesContent":["import { z } from 'zod'\nimport { defaultErrors, type ErrorFactory } from './errors'\n\n/**\n * Structural surface of @convex-dev/rate-limiter's RateLimiter (checked\n * against 0.3.x; re-verify at install). The host mounts the component and\n * constructs the limiter; the kit only ever receives the instance —\n * injection keeps the kit dependency-free.\n */\nexport type RateLimiterLike = {\n\tlimit: (\n\t\tctx: never,\n\t\tname: string,\n\t\toptions?: { key?: string },\n\t) => Promise<{ ok: boolean; retryAfter?: number }>\n}\n\n/**\n * The first packaged middleware: rate limiting on the Command/Query\n * middleware seams. Runs before guards and the handler; a rejected call\n * throws RATE_LIMITED (audit and handler never run). Keyed by ctx.tenant by\n * default — when no key fn is given and ctx.tenant is undefined, this is a\n * configuration error, not a silent shared bucket.\n *\n * The returned middleware is shape-compatible with both AnyCommandMiddleware\n * and AnyQueryMiddleware.\n */\nexport function rateLimit<Context = never>(config: {\n\tlimiter: RateLimiterLike\n\tname: string\n\t/** Defaults to ctx.tenant. */\n\tkey?: (context: Context) => string\n\t/** Observe a rejection before the throw (metrics, headers). */\n\tonLimit?: (status: { ok: boolean; retryAfter?: number }, context: Context) => void | Promise<void>\n\terrors?: ErrorFactory\n}) {\n\tconst errors = config.errors ?? defaultErrors\n\treturn async <Result>(input: {\n\t\tcontext: never\n\t\tnext: (options?: { context?: object }) => Promise<Result>\n\t}): Promise<Result> => {\n\t\tconst key = config.key ? config.key(input.context) : tenantContext.parse(input.context).tenant\n\t\tif (key === undefined) {\n\t\t\treturn errors.throw({\n\t\t\t\tcode: 'RATE_LIMIT_KEY_MISSING',\n\t\t\t\tmessage: `rateLimit(\"${config.name}\") has no key: ctx.tenant is undefined and no key fn was configured`,\n\t\t\t})\n\t\t}\n\t\tconst status = await config.limiter.limit(input.context, config.name, {\n\t\t\tkey,\n\t\t})\n\t\tif (!status.ok) {\n\t\t\tawait config.onLimit?.(status, input.context)\n\t\t\treturn errors.throw({\n\t\t\t\tcode: 'RATE_LIMITED',\n\t\t\t\tmessage: `Rate limit \"${config.name}\" exceeded${\n\t\t\t\t\tstatus.retryAfter === undefined ? '' : `; retry after ${Math.ceil(status.retryAfter)}ms`\n\t\t\t\t}`,\n\t\t\t})\n\t\t}\n\t\treturn input.next()\n\t}\n}\n\nconst tenantContext = z.object({ tenant: z.string().optional() })\n"],"mappings":"qEA2BA,SAAgB,EAA2B,EAQxC,CACF,IAAM,EAAS,EAAO,QAAU,EAChC,OAAO,KAAe,IAGC,CACtB,IAAM,EAAM,EAAO,IAAM,EAAO,IAAI,EAAM,OAAO,EAAI,EAAc,MAAM,EAAM,OAAO,CAAC,CAAC,OACxF,GAAI,IAAQ,IAAA,GACX,OAAO,EAAO,MAAM,CACnB,KAAM,yBACN,QAAS,cAAc,EAAO,KAAK,oEACpC,CAAC,EAEF,IAAM,EAAS,MAAM,EAAO,QAAQ,MAAM,EAAM,QAAS,EAAO,KAAM,CACrE,KACD,CAAC,EAUD,OATK,EAAO,GASL,EAAM,KAAK,GARjB,MAAM,EAAO,UAAU,EAAQ,EAAM,OAAO,EACrC,EAAO,MAAM,CACnB,KAAM,eACN,QAAS,eAAe,EAAO,KAAK,YACnC,EAAO,aAAe,IAAA,GAAY,GAAK,iBAAiB,KAAK,KAAK,EAAO,UAAU,EAAE,KAEvF,CAAC,EAGH,CACD,CAEA,MAAM,EAAgB,EAAE,OAAO,CAAE,OAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,CAAE,CAAC"}
1
+ {"version":3,"file":"middleware.mjs","names":["rateLimit","errors","config","defaultErrors","key","input","tenantContext","status","z"],"sources":["../src/middleware.ts"],"sourcesContent":["import { z } from 'zod'\nimport { defaultErrors, type ErrorFactory } from './errors'\n\n/**\n * Structural surface of @convex-dev/rate-limiter's RateLimiter (checked\n * against 0.3.x; re-verify at install). The host mounts the component and\n * constructs the limiter; the kit only ever receives the instance —\n * injection keeps the kit dependency-free.\n */\nexport type RateLimiterLike = {\n\tlimit: (\n\t\tctx: never,\n\t\tname: string,\n\t\toptions?: { key?: string },\n\t) => Promise<{ ok: boolean; retryAfter?: number }>\n}\n\n/**\n * The first packaged middleware: rate limiting on the Command/Query\n * middleware seams. Runs before guards and the handler; a rejected call\n * throws RATE_LIMITED (audit and handler never run). Keyed by ctx.tenant by\n * default — when no key fn is given and ctx.tenant is undefined, this is a\n * configuration error, not a silent shared bucket.\n *\n * The returned middleware is shape-compatible with both AnyCommandMiddleware\n * and AnyQueryMiddleware.\n */\nexport function rateLimit<Context = never>(config: {\n\tlimiter: RateLimiterLike\n\tname: string\n\t/** Defaults to ctx.tenant. */\n\tkey?: (context: Context) => string\n\t/** Observe a rejection before the throw (metrics, headers). */\n\tonLimit?: (status: { ok: boolean; retryAfter?: number }, context: Context) => void | Promise<void>\n\terrors?: ErrorFactory\n}) {\n\tconst errors = config.errors ?? defaultErrors\n\treturn async <Result>(input: {\n\t\tcontext: never\n\t\tnext: (options?: { context?: object }) => Promise<Result>\n\t}): Promise<Result> => {\n\t\tconst key = config.key ? config.key(input.context) : tenantContext.parse(input.context).tenant\n\t\tif (key === undefined) {\n\t\t\treturn errors.throw({\n\t\t\t\tcode: 'RATE_LIMIT_KEY_MISSING',\n\t\t\t\tmessage: `rateLimit(\"${config.name}\") has no key: ctx.tenant is undefined and no key fn was configured`,\n\t\t\t})\n\t\t}\n\t\tconst status = await config.limiter.limit(input.context, config.name, {\n\t\t\tkey,\n\t\t})\n\t\tif (!status.ok) {\n\t\t\tawait config.onLimit?.(status, input.context)\n\t\t\treturn errors.throw({\n\t\t\t\tcode: 'RATE_LIMITED',\n\t\t\t\tmessage: `Rate limit \"${config.name}\" exceeded${\n\t\t\t\t\tstatus.retryAfter === undefined ? '' : `; retry after ${Math.ceil(status.retryAfter)}ms`\n\t\t\t\t}`,\n\t\t\t})\n\t\t}\n\t\treturn input.next()\n\t}\n}\n\nconst tenantContext = z.object({ tenant: z.string().optional() })\n"],"mappings":"qEA2BA,SAAgBA,EAA2B,EAQxC,CACF,IAAMC,EAASC,EAAO,QAAUC,EAChC,OAAO,KAAe,IAGC,CACtB,IAAMC,EAAMF,EAAO,IAAMA,EAAO,IAAIG,EAAM,OAAO,EAAIC,EAAc,MAAMD,EAAM,OAAO,CAAC,CAAC,OACxF,GAAID,IAAQ,IAAA,GACX,OAAOH,EAAO,MAAM,CACnB,KAAM,yBACN,QAAS,cAAcC,EAAO,KAAK,oEACpC,CAAC,EAEF,IAAMK,EAAS,MAAML,EAAO,QAAQ,MAAMG,EAAM,QAASH,EAAO,KAAM,CACrE,KACD,CAAC,EAUD,OATKK,EAAO,GASLF,EAAM,KAAK,GARjB,MAAMH,EAAO,UAAUK,EAAQF,EAAM,OAAO,EACrCJ,EAAO,MAAM,CACnB,KAAM,eACN,QAAS,eAAeC,EAAO,KAAK,YACnCK,EAAO,aAAe,IAAA,GAAY,GAAK,iBAAiB,KAAK,KAAKA,EAAO,UAAU,EAAE,KAEvF,CAAC,EAGH,CACD,CAEA,MAAMD,EAAgBE,EAAE,OAAO,CAAE,OAAQA,EAAE,OAAO,CAAC,CAAC,SAAS,CAAE,CAAC"}
@@ -1,6 +1,6 @@
1
1
  //#region src/modules/contracts/contract.d.ts
2
2
  /** Structural contracts keep the optional Effect peer out of this module. */
3
- interface StandardSchema<Input = unknown, Output = Input> {
3
+ export interface StandardSchema<Input = unknown, Output = Input> {
4
4
  readonly '~standard': {
5
5
  readonly version: 1;
6
6
  readonly vendor: string;
@@ -11,24 +11,24 @@ interface StandardSchema<Input = unknown, Output = Input> {
11
11
  readonly validate: (value: unknown) => ValidationResult<Output> | Promise<ValidationResult<Output>>;
12
12
  };
13
13
  }
14
- interface ValidationIssue {
14
+ export interface ValidationIssue {
15
15
  readonly message: string;
16
16
  readonly path?: readonly (PropertyKey | {
17
17
  readonly key: PropertyKey;
18
18
  })[];
19
19
  }
20
- type ValidationResult<Output> = {
20
+ export type ValidationResult<Output> = {
21
21
  readonly value: Output;
22
22
  readonly issues?: undefined;
23
23
  } | {
24
24
  readonly issues: readonly ValidationIssue[];
25
25
  };
26
- interface LegacyParser<Output = unknown> {
26
+ export interface LegacyParser<Output = unknown> {
27
27
  readonly parse: (value: unknown) => Output;
28
28
  readonly parseAsync?: (value: unknown) => Promise<Output>;
29
29
  }
30
30
  /** Decode execution is an opaque channel here; optional adapters give it concrete semantics. */
31
- interface Decoder<Input = unknown, Output = unknown, Execution = unknown> {
31
+ export interface Decoder<Input = unknown, Output = unknown, Execution = unknown> {
32
32
  readonly kind: 'contract' | 'effect-contract';
33
33
  readonly types?: {
34
34
  readonly input: Input;
@@ -36,19 +36,19 @@ interface Decoder<Input = unknown, Output = unknown, Execution = unknown> {
36
36
  };
37
37
  readonly decode: (value: unknown) => Execution;
38
38
  }
39
- type ContractSchema = LegacyParser | StandardSchema<unknown, unknown> | Decoder;
40
- type NeutralSchema = LegacyParser | StandardSchema<unknown, unknown> | (Decoder<unknown, unknown, ValidationResult<unknown> | Promise<ValidationResult<unknown>>> & {
39
+ export type ContractSchema = LegacyParser | StandardSchema<unknown, unknown> | Decoder;
40
+ export type NeutralSchema = LegacyParser | StandardSchema<unknown, unknown> | (Decoder<unknown, unknown, ValidationResult<unknown> | Promise<ValidationResult<unknown>>> & {
41
41
  readonly kind: 'contract';
42
42
  });
43
- type ContractInput<S> = S extends Decoder<infer Input, unknown, unknown> ? Input : S extends StandardSchema<infer Input, unknown> ? Input : S extends {
43
+ export type ContractInput<S> = S extends Decoder<infer Input, unknown, unknown> ? Input : S extends StandardSchema<infer Input, unknown> ? Input : S extends {
44
44
  readonly _input: infer Input;
45
45
  } ? Input : S extends LegacyParser<infer Output> ? Awaited<Output> : never;
46
- type ContractOutput<S> = S extends Decoder<unknown, infer Output, unknown> ? Output : S extends StandardSchema<unknown, infer Output> ? Output : S extends LegacyParser<infer Output> ? Awaited<Output> : never;
47
- type ContractExecution<S> = S extends Decoder<unknown, unknown, infer Execution> ? Execution : never;
46
+ export type ContractOutput<S> = S extends Decoder<unknown, infer Output, unknown> ? Output : S extends StandardSchema<unknown, infer Output> ? Output : S extends LegacyParser<infer Output> ? Awaited<Output> : never;
47
+ export type ContractExecution<S> = S extends Decoder<unknown, unknown, infer Execution> ? Execution : never;
48
48
  /** Validation failures are values. Throws/rejections are deliberately left as defects. */
49
- declare function decodeContract<S extends NeutralSchema>(schema: S, value: unknown): Promise<ValidationResult<ContractOutput<S>>>;
49
+ export declare function decodeContract<S extends NeutralSchema>(schema: S, value: unknown): Promise<ValidationResult<ContractOutput<S>>>;
50
50
  /** Independent final and wire contracts never reuse the fresh-result transform. */
51
- declare function operationContract<const Input extends ContractSchema, const Result extends ContractSchema, const Replay extends ContractSchema, const Wire extends ContractSchema, const Definition extends object>(definition: Definition & {
51
+ export declare function operationContract<const Input extends ContractSchema, const Result extends ContractSchema, const Replay extends ContractSchema, const Wire extends ContractSchema, const Definition extends object>(definition: Definition & {
52
52
  input: Input;
53
53
  result: Result;
54
54
  replayResult: Replay & (ContractOutput<Replay> extends ContractOutput<Result> ? unknown : never);
@@ -66,5 +66,4 @@ declare function operationContract<const Input extends ContractSchema, const Res
66
66
  };
67
67
  };
68
68
  //#endregion
69
- export { ContractExecution, ContractInput, ContractOutput, ContractSchema, Decoder, LegacyParser, NeutralSchema, StandardSchema, ValidationIssue, ValidationResult, decodeContract, operationContract };
70
69
  //# sourceMappingURL=contract.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.mjs","names":[],"sources":["../../../src/modules/contracts/contract.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters -- These explicit validation boundaries receive untrusted transport values before schema decoding. */\n/** Structural contracts keep the optional Effect peer out of this module. */\nexport interface StandardSchema<Input = unknown, Output = Input> {\n\treadonly '~standard': {\n\t\treadonly version: 1\n\t\treadonly vendor: string\n\t\treadonly types?: { readonly input: Input; readonly output: Output }\n\t\treadonly validate: (\n\t\t\tvalue: unknown,\n\t\t) => ValidationResult<Output> | Promise<ValidationResult<Output>>\n\t}\n}\nexport interface ValidationIssue {\n\treadonly message: string\n\treadonly path?: readonly (PropertyKey | { readonly key: PropertyKey })[]\n}\nexport type ValidationResult<Output> =\n\t| { readonly value: Output; readonly issues?: undefined }\n\t| { readonly issues: readonly ValidationIssue[] }\nexport interface LegacyParser<Output = unknown> {\n\treadonly parse: (value: unknown) => Output\n\treadonly parseAsync?: (value: unknown) => Promise<Output>\n}\n/** Decode execution is an opaque channel here; optional adapters give it concrete semantics. */\nexport interface Decoder<Input = unknown, Output = unknown, Execution = unknown> {\n\treadonly kind: 'contract' | 'effect-contract'\n\treadonly types?: { readonly input: Input; readonly output: Output }\n\treadonly decode: (value: unknown) => Execution\n}\nexport type ContractSchema = LegacyParser | StandardSchema<unknown, unknown> | Decoder\nexport type NeutralSchema =\n\t| LegacyParser\n\t| StandardSchema<unknown, unknown>\n\t| (Decoder<unknown, unknown, ValidationResult<unknown> | Promise<ValidationResult<unknown>>> & {\n\t\t\treadonly kind: 'contract'\n\t })\nexport type ContractInput<S> =\n\tS extends Decoder<infer Input, unknown, unknown>\n\t\t? Input\n\t\t: S extends StandardSchema<infer Input, unknown>\n\t\t\t? Input\n\t\t\t: S extends { readonly _input: infer Input }\n\t\t\t\t? Input\n\t\t\t\t: S extends LegacyParser<infer Output>\n\t\t\t\t\t? Awaited<Output>\n\t\t\t\t\t: never\nexport type ContractOutput<S> =\n\tS extends Decoder<unknown, infer Output, unknown>\n\t\t? Output\n\t\t: S extends StandardSchema<unknown, infer Output>\n\t\t\t? Output\n\t\t\t: S extends LegacyParser<infer Output>\n\t\t\t\t? Awaited<Output>\n\t\t\t\t: never\nexport type ContractExecution<S> =\n\tS extends Decoder<unknown, unknown, infer Execution> ? Execution : never\n\n/** Validation failures are values. Throws/rejections are deliberately left as defects. */\nexport async function decodeContract<S extends NeutralSchema>(\n\tschema: S,\n\tvalue: unknown,\n): Promise<ValidationResult<ContractOutput<S>>> {\n\tlet result: ValidationResult<unknown>\n\tif ('kind' in schema) result = await schema.decode(value)\n\telse if ('parse' in schema)\n\t\tresult = { value: await (schema.parseAsync ? schema.parseAsync(value) : schema.parse(value)) }\n\telse result = await schema['~standard'].validate(value)\n\t// SAFETY: each branch returns the output associated with this exact schema.\n\treturn result as ValidationResult<ContractOutput<S>>\n}\n\n/** Independent final and wire contracts never reuse the fresh-result transform. */\nexport function operationContract<\n\tconst Input extends ContractSchema,\n\tconst Result extends ContractSchema,\n\tconst Replay extends ContractSchema,\n\tconst Wire extends ContractSchema,\n\tconst Definition extends object,\n>(\n\tdefinition: Definition & {\n\t\tinput: Input\n\t\tresult: Result\n\t\treplayResult: Replay & (ContractOutput<Replay> extends ContractOutput<Result> ? unknown : never)\n\t\twire: { project: (value: ContractOutput<Result>) => ContractInput<Wire>; schema: Wire }\n\t},\n) {\n\treturn definition\n}\n"],"mappings":"AA0DA,eAAsB,EACrB,EACA,EAC+C,CAC/C,IAAI,EAMJ,MALA,CAGK,EAHD,SAAU,EAAiB,MAAM,EAAO,OAAO,CAAK,EAC/C,UAAW,EACV,CAAE,MAAO,MAAO,EAAO,WAAa,EAAO,WAAW,CAAK,EAAI,EAAO,MAAM,CAAK,EAAG,EAChF,MAAM,EAAO,YAAY,CAAC,SAAS,CAAK,EAE/C,CACR,CAGA,SAAgB,EAOf,EAMC,CACD,OAAO,CACR"}
1
+ {"version":3,"file":"contract.mjs","names":["decodeContract","result","schema","value","operationContract","definition"],"sources":["../../../src/modules/contracts/contract.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters -- These explicit validation boundaries receive untrusted transport values before schema decoding. */\n/** Structural contracts keep the optional Effect peer out of this module. */\nexport interface StandardSchema<Input = unknown, Output = Input> {\n\treadonly '~standard': {\n\t\treadonly version: 1\n\t\treadonly vendor: string\n\t\treadonly types?: { readonly input: Input; readonly output: Output }\n\t\treadonly validate: (\n\t\t\tvalue: unknown,\n\t\t) => ValidationResult<Output> | Promise<ValidationResult<Output>>\n\t}\n}\nexport interface ValidationIssue {\n\treadonly message: string\n\treadonly path?: readonly (PropertyKey | { readonly key: PropertyKey })[]\n}\nexport type ValidationResult<Output> =\n\t| { readonly value: Output; readonly issues?: undefined }\n\t| { readonly issues: readonly ValidationIssue[] }\nexport interface LegacyParser<Output = unknown> {\n\treadonly parse: (value: unknown) => Output\n\treadonly parseAsync?: (value: unknown) => Promise<Output>\n}\n/** Decode execution is an opaque channel here; optional adapters give it concrete semantics. */\nexport interface Decoder<Input = unknown, Output = unknown, Execution = unknown> {\n\treadonly kind: 'contract' | 'effect-contract'\n\treadonly types?: { readonly input: Input; readonly output: Output }\n\treadonly decode: (value: unknown) => Execution\n}\nexport type ContractSchema = LegacyParser | StandardSchema<unknown, unknown> | Decoder\nexport type NeutralSchema =\n\t| LegacyParser\n\t| StandardSchema<unknown, unknown>\n\t| (Decoder<unknown, unknown, ValidationResult<unknown> | Promise<ValidationResult<unknown>>> & {\n\t\t\treadonly kind: 'contract'\n\t })\nexport type ContractInput<S> =\n\tS extends Decoder<infer Input, unknown, unknown>\n\t\t? Input\n\t\t: S extends StandardSchema<infer Input, unknown>\n\t\t\t? Input\n\t\t\t: S extends { readonly _input: infer Input }\n\t\t\t\t? Input\n\t\t\t\t: S extends LegacyParser<infer Output>\n\t\t\t\t\t? Awaited<Output>\n\t\t\t\t\t: never\nexport type ContractOutput<S> =\n\tS extends Decoder<unknown, infer Output, unknown>\n\t\t? Output\n\t\t: S extends StandardSchema<unknown, infer Output>\n\t\t\t? Output\n\t\t\t: S extends LegacyParser<infer Output>\n\t\t\t\t? Awaited<Output>\n\t\t\t\t: never\nexport type ContractExecution<S> =\n\tS extends Decoder<unknown, unknown, infer Execution> ? Execution : never\n\n/** Validation failures are values. Throws/rejections are deliberately left as defects. */\nexport async function decodeContract<S extends NeutralSchema>(\n\tschema: S,\n\tvalue: unknown,\n): Promise<ValidationResult<ContractOutput<S>>> {\n\tlet result: ValidationResult<unknown>\n\tif ('kind' in schema) result = await schema.decode(value)\n\telse if ('parse' in schema)\n\t\tresult = { value: await (schema.parseAsync ? schema.parseAsync(value) : schema.parse(value)) }\n\telse result = await schema['~standard'].validate(value)\n\t// SAFETY: each branch returns the output associated with this exact schema.\n\treturn result as ValidationResult<ContractOutput<S>>\n}\n\n/** Independent final and wire contracts never reuse the fresh-result transform. */\nexport function operationContract<\n\tconst Input extends ContractSchema,\n\tconst Result extends ContractSchema,\n\tconst Replay extends ContractSchema,\n\tconst Wire extends ContractSchema,\n\tconst Definition extends object,\n>(\n\tdefinition: Definition & {\n\t\tinput: Input\n\t\tresult: Result\n\t\treplayResult: Replay & (ContractOutput<Replay> extends ContractOutput<Result> ? unknown : never)\n\t\twire: { project: (value: ContractOutput<Result>) => ContractInput<Wire>; schema: Wire }\n\t},\n) {\n\treturn definition\n}\n"],"mappings":"AA0DA,eAAsBA,EACrB,EACA,EAC+C,CAC/C,IAAIC,EAMJ,MALA,CAGKA,EAHD,SAAUC,EAAiB,MAAMA,EAAO,OAAOC,CAAK,EAC/C,UAAWD,EACV,CAAE,MAAO,MAAOA,EAAO,WAAaA,EAAO,WAAWC,CAAK,EAAID,EAAO,MAAMC,CAAK,EAAG,EAChF,MAAMD,EAAO,YAAY,CAAC,SAASC,CAAK,EAE/CF,CACR,CAGA,SAAgBG,EAOf,EAMC,CACD,OAAOC,CACR"}
@@ -1,10 +1,9 @@
1
1
  import { ValidationResult } from "./contract.mjs";
2
- import { StandardSchemaV1 } from "../../node_modules/@standard-schema/spec/dist/index.mjs";
3
2
  import { GenericDataModel, GenericDatabaseReader } from "convex/server";
4
3
  import { Infer, Validator } from "convex/values";
5
4
  //#region src/modules/contracts/convex.d.ts
6
5
  /** Keep native registration authoritative, especially for actions with no db. */
7
- declare function convexContract<const V extends Validator<unknown, 'required' | 'optional', string>>(validator: V, options?: {
6
+ export declare function convexContract<const V extends Validator<unknown, 'required' | 'optional', string>>(validator: V, options?: {
8
7
  db?: GenericDatabaseReader<GenericDataModel>;
9
8
  }): {
10
9
  kind: "contract";
@@ -13,10 +12,9 @@ declare function convexContract<const V extends Validator<unknown, 'required' |
13
12
  readonly output: Infer<V>;
14
13
  } | undefined;
15
14
  decode: (value: unknown) => Promise<ValidationResult<Infer<V>>> | ValidationResult<Infer<V>>;
16
- schema: StandardSchemaV1<Infer<V>, Infer<V>>;
15
+ schema: import("@standard-schema/spec").StandardSchemaV1<Infer<V>, Infer<V>>;
17
16
  nativeValidator: V;
18
17
  };
19
- type ConvexContractValue<V extends Validator<unknown, 'required' | 'optional', string>> = Infer<V>;
18
+ export type ConvexContractValue<V extends Validator<unknown, 'required' | 'optional', string>> = Infer<V>;
20
19
  //#endregion
21
- export { ConvexContractValue, convexContract };
22
20
  //# sourceMappingURL=convex.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convex.mjs","names":[],"sources":["../../../src/modules/contracts/convex.ts"],"sourcesContent":["import type { GenericDatabaseReader, GenericDataModel } from 'convex/server'\nimport type { Infer, Validator } from 'convex/values'\nimport { toStandardSchema } from 'convex-helpers/standardSchema'\nimport { standardContract } from './standard'\n\n/** Keep native registration authoritative, especially for actions with no db. */\nexport function convexContract<const V extends Validator<unknown, 'required' | 'optional', string>>(\n\tvalidator: V,\n\toptions?: { db?: GenericDatabaseReader<GenericDataModel> },\n) {\n\treturn { ...standardContract(toStandardSchema(validator, options)), nativeValidator: validator }\n}\nexport type ConvexContractValue<V extends Validator<unknown, 'required' | 'optional', string>> =\n\tInfer<V>\n"],"mappings":"mHAMA,SAAgB,EACf,EACA,EACC,CACD,MAAO,CAAE,GAAG,EAAiB,EAAiB,EAAW,CAAO,CAAC,EAAG,gBAAiB,CAAU,CAChG"}
1
+ {"version":3,"file":"convex.mjs","names":["convexContract","standardContract","toStandardSchema","validator","options"],"sources":["../../../src/modules/contracts/convex.ts"],"sourcesContent":["import type { GenericDatabaseReader, GenericDataModel } from 'convex/server'\nimport type { Infer, Validator } from 'convex/values'\nimport { toStandardSchema } from 'convex-helpers/standardSchema'\nimport { standardContract } from './standard'\n\n/** Keep native registration authoritative, especially for actions with no db. */\nexport function convexContract<const V extends Validator<unknown, 'required' | 'optional', string>>(\n\tvalidator: V,\n\toptions?: { db?: GenericDatabaseReader<GenericDataModel> },\n) {\n\treturn { ...standardContract(toStandardSchema(validator, options)), nativeValidator: validator }\n}\nexport type ConvexContractValue<V extends Validator<unknown, 'required' | 'optional', string>> =\n\tInfer<V>\n"],"mappings":"mHAMA,SAAgBA,EACf,EACA,EACC,CACD,MAAO,CAAE,GAAGC,EAAiBC,EAAiBC,EAAWC,CAAO,CAAC,EAAG,gBAAiBD,CAAU,CAChG"}
@@ -1,9 +1,9 @@
1
1
  //#region src/modules/contracts/errors.d.ts
2
2
  /** Explicit synchronous validators for the final public detail representation. */
3
- type ErrorDetailParser<Output = unknown> = Readonly<{
3
+ export type ErrorDetailParser<Output = unknown> = Readonly<{
4
4
  parse: (value: unknown) => Output;
5
5
  }>;
6
- type ErrorDefinitions = Readonly<Record<string, Readonly<{
6
+ export type ErrorDefinitions = Readonly<Record<string, Readonly<{
7
7
  message: string;
8
8
  details: Readonly<Record<string, ErrorDetailParser>>;
9
9
  }>>>;
@@ -11,25 +11,25 @@ type Code<Definitions extends ErrorDefinitions> = Extract<keyof Definitions, str
11
11
  type Details<Definition extends ErrorDefinitions[string]> = Definition extends ErrorDefinitions[string] ? { [Field in keyof Definition['details']]: ReturnType<Definition['details'][Field]['parse']>; } : never;
12
12
  declare const declaredErrorBrand: unique symbol;
13
13
  /** Server failures are trusted only by the contract that created them. */
14
- type DeclaredError<Definitions extends ErrorDefinitions> = { [Key in Code<Definitions>]: Readonly<{
14
+ export type DeclaredError<Definitions extends ErrorDefinitions> = { [Key in Code<Definitions>]: Readonly<{
15
15
  _tag: 'DeclaredError';
16
16
  code: Key;
17
17
  details: Details<Definitions[Key]>;
18
18
  [declaredErrorBrand]: true;
19
19
  }>; }[Code<Definitions>];
20
- type DeclaredFailure<Definitions extends ErrorDefinitions> = { [Key in Code<Definitions>]: Readonly<{
20
+ export type DeclaredFailure<Definitions extends ErrorDefinitions> = { [Key in Code<Definitions>]: Readonly<{
21
21
  _tag: 'DeclaredFailure';
22
22
  version: 1;
23
23
  code: Key;
24
24
  message: string;
25
25
  details: Details<Definitions[Key]>;
26
26
  }>; }[Code<Definitions>];
27
- type UnknownFailure = Readonly<{
27
+ export type UnknownFailure = Readonly<{
28
28
  _tag: 'UnknownFailure';
29
29
  version: 1;
30
30
  }>;
31
- type DecodedFailure<Definitions extends ErrorDefinitions> = DeclaredFailure<Definitions> | UnknownFailure;
32
- type ErrorContract<Definitions extends ErrorDefinitions> = Readonly<{
31
+ export type DecodedFailure<Definitions extends ErrorDefinitions> = DeclaredFailure<Definitions> | UnknownFailure;
32
+ export type ErrorContract<Definitions extends ErrorDefinitions> = Readonly<{
33
33
  create: <Key extends Code<Definitions>>(code: Key, details: Details<Definitions[NoInfer<Key>]>) => Extract<DeclaredError<Definitions>, {
34
34
  code: Key;
35
35
  }>;
@@ -38,7 +38,6 @@ type ErrorContract<Definitions extends ErrorDefinitions> = Readonly<{
38
38
  decode: (payload: unknown) => DecodedFailure<Definitions>;
39
39
  }>;
40
40
  /** Closed safe codes, allowlisted details, and a versioned checked transport union. */
41
- declare function defineErrorContract<const Definitions extends ErrorDefinitions>(definitions: Definitions): ErrorContract<Definitions>;
41
+ export declare function defineErrorContract<const Definitions extends ErrorDefinitions>(definitions: Definitions): ErrorContract<Definitions>;
42
42
  //#endregion
43
- export { DeclaredError, DeclaredFailure, DecodedFailure, ErrorContract, ErrorDefinitions, ErrorDetailParser, UnknownFailure, defineErrorContract };
44
43
  //# sourceMappingURL=errors.d.mts.map
@@ -1,2 +1,2 @@
1
- const e=Object.freeze({_tag:`UnknownFailure`,version:1});function t(t){let a=Object.fromEntries(Object.entries(t).map(([e,t])=>{if(!e||!t.message||t.message.length>200)throw Error(`Declared errors require a code and a public message of 1–200 characters`);return[e,{message:t.message,details:{...t.details}}]})),o=new WeakMap;return{create(e,t){let n;try{if(!Object.hasOwn(a,e))throw Error(`Undeclared code`);let r=a[e];n={_tag:`DeclaredFailure`,version:1,code:e,message:r.message,details:i(r,t,!1)}}catch{throw Error(`Invalid declared error details`)}let s=Object.freeze({_tag:`DeclaredError`,code:e,details:r(n.details)});return o.set(s,n),s},project(t){if(typeof t!=`object`||!t)return e;let n=o.get(t);return n?r(n):e},decode(t){try{if(!n(t)||t._tag!==`DeclaredFailure`||t.version!==1||typeof t.code!=`string`||!Object.hasOwn(a,t.code)||Object.keys(t).length!==5||![`message`,`details`,`_tag`,`version`,`code`].every(e=>Object.hasOwn(t,e)))return e;let o=a[t.code];return t.message===o.message?(r(t.details),{_tag:`DeclaredFailure`,version:1,code:t.code,message:o.message,details:i(o,t.details,!0)}):e}catch{return e}}}}function n(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function r(e,t=new Set){if(e===null||typeof e==`string`||typeof e==`boolean`||typeof e==`number`&&Number.isFinite(e))return e;if(typeof e!=`object`||!e||t.has(e))throw Error(`Invalid JSON`);t.add(e);try{if(Array.isArray(e)){let n=[];for(let i=0;i<e.length;i++)n.push(r(e[i],t));return n}if(!n(e))throw Error(`Invalid JSON`);return Object.fromEntries(Object.entries(e).map(([e,n])=>[e,r(n,t)]))}finally{t.delete(e)}}function i(e,t,i){if(!n(t))throw Error(`Invalid details`);let a=Object.keys(e.details);if(i&&Object.keys(t).some(t=>!Object.hasOwn(e.details,t)))throw Error(`Undeclared detail`);return Object.fromEntries(a.map(n=>{if(!Object.hasOwn(t,n))throw Error(`Missing detail`);return[n,r(e.details[n].parse(t[n]))]}))}export{t as defineErrorContract};
1
+ const e=Object.freeze({_tag:`UnknownFailure`,version:1});function t(t){let a=Object.fromEntries(Object.entries(t).map(([e,t])=>{if(!e||!t.message||t.message.length>200)throw Error(`Declared errors require a code and a public message of 1–200 characters`);return[e,{message:t.message,details:{...t.details}}]})),o=/* @__PURE__ */ new WeakMap;return{create(e,t){let n;try{if(!Object.hasOwn(a,e))throw Error(`Undeclared code`);let r=a[e];n={_tag:`DeclaredFailure`,version:1,code:e,message:r.message,details:i(r,t,!1)}}catch{throw Error(`Invalid declared error details`)}let s=Object.freeze({_tag:`DeclaredError`,code:e,details:r(n.details)});return o.set(s,n),s},project(t){if(typeof t!=`object`||!t)return e;let n=o.get(t);return n?r(n):e},decode(t){try{if(!n(t)||t._tag!==`DeclaredFailure`||t.version!==1||typeof t.code!=`string`||!Object.hasOwn(a,t.code)||Object.keys(t).length!==5||![`message`,`details`,`_tag`,`version`,`code`].every(e=>Object.hasOwn(t,e)))return e;let o=a[t.code];return t.message===o.message?(r(t.details),{_tag:`DeclaredFailure`,version:1,code:t.code,message:o.message,details:i(o,t.details,!0)}):e}catch{return e}}}}function n(e){if(typeof e!=`object`||!e||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function r(e,t=/* @__PURE__ */ new Set){if(e===null||typeof e==`string`||typeof e==`boolean`||typeof e==`number`&&Number.isFinite(e))return e;if(typeof e!=`object`||!e||t.has(e))throw Error(`Invalid JSON`);t.add(e);try{if(Array.isArray(e)){let n=[];for(let i=0;i<e.length;i++)n.push(r(e[i],t));return n}if(!n(e))throw Error(`Invalid JSON`);return Object.fromEntries(Object.entries(e).map(([e,n])=>[e,r(n,t)]))}finally{t.delete(e)}}function i(e,t,i){if(!n(t))throw Error(`Invalid details`);let a=Object.keys(e.details);if(i&&Object.keys(t).some(t=>!Object.hasOwn(e.details,t)))throw Error(`Undeclared detail`);return Object.fromEntries(a.map(n=>{if(!Object.hasOwn(t,n))throw Error(`Missing detail`);return[n,r(e.details[n].parse(t[n]))]}))}export{t as defineErrorContract};
2
2
  //# sourceMappingURL=errors.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.mjs","names":[],"sources":["../../../src/modules/contracts/errors.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns, anti-slop/no-unknown-type-aliases, anti-slop/no-runtime-typeof, anti-slop/no-unsafe-dictionary-type -- This neutral contract validates unknown transport data and an explicitly keyed code/detail declaration. */\n\n/** Explicit synchronous validators for the final public detail representation. */\nexport type ErrorDetailParser<Output = unknown> = Readonly<{\n\tparse: (value: unknown) => Output\n}>\n\nexport type ErrorDefinitions = Readonly<\n\tRecord<\n\t\tstring,\n\t\tReadonly<{\n\t\t\tmessage: string\n\t\t\tdetails: Readonly<Record<string, ErrorDetailParser>>\n\t\t}>\n\t>\n>\n\ntype Code<Definitions extends ErrorDefinitions> = Extract<keyof Definitions, string>\ntype Details<Definition extends ErrorDefinitions[string]> =\n\tDefinition extends ErrorDefinitions[string]\n\t\t? { [Field in keyof Definition['details']]: ReturnType<Definition['details'][Field]['parse']> }\n\t\t: never\n\ndeclare const declaredErrorBrand: unique symbol\n\n/** Server failures are trusted only by the contract that created them. */\nexport type DeclaredError<Definitions extends ErrorDefinitions> = {\n\t[Key in Code<Definitions>]: Readonly<{\n\t\t_tag: 'DeclaredError'\n\t\tcode: Key\n\t\tdetails: Details<Definitions[Key]>\n\t\t[declaredErrorBrand]: true\n\t}>\n}[Code<Definitions>]\n\nexport type DeclaredFailure<Definitions extends ErrorDefinitions> = {\n\t[Key in Code<Definitions>]: Readonly<{\n\t\t_tag: 'DeclaredFailure'\n\t\tversion: 1\n\t\tcode: Key\n\t\tmessage: string\n\t\tdetails: Details<Definitions[Key]>\n\t}>\n}[Code<Definitions>]\n\nexport type UnknownFailure = Readonly<{ _tag: 'UnknownFailure'; version: 1 }>\nexport type DecodedFailure<Definitions extends ErrorDefinitions> =\n\t| DeclaredFailure<Definitions>\n\t| UnknownFailure\n\nexport type ErrorContract<Definitions extends ErrorDefinitions> = Readonly<{\n\tcreate: <Key extends Code<Definitions>>(\n\t\tcode: Key,\n\t\tdetails: Details<Definitions[NoInfer<Key>]>,\n\t) => Extract<DeclaredError<Definitions>, { code: Key }>\n\tproject: (error: unknown) => DecodedFailure<Definitions>\n\t/** Receives envelope data, e.g. ConvexError.data; never parses error messages. */\n\tdecode: (payload: unknown) => DecodedFailure<Definitions>\n}>\n\nconst unknownFailure: UnknownFailure = Object.freeze({ _tag: 'UnknownFailure', version: 1 })\ntype Json = null | boolean | number | string | Json[] | { [key: string]: Json }\n\n/** Closed safe codes, allowlisted details, and a versioned checked transport union. */\nexport function defineErrorContract<const Definitions extends ErrorDefinitions>(\n\tdefinitions: Definitions,\n): ErrorContract<Definitions> {\n\t// SAFETY: the snapshot copies every declaration without changing its code, message or paired parsers.\n\tconst declarations = Object.fromEntries(\n\t\tObject.entries(definitions).map(([code, definition]) => {\n\t\t\tif (!code || !definition.message || definition.message.length > 200) {\n\t\t\t\tthrow Error('Declared errors require a code and a public message of 1–200 characters')\n\t\t\t}\n\t\t\treturn [code, { message: definition.message, details: { ...definition.details } }]\n\t\t}),\n\t) as Definitions\n\tconst trusted = new WeakMap<object, DeclaredFailure<Definitions>>()\n\treturn {\n\t\tcreate(code, details) {\n\t\t\tlet envelope: DeclaredFailure<Definitions>\n\t\t\ttry {\n\t\t\t\tif (!Object.hasOwn(declarations, code)) throw Error('Undeclared code')\n\t\t\t\tconst definition = declarations[code]\n\t\t\t\t// SAFETY: the selected closed declaration validates every field before construction.\n\t\t\t\tenvelope = {\n\t\t\t\t\t_tag: 'DeclaredFailure',\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcode,\n\t\t\t\t\tmessage: definition.message,\n\t\t\t\t\tdetails: parseDetails(definition, details, false),\n\t\t\t\t} as DeclaredFailure<Definitions>\n\t\t\t} catch {\n\t\t\t\t// Validator messages, issue paths and provider causes remain private.\n\t\t\t\tthrow Error('Invalid declared error details')\n\t\t\t}\n\t\t\t// SAFETY: identity is registered below; the inaccessible brand cannot confer trust by itself.\n\t\t\tconst error = Object.freeze({\n\t\t\t\t_tag: 'DeclaredError',\n\t\t\t\tcode,\n\t\t\t\tdetails: copyJson(envelope.details),\n\t\t\t}) as Extract<DeclaredError<Definitions>, { code: typeof code }>\n\t\t\ttrusted.set(error, envelope)\n\t\t\treturn error\n\t\t},\n\t\tproject(error) {\n\t\t\tif (error === null || typeof error !== 'object') return unknownFailure\n\t\t\tconst envelope = trusted.get(error)\n\t\t\t// SAFETY: only validated contract-owned envelopes enter the private map.\n\t\t\treturn envelope ? (copyJson(envelope) as DeclaredFailure<Definitions>) : unknownFailure\n\t\t},\n\t\tdecode(payload) {\n\t\t\ttry {\n\t\t\t\tif (\n\t\t\t\t\t!isRecord(payload) ||\n\t\t\t\t\tpayload._tag !== 'DeclaredFailure' ||\n\t\t\t\t\tpayload.version !== 1 ||\n\t\t\t\t\ttypeof payload.code !== 'string' ||\n\t\t\t\t\t!Object.hasOwn(declarations, payload.code) ||\n\t\t\t\t\tObject.keys(payload).length !== 5 ||\n\t\t\t\t\t!['message', 'details', '_tag', 'version', 'code'].every((key) =>\n\t\t\t\t\t\tObject.hasOwn(payload, key),\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn unknownFailure\n\t\t\t\t}\n\t\t\t\tconst definition = declarations[payload.code]\n\t\t\t\tif (payload.message !== definition.message) return unknownFailure\n\t\t\t\t// Validate raw transport JSON too: parsers must not hide non-JSON payloads.\n\t\t\t\tcopyJson(payload.details)\n\t\t\t\t// SAFETY: code membership and every allowlisted field have been checked independently.\n\t\t\t\treturn {\n\t\t\t\t\t_tag: 'DeclaredFailure',\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcode: payload.code,\n\t\t\t\t\tmessage: definition.message,\n\t\t\t\t\tdetails: parseDetails(definition, payload.details, true),\n\t\t\t\t} as DeclaredFailure<Definitions>\n\t\t\t} catch {\n\t\t\t\treturn unknownFailure\n\t\t\t}\n\t\t},\n\t}\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\tif (value === null || typeof value !== 'object' || Array.isArray(value)) return false\n\tconst prototype = Object.getPrototypeOf(value)\n\treturn prototype === Object.prototype || prototype === null\n}\n\n/** Copy data without invoking toJSON or retaining mutable provider objects. */\nfunction copyJson(value: unknown, ancestors = new Set<object>()): Json {\n\tif (value === null || typeof value === 'string' || typeof value === 'boolean') return value\n\tif (typeof value === 'number' && Number.isFinite(value)) return value\n\tif (typeof value !== 'object' || value === null || ancestors.has(value))\n\t\tthrow Error('Invalid JSON')\n\tancestors.add(value)\n\ttry {\n\t\tif (Array.isArray(value)) {\n\t\t\tconst result: Json[] = []\n\t\t\tfor (let index = 0; index < value.length; index++)\n\t\t\t\tresult.push(copyJson(value[index], ancestors))\n\t\t\treturn result\n\t\t}\n\t\tif (!isRecord(value)) throw Error('Invalid JSON')\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(value).map(([key, child]) => [key, copyJson(child, ancestors)]),\n\t\t)\n\t} finally {\n\t\tancestors.delete(value)\n\t}\n}\n\nfunction parseDetails<const Definition extends ErrorDefinitions[string]>(\n\tdefinition: Definition,\n\tvalue: unknown,\n\tstrict: boolean,\n): Details<Definition> {\n\tif (!isRecord(value)) throw Error('Invalid details')\n\tconst fields = Object.keys(definition.details)\n\tif (strict && Object.keys(value).some((key) => !Object.hasOwn(definition.details, key))) {\n\t\tthrow Error('Undeclared detail')\n\t}\n\t// SAFETY: each declared field is validated by its paired parser before its JSON-safe copy is returned.\n\treturn Object.fromEntries(\n\t\tfields.map((field) => {\n\t\t\tif (!Object.hasOwn(value, field)) throw Error('Missing detail')\n\t\t\treturn [field, copyJson(definition.details[field].parse(value[field]))]\n\t\t}),\n\t) as Details<Definition>\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"errors.mjs","names":["unknownFailure","defineErrorContract","declarations","definitions","code","definition","trusted","envelope","parseDetails","details","error","copyJson","isRecord","payload","key","value","prototype","ancestors","result","index","child","fields","strict","field"],"sources":["../../../src/modules/contracts/errors.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns, anti-slop/no-unknown-type-aliases, anti-slop/no-runtime-typeof, anti-slop/no-unsafe-dictionary-type -- This neutral contract validates unknown transport data and an explicitly keyed code/detail declaration. */\n\n/** Explicit synchronous validators for the final public detail representation. */\nexport type ErrorDetailParser<Output = unknown> = Readonly<{\n\tparse: (value: unknown) => Output\n}>\n\nexport type ErrorDefinitions = Readonly<\n\tRecord<\n\t\tstring,\n\t\tReadonly<{\n\t\t\tmessage: string\n\t\t\tdetails: Readonly<Record<string, ErrorDetailParser>>\n\t\t}>\n\t>\n>\n\ntype Code<Definitions extends ErrorDefinitions> = Extract<keyof Definitions, string>\ntype Details<Definition extends ErrorDefinitions[string]> =\n\tDefinition extends ErrorDefinitions[string]\n\t\t? { [Field in keyof Definition['details']]: ReturnType<Definition['details'][Field]['parse']> }\n\t\t: never\n\ndeclare const declaredErrorBrand: unique symbol\n\n/** Server failures are trusted only by the contract that created them. */\nexport type DeclaredError<Definitions extends ErrorDefinitions> = {\n\t[Key in Code<Definitions>]: Readonly<{\n\t\t_tag: 'DeclaredError'\n\t\tcode: Key\n\t\tdetails: Details<Definitions[Key]>\n\t\t[declaredErrorBrand]: true\n\t}>\n}[Code<Definitions>]\n\nexport type DeclaredFailure<Definitions extends ErrorDefinitions> = {\n\t[Key in Code<Definitions>]: Readonly<{\n\t\t_tag: 'DeclaredFailure'\n\t\tversion: 1\n\t\tcode: Key\n\t\tmessage: string\n\t\tdetails: Details<Definitions[Key]>\n\t}>\n}[Code<Definitions>]\n\nexport type UnknownFailure = Readonly<{ _tag: 'UnknownFailure'; version: 1 }>\nexport type DecodedFailure<Definitions extends ErrorDefinitions> =\n\t| DeclaredFailure<Definitions>\n\t| UnknownFailure\n\nexport type ErrorContract<Definitions extends ErrorDefinitions> = Readonly<{\n\tcreate: <Key extends Code<Definitions>>(\n\t\tcode: Key,\n\t\tdetails: Details<Definitions[NoInfer<Key>]>,\n\t) => Extract<DeclaredError<Definitions>, { code: Key }>\n\tproject: (error: unknown) => DecodedFailure<Definitions>\n\t/** Receives envelope data, e.g. ConvexError.data; never parses error messages. */\n\tdecode: (payload: unknown) => DecodedFailure<Definitions>\n}>\n\nconst unknownFailure: UnknownFailure = Object.freeze({ _tag: 'UnknownFailure', version: 1 })\ntype Json = null | boolean | number | string | Json[] | { [key: string]: Json }\n\n/** Closed safe codes, allowlisted details, and a versioned checked transport union. */\nexport function defineErrorContract<const Definitions extends ErrorDefinitions>(\n\tdefinitions: Definitions,\n): ErrorContract<Definitions> {\n\t// SAFETY: the snapshot copies every declaration without changing its code, message or paired parsers.\n\tconst declarations = Object.fromEntries(\n\t\tObject.entries(definitions).map(([code, definition]) => {\n\t\t\tif (!code || !definition.message || definition.message.length > 200) {\n\t\t\t\tthrow Error('Declared errors require a code and a public message of 1–200 characters')\n\t\t\t}\n\t\t\treturn [code, { message: definition.message, details: { ...definition.details } }]\n\t\t}),\n\t) as Definitions\n\tconst trusted = new WeakMap<object, DeclaredFailure<Definitions>>()\n\treturn {\n\t\tcreate(code, details) {\n\t\t\tlet envelope: DeclaredFailure<Definitions>\n\t\t\ttry {\n\t\t\t\tif (!Object.hasOwn(declarations, code)) throw Error('Undeclared code')\n\t\t\t\tconst definition = declarations[code]\n\t\t\t\t// SAFETY: the selected closed declaration validates every field before construction.\n\t\t\t\tenvelope = {\n\t\t\t\t\t_tag: 'DeclaredFailure',\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcode,\n\t\t\t\t\tmessage: definition.message,\n\t\t\t\t\tdetails: parseDetails(definition, details, false),\n\t\t\t\t} as DeclaredFailure<Definitions>\n\t\t\t} catch {\n\t\t\t\t// Validator messages, issue paths and provider causes remain private.\n\t\t\t\tthrow Error('Invalid declared error details')\n\t\t\t}\n\t\t\t// SAFETY: identity is registered below; the inaccessible brand cannot confer trust by itself.\n\t\t\tconst error = Object.freeze({\n\t\t\t\t_tag: 'DeclaredError',\n\t\t\t\tcode,\n\t\t\t\tdetails: copyJson(envelope.details),\n\t\t\t}) as Extract<DeclaredError<Definitions>, { code: typeof code }>\n\t\t\ttrusted.set(error, envelope)\n\t\t\treturn error\n\t\t},\n\t\tproject(error) {\n\t\t\tif (error === null || typeof error !== 'object') return unknownFailure\n\t\t\tconst envelope = trusted.get(error)\n\t\t\t// SAFETY: only validated contract-owned envelopes enter the private map.\n\t\t\treturn envelope ? (copyJson(envelope) as DeclaredFailure<Definitions>) : unknownFailure\n\t\t},\n\t\tdecode(payload) {\n\t\t\ttry {\n\t\t\t\tif (\n\t\t\t\t\t!isRecord(payload) ||\n\t\t\t\t\tpayload._tag !== 'DeclaredFailure' ||\n\t\t\t\t\tpayload.version !== 1 ||\n\t\t\t\t\ttypeof payload.code !== 'string' ||\n\t\t\t\t\t!Object.hasOwn(declarations, payload.code) ||\n\t\t\t\t\tObject.keys(payload).length !== 5 ||\n\t\t\t\t\t!['message', 'details', '_tag', 'version', 'code'].every((key) =>\n\t\t\t\t\t\tObject.hasOwn(payload, key),\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\treturn unknownFailure\n\t\t\t\t}\n\t\t\t\tconst definition = declarations[payload.code]\n\t\t\t\tif (payload.message !== definition.message) return unknownFailure\n\t\t\t\t// Validate raw transport JSON too: parsers must not hide non-JSON payloads.\n\t\t\t\tcopyJson(payload.details)\n\t\t\t\t// SAFETY: code membership and every allowlisted field have been checked independently.\n\t\t\t\treturn {\n\t\t\t\t\t_tag: 'DeclaredFailure',\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcode: payload.code,\n\t\t\t\t\tmessage: definition.message,\n\t\t\t\t\tdetails: parseDetails(definition, payload.details, true),\n\t\t\t\t} as DeclaredFailure<Definitions>\n\t\t\t} catch {\n\t\t\t\treturn unknownFailure\n\t\t\t}\n\t\t},\n\t}\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\tif (value === null || typeof value !== 'object' || Array.isArray(value)) return false\n\tconst prototype = Object.getPrototypeOf(value)\n\treturn prototype === Object.prototype || prototype === null\n}\n\n/** Copy data without invoking toJSON or retaining mutable provider objects. */\nfunction copyJson(value: unknown, ancestors = new Set<object>()): Json {\n\tif (value === null || typeof value === 'string' || typeof value === 'boolean') return value\n\tif (typeof value === 'number' && Number.isFinite(value)) return value\n\tif (typeof value !== 'object' || value === null || ancestors.has(value))\n\t\tthrow Error('Invalid JSON')\n\tancestors.add(value)\n\ttry {\n\t\tif (Array.isArray(value)) {\n\t\t\tconst result: Json[] = []\n\t\t\tfor (let index = 0; index < value.length; index++)\n\t\t\t\tresult.push(copyJson(value[index], ancestors))\n\t\t\treturn result\n\t\t}\n\t\tif (!isRecord(value)) throw Error('Invalid JSON')\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(value).map(([key, child]) => [key, copyJson(child, ancestors)]),\n\t\t)\n\t} finally {\n\t\tancestors.delete(value)\n\t}\n}\n\nfunction parseDetails<const Definition extends ErrorDefinitions[string]>(\n\tdefinition: Definition,\n\tvalue: unknown,\n\tstrict: boolean,\n): Details<Definition> {\n\tif (!isRecord(value)) throw Error('Invalid details')\n\tconst fields = Object.keys(definition.details)\n\tif (strict && Object.keys(value).some((key) => !Object.hasOwn(definition.details, key))) {\n\t\tthrow Error('Undeclared detail')\n\t}\n\t// SAFETY: each declared field is validated by its paired parser before its JSON-safe copy is returned.\n\treturn Object.fromEntries(\n\t\tfields.map((field) => {\n\t\t\tif (!Object.hasOwn(value, field)) throw Error('Missing detail')\n\t\t\treturn [field, copyJson(definition.details[field].parse(value[field]))]\n\t\t}),\n\t) as Details<Definition>\n}\n"],"mappings":"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"}