@supalive/core 1.8.1 → 1.10.0

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 (106) hide show
  1. package/README.md +1 -2
  2. package/dist/index-BQRlJY_1.d.ts +2192 -0
  3. package/dist/index-BQRlJY_1.d.ts.map +1 -0
  4. package/dist/index-CDG1kbFO.d.ts +2211 -0
  5. package/dist/index-CDG1kbFO.d.ts.map +1 -0
  6. package/dist/index-CkYZi3ai.d.ts +2186 -0
  7. package/dist/index-CkYZi3ai.d.ts.map +1 -0
  8. package/dist/index-D8O39FoZ.d.ts +2192 -0
  9. package/dist/index-D8O39FoZ.d.ts.map +1 -0
  10. package/dist/index-DKlWIC3k.d.ts +2200 -0
  11. package/dist/index-DKlWIC3k.d.ts.map +1 -0
  12. package/dist/index-Dy9UlONo.d.ts +2192 -0
  13. package/dist/index-Dy9UlONo.d.ts.map +1 -0
  14. package/dist/index-WMhtVzJA.d.ts +2192 -0
  15. package/dist/index-WMhtVzJA.d.ts.map +1 -0
  16. package/dist/index-tDcHLwJu.d.ts +2186 -0
  17. package/dist/index-tDcHLwJu.d.ts.map +1 -0
  18. package/dist/mysql-BBNCFz8q.d.ts +109 -0
  19. package/dist/mysql-BBNCFz8q.d.ts.map +1 -0
  20. package/dist/mysql-BVz7201u.d.ts +109 -0
  21. package/dist/mysql-BVz7201u.d.ts.map +1 -0
  22. package/dist/mysql-CBSuONm5.d.ts +109 -0
  23. package/dist/mysql-CBSuONm5.d.ts.map +1 -0
  24. package/dist/mysql-CBlZ6FVc.d.ts +109 -0
  25. package/dist/mysql-CBlZ6FVc.d.ts.map +1 -0
  26. package/dist/mysql-CDenA4XE.d.ts +109 -0
  27. package/dist/mysql-CDenA4XE.d.ts.map +1 -0
  28. package/dist/mysql-CfYZLs5V.d.ts +109 -0
  29. package/dist/mysql-CfYZLs5V.d.ts.map +1 -0
  30. package/dist/mysql-DAfFK5v1.d.ts +109 -0
  31. package/dist/mysql-DAfFK5v1.d.ts.map +1 -0
  32. package/dist/mysql-DjjyCiO4.d.ts +109 -0
  33. package/dist/mysql-DjjyCiO4.d.ts.map +1 -0
  34. package/dist/postgres-BKGLPrKt.d.ts +113 -0
  35. package/dist/postgres-BKGLPrKt.d.ts.map +1 -0
  36. package/dist/postgres-CKBWXyY8.d.ts +113 -0
  37. package/dist/postgres-CKBWXyY8.d.ts.map +1 -0
  38. package/dist/postgres-CUHirAJN.d.ts +113 -0
  39. package/dist/postgres-CUHirAJN.d.ts.map +1 -0
  40. package/dist/postgres-Cj9zuZ8p.d.ts +113 -0
  41. package/dist/postgres-Cj9zuZ8p.d.ts.map +1 -0
  42. package/dist/postgres-DGK6Y1aL.d.ts +113 -0
  43. package/dist/postgres-DGK6Y1aL.d.ts.map +1 -0
  44. package/dist/postgres-DQxKs5Nu.d.ts +113 -0
  45. package/dist/postgres-DQxKs5Nu.d.ts.map +1 -0
  46. package/dist/postgres-hlrVkOXa.d.ts +113 -0
  47. package/dist/postgres-hlrVkOXa.d.ts.map +1 -0
  48. package/dist/postgres-ziXP2hco.d.ts +113 -0
  49. package/dist/postgres-ziXP2hco.d.ts.map +1 -0
  50. package/dist/procedure-B4qKrlBL.js +158 -0
  51. package/dist/procedure-B4qKrlBL.js.map +1 -0
  52. package/dist/procedure-BDcrK98I.js +173 -0
  53. package/dist/procedure-BDcrK98I.js.map +1 -0
  54. package/dist/procedure-BxGOWNWg.js.map +1 -0
  55. package/dist/procedure-CRkrxHvn.js +187 -0
  56. package/dist/procedure-CRkrxHvn.js.map +1 -0
  57. package/dist/procedure-Ck4v3__H.js +212 -0
  58. package/dist/procedure-Ck4v3__H.js.map +1 -0
  59. package/dist/procedure-DPgXC2Cm.js +221 -0
  60. package/dist/procedure-DPgXC2Cm.js.map +1 -0
  61. package/dist/procedure-xUVIUm5W.js +213 -0
  62. package/dist/procedure-xUVIUm5W.js.map +1 -0
  63. package/dist/src/client/index.d.ts +1 -1
  64. package/dist/src/client/index.js +1 -1
  65. package/dist/src/exports/mysql.d.ts +1 -1
  66. package/dist/src/exports/postgres.d.ts +1 -1
  67. package/dist/src/exports/procedure.d.ts +17 -2
  68. package/dist/src/exports/procedure.d.ts.map +1 -0
  69. package/dist/src/exports/procedure.js +8 -2
  70. package/dist/src/exports/procedure.js.map +1 -0
  71. package/dist/src/exports/schema-sql.d.ts +1 -1
  72. package/dist/src/exports/server.d.ts +24 -124
  73. package/dist/src/exports/server.d.ts.map +1 -1
  74. package/dist/src/exports/server.js +128 -30
  75. package/dist/src/exports/server.js.map +1 -1
  76. package/dist/src/exports/sub-manager-worker-entry.d.ts +1 -0
  77. package/dist/src/exports/sub-manager-worker-entry.js +71 -0
  78. package/dist/src/exports/sub-manager-worker-entry.js.map +1 -0
  79. package/dist/src/exports/subscription-manager-worker-entry.js +3 -49
  80. package/dist/src/exports/subscription-manager-worker-entry.js.map +1 -1
  81. package/dist/src/exports/types.d.ts +2 -2
  82. package/dist/sub-worker-dispatch-G8V8asfR.js +810 -0
  83. package/dist/sub-worker-dispatch-G8V8asfR.js.map +1 -0
  84. package/dist/subscription-worker-dispatch-CSQV-PO3.js +810 -0
  85. package/dist/subscription-worker-dispatch-CSQV-PO3.js.map +1 -0
  86. package/dist/types_server-AQ8Jl2_R.d.ts +521 -0
  87. package/dist/types_server-AQ8Jl2_R.d.ts.map +1 -0
  88. package/dist/types_server-BB2WvXEA.d.ts +521 -0
  89. package/dist/types_server-BB2WvXEA.d.ts.map +1 -0
  90. package/dist/types_server-BI7uQd6x.d.ts +328 -0
  91. package/dist/types_server-BI7uQd6x.d.ts.map +1 -0
  92. package/dist/types_server-BcT4A8OM.d.ts +328 -0
  93. package/dist/types_server-BcT4A8OM.d.ts.map +1 -0
  94. package/dist/types_server-CO3IYNS9.d.ts +328 -0
  95. package/dist/types_server-CO3IYNS9.d.ts.map +1 -0
  96. package/dist/types_server-Clf74qZP.d.ts +328 -0
  97. package/dist/types_server-Clf74qZP.d.ts.map +1 -0
  98. package/dist/types_server-DEAwXI4p.d.ts +328 -0
  99. package/dist/types_server-DEAwXI4p.d.ts.map +1 -0
  100. package/dist/types_server-DU9JMSXd.d.ts +521 -0
  101. package/dist/types_server-DU9JMSXd.d.ts.map +1 -0
  102. package/dist/zod_ext-B5cyjWqZ.d.ts +11 -0
  103. package/dist/zod_ext-B5cyjWqZ.d.ts.map +1 -0
  104. package/dist/zod_ext-CZlJ4wtJ.d.ts +11 -0
  105. package/dist/zod_ext-CZlJ4wtJ.d.ts.map +1 -0
  106. package/package.json +6 -5
@@ -0,0 +1,187 @@
1
+ //#region src/router/procedure.ts
2
+ /**
3
+ * Mark a Zod schema as a **partial codegen hint** for the procedure's return
4
+ * type. Only the fields you specify are used; everything else is inferred from
5
+ * the handler's TypeScript return type.
6
+ *
7
+ * Purely for codegen — the returned schema is the same Zod type you passed in.
8
+ *
9
+ * @example
10
+ * returns: partial(z.object({
11
+ * value: z.array(genModelName("StoreCardItem")(z.object({
12
+ * balanceCents: z.number().int(),
13
+ * }))),
14
+ * })),
15
+ */
16
+ function partial(schema) {
17
+ return schema.meta({ __partial: true });
18
+ }
19
+ /**
20
+ * Attach a custom model name to a Zod schema via `.meta({ __genType: name })`.
21
+ * The codegen uses this name instead of auto-generating one from the TS type.
22
+ *
23
+ * Purely for codegen — the returned schema is the same Zod type you passed in.
24
+ *
25
+ * @example
26
+ * z.array(genModelName("StoreCardItem")(z.object({ ... })))
27
+ */
28
+ function genModelName(name) {
29
+ return (schema) => schema.meta({ __genType: name });
30
+ }
31
+ /**
32
+ * Create a query builder with a pre-defined context type.
33
+ * This allows you to define the context type once and have it inferred
34
+ * automatically in all your query handlers.
35
+ *
36
+ * @example
37
+ * // Define your server context
38
+ * interface ServerContext {
39
+ * auth: { userId: string };
40
+ * requestId: string;
41
+ * }
42
+ *
43
+ * // Create a typed query builder
44
+ * const query = createQueryBuilder<ServerContext>();
45
+ *
46
+ * // Use it - context type is automatically inferred!
47
+ * const getUser = query({
48
+ * args: z.object({ id: z.string() }),
49
+ * handler: async (ctx, { id }) => {
50
+ * // ctx.db for database queries
51
+ * const user = await ctx.db.query(UsersSchema).find(id);
52
+ * // ctx.context for server context
53
+ * console.log(ctx.context.requestId);
54
+ * return user;
55
+ * }
56
+ * });
57
+ */
58
+ function createQueryBuilder() {
59
+ return function query(config) {
60
+ return {
61
+ _type: "procedure",
62
+ procedureType: "query",
63
+ inputSchema: config.args,
64
+ outputSchema: config.returns,
65
+ fn: config.handler,
66
+ internal: config.internal ?? false,
67
+ queryIdentity: config.queryIdentity
68
+ };
69
+ };
70
+ }
71
+ /**
72
+ * Create a mutation builder with a pre-defined context type.
73
+ * This allows you to define the context type once and have it inferred
74
+ * automatically in all your mutation handlers.
75
+ *
76
+ * @example
77
+ * // Define your server context
78
+ * interface ServerContext {
79
+ * auth: { userId: string };
80
+ * requestId: string;
81
+ * }
82
+ *
83
+ * // Create a typed mutation builder
84
+ * const mutation = createMutationBuilder<ServerContext>();
85
+ *
86
+ * // Use it - context type is automatically inferred!
87
+ * const createUser = mutation({
88
+ * args: z.object({ name: z.string() }),
89
+ * handler: async (ctx, { name }) => {
90
+ * // ctx.db for mutations
91
+ * await ctx.db.insert(UsersSchema, id, { name });
92
+ * // ctx.context for server context
93
+ * console.log(ctx.context.requestId);
94
+ * return { success: true };
95
+ * }
96
+ * });
97
+ */
98
+ function createMutationBuilder() {
99
+ return function mutation(config) {
100
+ return {
101
+ _type: "procedure",
102
+ procedureType: "mutation",
103
+ inputSchema: config.args,
104
+ outputSchema: config.returns,
105
+ fn: config.handler,
106
+ internal: config.internal ?? false
107
+ };
108
+ };
109
+ }
110
+ /**
111
+ * Create an action builder with a pre-defined context type.
112
+ * Actions have access to the full SupaliveDb for both queries and mutations.
113
+ *
114
+ * @example
115
+ * // Define your server context
116
+ * interface ServerContext {
117
+ * auth: { userId: string };
118
+ * requestId: string;
119
+ * }
120
+ *
121
+ * // Create a typed action builder
122
+ * const action = createActionBuilder<ServerContext>();
123
+ *
124
+ * // Use it - context type is automatically inferred!
125
+ * const processOrder = action({
126
+ * args: z.object({ orderId: z.string() }),
127
+ * handler: async (ctx, { orderId }) => {
128
+ * // ctx.db for full database access
129
+ * const order = await ctx.db.query(async (db) => {
130
+ * return db.query(OrdersSchema).find(orderId);
131
+ * });
132
+ * await ctx.db.mutation(async (db) => {
133
+ * await db.update(OrdersSchema, orderId, { status: "processed" });
134
+ * });
135
+ * // ctx.context for server context
136
+ * console.log(ctx.context.requestId);
137
+ * return { success: true };
138
+ * }
139
+ * });
140
+ */
141
+ function createActionBuilder() {
142
+ return function action(config) {
143
+ return {
144
+ _type: "procedure",
145
+ procedureType: "action",
146
+ inputSchema: config.args,
147
+ outputSchema: config.returns,
148
+ fn: config.handler,
149
+ internal: config.internal ?? false
150
+ };
151
+ };
152
+ }
153
+ /**
154
+ * Create a job builder with a pre-defined context type. A job is a
155
+ * server-only procedure invoked by the scheduler over HTTP — either on its
156
+ * declared `cron` schedule or as a precise one-shot enqueued via the
157
+ * server's job API. Jobs run like actions (full db, non-transactional) and
158
+ * are always internal, so they are never reachable from a client.
159
+ *
160
+ * @example
161
+ * const job = createJobBuilder<ServerContext>();
162
+ *
163
+ * export const cleanupOtps = job({
164
+ * cron: "0 * * * *", // hourly
165
+ * args: z.object({}),
166
+ * handler: async (ctx) => {
167
+ * await ctx.db.mutation(async (db) => { ... });
168
+ * return { ok: true };
169
+ * },
170
+ * });
171
+ */
172
+ function createJobBuilder() {
173
+ return function job(config) {
174
+ return {
175
+ _type: "procedure",
176
+ procedureType: "job",
177
+ inputSchema: config.args,
178
+ fn: config.handler,
179
+ internal: true,
180
+ cron: config.cron
181
+ };
182
+ };
183
+ }
184
+ //#endregion
185
+ export { genModelName as a, createQueryBuilder as i, createJobBuilder as n, partial as o, createMutationBuilder as r, createActionBuilder as t };
186
+
187
+ //# sourceMappingURL=procedure-CRkrxHvn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"procedure-CRkrxHvn.js","names":[],"sources":["../src/router/procedure.ts"],"sourcesContent":["import type { ZodType } from \"zod\";\nimport type { DbReader, DbWriter } from \"../db/context\";\nimport type { SupaliveDb } from \"../db/realtime_db\";\nimport type { ObjectStorage } from \"../storage\";\nimport type { JobClient } from \"../jobs/scheduler\";\n\n// ─── Context Types ───────────────────────────────────────────────────────────\n\n/**\n * Query context passed to query handlers.\n * Contains database reader and user-defined server context.\n */\nexport interface QueryCtx<TContext = unknown> {\n /** Database reader for queries */\n db: DbReader;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n/**\n * Mutation context passed to mutation handlers.\n * Contains database writer and user-defined server context.\n */\nexport interface MutationCtx<TContext = unknown> {\n /** Database writer for mutations (includes insert/update/delete) */\n db: DbWriter;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n/**\n * Action context passed to action handlers.\n *\n * Actions are the \"external I/O\" tier: they hold the full {@link SupaliveDb}\n * (queries + mutations) and are the ONLY context that also carries side-effect\n * services — {@link ObjectStorage} for uploads/downloads and a {@link JobClient}\n * for scheduling precise one-shots. Queries/mutations stay pure (db only) so\n * they remain cacheable and transaction-scoped.\n */\nexport interface ActionCtx<TContext = unknown> {\n /** Full database interface for queries and mutations */\n db: SupaliveDb;\n /** Object storage, when the server was configured with one (see\n * `SupaliveServerConfig.storage`); `undefined` otherwise. The usual home\n * for upload/download presigning. */\n storage: ObjectStorage;\n /** Job scheduler client for enqueueing precise one-shots, when the server\n * was configured with a `scheduler`; `undefined` otherwise. Scheduling is\n * network I/O, so it belongs in actions, never inside a DB transaction. */\n scheduler: JobClient;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n/**\n * Job context passed to job handlers. Structurally identical to\n * {@link ActionCtx}: a job is a server-only procedure that runs\n * non-transactionally against the full {@link SupaliveDb} and may perform\n * external work, but it is triggered by the scheduler over HTTP (a cron tick\n * or a precise one-shot) rather than by a connected client. `serverCtx` is\n * the system context built by the server's `jobContext` factory.\n */\nexport interface JobCtx<TContext = unknown> {\n /** Full database interface for queries and mutations */\n db: SupaliveDb;\n /** System server context built by the server for scheduler-triggered runs */\n serverCtx?: TContext;\n}\n\n/**\n * Context handed to `caller.<proc>.runQuery` / `.runMutation` when invoking one\n * procedure from inside another. Pass the caller handler's own `ctx` — its `db`\n * carries the parent's live transaction (a {@link DbReader}/{@link DbWriter}) or,\n * inside an action, the full {@link SupaliveDb}. The caller uses this to decide\n * whether the nested call joins the parent's snapshot (queries) or runs as an\n * independent sub-transaction (mutations).\n */\nexport interface ParentCtx<TContext = unknown> {\n db: DbReader | DbWriter | SupaliveDb;\n serverCtx?: TContext | undefined;\n}\n\n// ─── Procedure Types ─────────────────────────────────────────────────────────\n\nexport type QueryFn<TInput, TResult, TContext = unknown> = (\n ctx: QueryCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\nexport type MutationFn<TInput, TResult, TContext = unknown> = (\n ctx: MutationCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\nexport type ActionFn<TInput, TResult, TContext = unknown> = (\n ctx: ActionCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\nexport type JobFn<TInput, TResult, TContext = unknown> = (\n ctx: JobCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\n/**\n * Per-procedure override for the cache/subscription segmentation key.\n *\n * omitted | undefined → fall back to `config.getUserId(serverCtx)` (default)\n * false → no identity in hash; cache/sub shared across all users\n * string → a static identity literal (e.g. \"public\" or a tenant id)\n * function → compute from serverCtx + input (sync)\n *\n * When the result of a query is identical regardless of who calls it, set\n * this to a literal (or `false`) so a single cache entry serves everyone.\n *\n * The function form intentionally takes `serverCtx` (not the full `QueryCtx`)\n * because identity is resolved before any DB read is issued.\n */\nexport type QueryIdentitySpec<TInput, TContext> =\n | false\n | string\n | ((serverCtx: TContext, input: TInput) => string | null | undefined);\n\nexport interface BaseProcedure<\n TInput, TResult,\n TType extends \"query\" | \"mutation\" | \"action\" | \"job\",\n TContext = unknown,\n TInternal extends boolean = boolean\n> {\n readonly _type: \"procedure\";\n readonly procedureType: TType;\n readonly inputSchema: ZodType<TInput>;\n readonly outputSchema?: ZodType<any>;\n readonly fn: QueryFn<TInput, TResult, TContext> | MutationFn<TInput, TResult, TContext> | ActionFn<TInput, TResult, TContext> | JobFn<TInput, TResult, TContext>;\n readonly internal: TInternal;\n}\n\nexport interface QueryProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"query\", TContext, TInternal> {\n readonly procedureType: \"query\";\n readonly fn: QueryFn<TInput, TResult, TContext>;\n readonly queryIdentity?: QueryIdentitySpec<TInput, TContext>;\n}\n\nexport interface MutationProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"mutation\", TContext, TInternal> {\n readonly procedureType: \"mutation\";\n readonly fn: MutationFn<TInput, TResult, TContext>;\n}\n\nexport interface ActionProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"action\", TContext, TInternal> {\n readonly procedureType: \"action\";\n readonly fn: ActionFn<TInput, TResult, TContext>;\n}\n\n/**\n * A scheduler-triggered, server-only procedure. Runs like an action (full\n * db, non-transactional, may do external work) but is dispatched by the\n * server's HTTP job endpoint on a cron tick or a precise one-shot rather\n * than over the client WebSocket. Always {@link internal}: true, so it is\n * never reachable via `call`/`subscribe`.\n */\nexport interface JobProcedure<\n TInput, TResult,\n TContext = unknown,\n> extends BaseProcedure<TInput, TResult, \"job\", TContext, true> {\n readonly procedureType: \"job\";\n readonly fn: JobFn<TInput, TResult, TContext>;\n /**\n * Cron expression for a recurring job (e.g. `\"0 3 * * *\"`). Declared crons\n * are synced to the scheduler at server startup. Omit for a job that is\n * only ever invoked as a precise one-shot via the scheduler API.\n */\n readonly cron?: string;\n}\n\nexport type AnyProcedure<TContext = unknown> =\n | QueryProcedure<any, any, TContext>\n | MutationProcedure<any, any, TContext>\n | ActionProcedure<any, any, TContext>\n | JobProcedure<any, any, TContext>;\n\n// ─── Codegen Return Type Helpers ─────────────────────────────────────────────\n\n/**\n * Mark a Zod schema as a **partial codegen hint** for the procedure's return\n * type. Only the fields you specify are used; everything else is inferred from\n * the handler's TypeScript return type.\n *\n * Purely for codegen — the returned schema is the same Zod type you passed in.\n *\n * @example\n * returns: partial(z.object({\n * value: z.array(genModelName(\"StoreCardItem\")(z.object({\n * balanceCents: z.number().int(),\n * }))),\n * })),\n */\nexport function partial<T extends ZodType<any>>(schema: T): T {\n return schema.meta({ __partial: true }) as T;\n}\n\n/**\n * Attach a custom model name to a Zod schema via `.meta({ __genType: name })`.\n * The codegen uses this name instead of auto-generating one from the TS type.\n *\n * Purely for codegen — the returned schema is the same Zod type you passed in.\n *\n * @example\n * z.array(genModelName(\"StoreCardItem\")(z.object({ ... })))\n */\nexport function genModelName<T extends ZodType<any>>(name: string) {\n return (schema: T): T => schema.meta({ __genType: name }) as T;\n}\n\n// ─── Procedure Configuration Types ───────────────────────────────────────────\n\nexport interface QueryConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The query handler function */\n handler: QueryFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n /**\n * Partial Zod schema describing return-type overrides for codegen.\n * Only the fields you specify are used; everything else is inferred\n * from the handler's TypeScript return type. Wrap with `partial()`\n * for explicit partial semantics and `genModelName()` for model naming.\n */\n returns?: ZodType<any>;\n /**\n * Override the cache/subscription segmentation key for this procedure.\n * See {@link QueryIdentitySpec}. Omit to keep the default (per-user) behavior.\n */\n queryIdentity?: QueryIdentitySpec<TInput, TContext>;\n}\n\nexport interface MutationConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The mutation handler function */\n handler: MutationFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n /**\n * Partial Zod schema describing return-type overrides for codegen.\n * Only the fields you specify are used; everything else is inferred\n * from the handler's TypeScript return type.\n */\n returns?: ZodType<any>;\n}\n\nexport interface ActionConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The action handler function */\n handler: ActionFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n /**\n * Partial Zod schema describing return-type overrides for codegen.\n * Only the fields you specify are used; everything else is inferred\n * from the handler's TypeScript return type.\n */\n returns?: ZodType<any>;\n}\n\nexport interface JobConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for the job payload */\n args: ZodType<TInput>;\n /** The job handler function */\n handler: JobFn<TInput, TResult, TContext>;\n /**\n * Cron expression for a recurring schedule (e.g. `\"0 3 * * *\"`). Omit for a\n * job that is only invoked as a precise one-shot.\n */\n cron?: string;\n}\n\n/** Extract input type from a procedure */\nexport type InputOf<T> = T extends BaseProcedure<infer I, any, any, any> ? I : never;\n\n/** Extract output type from a procedure */\nexport type OutputOf<T> = T extends BaseProcedure<any, infer O, any, any> ? O : never;\n\n/** Extract procedure type (query/mutation) */\nexport type TypeOf<T> = T extends BaseProcedure<any, any, infer Type, any> ? Type : never;\n\n/** Extract server context type from a procedure */\nexport type ContextOf<T> = T extends BaseProcedure<any, any, any, infer C> ? C : never;\n\n/**\n * Create a query builder with a pre-defined context type.\n * This allows you to define the context type once and have it inferred\n * automatically in all your query handlers.\n * \n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n * \n * // Create a typed query builder\n * const query = createQueryBuilder<ServerContext>();\n * \n * // Use it - context type is automatically inferred!\n * const getUser = query({\n * args: z.object({ id: z.string() }),\n * handler: async (ctx, { id }) => {\n * // ctx.db for database queries\n * const user = await ctx.db.query(UsersSchema).find(id);\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return user;\n * }\n * });\n */\nexport function createQueryBuilder<TContext = unknown>() {\n return function query<TInput, TResult, const TInternal extends boolean = false>(\n config: QueryConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): QueryProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"query\",\n inputSchema: config.args,\n outputSchema: config.returns,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n queryIdentity: config.queryIdentity,\n };\n };\n}\n\n// ─── Mutation Builder Factory ────────────────────────────────────────────────\n\n/**\n * Create a mutation builder with a pre-defined context type.\n * This allows you to define the context type once and have it inferred\n * automatically in all your mutation handlers.\n * \n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n * \n * // Create a typed mutation builder\n * const mutation = createMutationBuilder<ServerContext>();\n * \n * // Use it - context type is automatically inferred!\n * const createUser = mutation({\n * args: z.object({ name: z.string() }),\n * handler: async (ctx, { name }) => {\n * // ctx.db for mutations\n * await ctx.db.insert(UsersSchema, id, { name });\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return { success: true };\n * }\n * });\n */\nexport function createMutationBuilder<TContext = unknown>() {\n return function mutation<TInput, TResult, const TInternal extends boolean = false>(\n config: MutationConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): MutationProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"mutation\",\n inputSchema: config.args,\n outputSchema: config.returns,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n };\n };\n}\n\n// ─── Action Builder Factory ──────────────────────────────────────────────────\n\n/**\n * Create an action builder with a pre-defined context type.\n * Actions have access to the full SupaliveDb for both queries and mutations.\n *\n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n *\n * // Create a typed action builder\n * const action = createActionBuilder<ServerContext>();\n *\n * // Use it - context type is automatically inferred!\n * const processOrder = action({\n * args: z.object({ orderId: z.string() }),\n * handler: async (ctx, { orderId }) => {\n * // ctx.db for full database access\n * const order = await ctx.db.query(async (db) => {\n * return db.query(OrdersSchema).find(orderId);\n * });\n * await ctx.db.mutation(async (db) => {\n * await db.update(OrdersSchema, orderId, { status: \"processed\" });\n * });\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return { success: true };\n * }\n * });\n */\nexport function createActionBuilder<TContext = unknown>() {\n return function action<TInput, TResult, const TInternal extends boolean = false>(\n config: ActionConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): ActionProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"action\",\n inputSchema: config.args,\n outputSchema: config.returns,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n };\n };\n}\n\n// ─── Job Builder Factory ─────────────────────────────────────────────────────\n\n/**\n * Create a job builder with a pre-defined context type. A job is a\n * server-only procedure invoked by the scheduler over HTTP — either on its\n * declared `cron` schedule or as a precise one-shot enqueued via the\n * server's job API. Jobs run like actions (full db, non-transactional) and\n * are always internal, so they are never reachable from a client.\n *\n * @example\n * const job = createJobBuilder<ServerContext>();\n *\n * export const cleanupOtps = job({\n * cron: \"0 * * * *\", // hourly\n * args: z.object({}),\n * handler: async (ctx) => {\n * await ctx.db.mutation(async (db) => { ... });\n * return { ok: true };\n * },\n * });\n */\nexport function createJobBuilder<TContext = unknown>() {\n return function job<TInput, TResult>(\n config: JobConfig<TInput, TResult, TContext>\n ): JobProcedure<TInput, TResult, TContext> {\n return {\n _type: \"procedure\",\n procedureType: \"job\",\n inputSchema: config.args,\n fn: config.handler,\n internal: true,\n cron: config.cron,\n };\n };\n}"],"mappings":";;;;;;;;;;;;;;;AAgNA,SAAgB,QAAgC,QAAc;CAC5D,OAAO,OAAO,KAAK,EAAE,WAAW,KAAK,CAAC;AACxC;;;;;;;;;;AAWA,SAAgB,aAAqC,MAAc;CACjE,QAAQ,WAAiB,OAAO,KAAK,EAAE,WAAW,KAAK,CAAC;AAC1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0GA,SAAgB,qBAAyC;CACvD,OAAO,SAAS,MACd,QACsD;EACtD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,cAAc,OAAO;GACrB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;GAC9B,eAAe,OAAO;EACxB;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,wBAA4C;CAC1D,OAAO,SAAS,SACd,QACyD;EACzD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,cAAc,OAAO;GACrB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;EAChC;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,sBAA0C;CACxD,OAAO,SAAS,OACd,QACuD;EACvD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,cAAc,OAAO;GACrB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;EAChC;CACF;AACF;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,mBAAuC;CACrD,OAAO,SAAS,IACd,QACyC;EACzC,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,IAAI,OAAO;GACX,UAAU;GACV,MAAM,OAAO;EACf;CACF;AACF"}
@@ -0,0 +1,212 @@
1
+ import { z as z$1 } from "zod";
2
+ //#region src/router/procedure.ts
3
+ if (!globalThis.__supaliveModelNamePatched) {
4
+ const patched = /* @__PURE__ */ new Set();
5
+ const samples = [
6
+ z$1.string(),
7
+ z$1.number(),
8
+ z$1.boolean(),
9
+ z$1.bigint(),
10
+ z$1.date(),
11
+ z$1.object({}),
12
+ z$1.array(z$1.string()),
13
+ z$1.enum(["_"]),
14
+ z$1.literal("_"),
15
+ z$1.null(),
16
+ z$1.undefined(),
17
+ z$1.any(),
18
+ z$1.unknown(),
19
+ z$1.void(),
20
+ z$1.never(),
21
+ z$1.nan(),
22
+ z$1.record(z$1.string(), z$1.string()),
23
+ z$1.union([z$1.string(), z$1.number()]),
24
+ z$1.intersection(z$1.string(), z$1.string()),
25
+ z$1.tuple([z$1.string()]),
26
+ z$1.promise(z$1.string()),
27
+ z$1.custom(),
28
+ z$1.coerce.string(),
29
+ z$1.coerce.number(),
30
+ z$1.coerce.boolean(),
31
+ z$1.coerce.bigint(),
32
+ z$1.coerce.date(),
33
+ z$1.string().optional(),
34
+ z$1.string().nullable(),
35
+ z$1.string().default(""),
36
+ z$1.string().pipe(z$1.string()),
37
+ z$1.string().transform(() => "")
38
+ ];
39
+ for (const inst of samples) {
40
+ const proto = Object.getPrototypeOf(inst);
41
+ if (patched.has(proto)) continue;
42
+ patched.add(proto);
43
+ const metaDesc = Object.getOwnPropertyDescriptor(proto, "meta");
44
+ if (!metaDesc || !metaDesc.get) continue;
45
+ if (proto.modelName) continue;
46
+ Object.defineProperty(proto, "modelName", {
47
+ value: function modelName(name) {
48
+ return this.meta({ __genType: name });
49
+ },
50
+ writable: true,
51
+ configurable: true
52
+ });
53
+ }
54
+ globalThis.__supaliveModelNamePatched = true;
55
+ }
56
+ /**
57
+ * Create a query builder with a pre-defined context type.
58
+ * This allows you to define the context type once and have it inferred
59
+ * automatically in all your query handlers.
60
+ *
61
+ * @example
62
+ * // Define your server context
63
+ * interface ServerContext {
64
+ * auth: { userId: string };
65
+ * requestId: string;
66
+ * }
67
+ *
68
+ * // Create a typed query builder
69
+ * const query = createQueryBuilder<ServerContext>();
70
+ *
71
+ * // Use it - context type is automatically inferred!
72
+ * const getUser = query({
73
+ * args: z.object({ id: z.string() }),
74
+ * handler: async (ctx, { id }) => {
75
+ * // ctx.db for database queries
76
+ * const user = await ctx.db.query(UsersSchema).find(id);
77
+ * // ctx.context for server context
78
+ * console.log(ctx.context.requestId);
79
+ * return user;
80
+ * }
81
+ * });
82
+ */
83
+ function createQueryBuilder() {
84
+ return function query(config) {
85
+ return {
86
+ _type: "procedure",
87
+ procedureType: "query",
88
+ inputSchema: config.args,
89
+ outputSchema: config.returns,
90
+ fn: config.handler,
91
+ internal: config.internal ?? false,
92
+ queryIdentity: config.queryIdentity
93
+ };
94
+ };
95
+ }
96
+ /**
97
+ * Create a mutation builder with a pre-defined context type.
98
+ * This allows you to define the context type once and have it inferred
99
+ * automatically in all your mutation handlers.
100
+ *
101
+ * @example
102
+ * // Define your server context
103
+ * interface ServerContext {
104
+ * auth: { userId: string };
105
+ * requestId: string;
106
+ * }
107
+ *
108
+ * // Create a typed mutation builder
109
+ * const mutation = createMutationBuilder<ServerContext>();
110
+ *
111
+ * // Use it - context type is automatically inferred!
112
+ * const createUser = mutation({
113
+ * args: z.object({ name: z.string() }),
114
+ * handler: async (ctx, { name }) => {
115
+ * // ctx.db for mutations
116
+ * await ctx.db.insert(UsersSchema, id, { name });
117
+ * // ctx.context for server context
118
+ * console.log(ctx.context.requestId);
119
+ * return { success: true };
120
+ * }
121
+ * });
122
+ */
123
+ function createMutationBuilder() {
124
+ return function mutation(config) {
125
+ return {
126
+ _type: "procedure",
127
+ procedureType: "mutation",
128
+ inputSchema: config.args,
129
+ outputSchema: config.returns,
130
+ fn: config.handler,
131
+ internal: config.internal ?? false
132
+ };
133
+ };
134
+ }
135
+ /**
136
+ * Create an action builder with a pre-defined context type.
137
+ * Actions have access to the full SupaliveDb for both queries and mutations.
138
+ *
139
+ * @example
140
+ * // Define your server context
141
+ * interface ServerContext {
142
+ * auth: { userId: string };
143
+ * requestId: string;
144
+ * }
145
+ *
146
+ * // Create a typed action builder
147
+ * const action = createActionBuilder<ServerContext>();
148
+ *
149
+ * // Use it - context type is automatically inferred!
150
+ * const processOrder = action({
151
+ * args: z.object({ orderId: z.string() }),
152
+ * handler: async (ctx, { orderId }) => {
153
+ * // ctx.db for full database access
154
+ * const order = await ctx.db.query(async (db) => {
155
+ * return db.query(OrdersSchema).find(orderId);
156
+ * });
157
+ * await ctx.db.mutation(async (db) => {
158
+ * await db.update(OrdersSchema, orderId, { status: "processed" });
159
+ * });
160
+ * // ctx.context for server context
161
+ * console.log(ctx.context.requestId);
162
+ * return { success: true };
163
+ * }
164
+ * });
165
+ */
166
+ function createActionBuilder() {
167
+ return function action(config) {
168
+ return {
169
+ _type: "procedure",
170
+ procedureType: "action",
171
+ inputSchema: config.args,
172
+ outputSchema: config.returns,
173
+ fn: config.handler,
174
+ internal: config.internal ?? false
175
+ };
176
+ };
177
+ }
178
+ /**
179
+ * Create a job builder with a pre-defined context type. A job is a
180
+ * server-only procedure invoked by the scheduler over HTTP — either on its
181
+ * declared `cron` schedule or as a precise one-shot enqueued via the
182
+ * server's job API. Jobs run like actions (full db, non-transactional) and
183
+ * are always internal, so they are never reachable from a client.
184
+ *
185
+ * @example
186
+ * const job = createJobBuilder<ServerContext>();
187
+ *
188
+ * export const cleanupOtps = job({
189
+ * cron: "0 * * * *", // hourly
190
+ * args: z.object({}),
191
+ * handler: async (ctx) => {
192
+ * await ctx.db.mutation(async (db) => { ... });
193
+ * return { ok: true };
194
+ * },
195
+ * });
196
+ */
197
+ function createJobBuilder() {
198
+ return function job(config) {
199
+ return {
200
+ _type: "procedure",
201
+ procedureType: "job",
202
+ inputSchema: config.args,
203
+ fn: config.handler,
204
+ internal: true,
205
+ cron: config.cron
206
+ };
207
+ };
208
+ }
209
+ //#endregion
210
+ export { createQueryBuilder as i, createJobBuilder as n, createMutationBuilder as r, createActionBuilder as t };
211
+
212
+ //# sourceMappingURL=procedure-Ck4v3__H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"procedure-Ck4v3__H.js","names":["z"],"sources":["../src/router/procedure.ts"],"sourcesContent":["import type { ZodType } from \"zod\";\nimport { z } from \"zod\";\nimport type { DbReader, DbWriter } from \"../db/context\";\nimport type { SupaliveDb } from \"../db/realtime_db\";\nimport type { ObjectStorage } from \"../storage\";\nimport type { JobClient } from \"../jobs/scheduler\";\n\n// ─── Zod .modelName() extension ─────────────────────────────────────────────\n// Patches every Zod schema type with a `.modelName(\"Name\")` method that sets\n// `__genType` metadata for codegen model renaming. Runs once at import time.\n//\n// Zod v4: `z.string` is a factory — `z.string.prototype` is NOT the real class\n// prototype. We collect the actual prototypes by creating one instance per type,\n// then patch each unique prototype once.\nif (!(globalThis as any).__supaliveModelNamePatched) {\n const patched = new Set<object>();\n // Create one instance of each core type to capture real class prototypes.\n const samples: ZodType[] = [\n z.string(), z.number(), z.boolean(), z.bigint(), z.date(),\n z.object({}), z.array(z.string()), z.enum([\"_\"]),\n z.literal(\"_\"), z.null(), z.undefined(), z.any(), z.unknown(),\n z.void(), z.never(), z.nan(), z.record(z.string(), z.string()),\n z.union([z.string(), z.number()]), z.intersection(z.string(), z.string()),\n z.tuple([z.string()]), z.promise(z.string()), z.custom(),\n z.coerce.string(), z.coerce.number(), z.coerce.boolean(),\n z.coerce.bigint(), z.coerce.date(),\n z.string().optional(), z.string().nullable(), z.string().default(\"\"),\n z.string().pipe(z.string()), z.string().transform(() => \"\"),\n ];\n for (const inst of samples) {\n const proto = Object.getPrototypeOf(inst);\n if (patched.has(proto)) continue;\n patched.add(proto);\n const metaDesc = Object.getOwnPropertyDescriptor(proto, \"meta\");\n if (!metaDesc || !metaDesc.get) continue;\n if ((proto as any).modelName) continue;\n Object.defineProperty(proto, \"modelName\", {\n value: function modelName(name: string) {\n return this.meta({ __genType: name });\n },\n writable: true,\n configurable: true,\n });\n }\n (globalThis as any).__supaliveModelNamePatched = true;\n}\n\n// ─── Context Types ───────────────────────────────────────────────────────────\n\n/**\n * Query context passed to query handlers.\n * Contains database reader and user-defined server context.\n */\nexport interface QueryCtx<TContext = unknown> {\n /** Database reader for queries */\n db: DbReader;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n/**\n * Mutation context passed to mutation handlers.\n * Contains database writer and user-defined server context.\n */\nexport interface MutationCtx<TContext = unknown> {\n /** Database writer for mutations (includes insert/update/delete) */\n db: DbWriter;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n/**\n * Action context passed to action handlers.\n *\n * Actions are the \"external I/O\" tier: they hold the full {@link SupaliveDb}\n * (queries + mutations) and are the ONLY context that also carries side-effect\n * services — {@link ObjectStorage} for uploads/downloads and a {@link JobClient}\n * for scheduling precise one-shots. Queries/mutations stay pure (db only) so\n * they remain cacheable and transaction-scoped.\n */\nexport interface ActionCtx<TContext = unknown> {\n /** Full database interface for queries and mutations */\n db: SupaliveDb;\n /** Object storage, when the server was configured with one (see\n * `SupaliveServerConfig.storage`); `undefined` otherwise. The usual home\n * for upload/download presigning. */\n storage: ObjectStorage;\n /** Job scheduler client for enqueueing precise one-shots, when the server\n * was configured with a `scheduler`; `undefined` otherwise. Scheduling is\n * network I/O, so it belongs in actions, never inside a DB transaction. */\n scheduler: JobClient;\n /** User-defined server context (auth, requestId, etc.) */\n serverCtx?: TContext;\n}\n\n/**\n * Job context passed to job handlers. Structurally identical to\n * {@link ActionCtx}: a job is a server-only procedure that runs\n * non-transactionally against the full {@link SupaliveDb} and may perform\n * external work, but it is triggered by the scheduler over HTTP (a cron tick\n * or a precise one-shot) rather than by a connected client. `serverCtx` is\n * the system context built by the server's `jobContext` factory.\n */\nexport interface JobCtx<TContext = unknown> {\n /** Full database interface for queries and mutations */\n db: SupaliveDb;\n /** System server context built by the server for scheduler-triggered runs */\n serverCtx?: TContext;\n}\n\n/**\n * Context handed to `caller.<proc>.runQuery` / `.runMutation` when invoking one\n * procedure from inside another. Pass the caller handler's own `ctx` — its `db`\n * carries the parent's live transaction (a {@link DbReader}/{@link DbWriter}) or,\n * inside an action, the full {@link SupaliveDb}. The caller uses this to decide\n * whether the nested call joins the parent's snapshot (queries) or runs as an\n * independent sub-transaction (mutations).\n */\nexport interface ParentCtx<TContext = unknown> {\n db: DbReader | DbWriter | SupaliveDb;\n serverCtx?: TContext | undefined;\n}\n\n// ─── Procedure Types ─────────────────────────────────────────────────────────\n\nexport type QueryFn<TInput, TResult, TContext = unknown> = (\n ctx: QueryCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\nexport type MutationFn<TInput, TResult, TContext = unknown> = (\n ctx: MutationCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\nexport type ActionFn<TInput, TResult, TContext = unknown> = (\n ctx: ActionCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\nexport type JobFn<TInput, TResult, TContext = unknown> = (\n ctx: JobCtx<TContext>,\n input: TInput,\n) => Promise<TResult>;\n\n/**\n * Per-procedure override for the cache/subscription segmentation key.\n *\n * omitted | undefined → fall back to `config.getUserId(serverCtx)` (default)\n * false → no identity in hash; cache/sub shared across all users\n * string → a static identity literal (e.g. \"public\" or a tenant id)\n * function → compute from serverCtx + input (sync)\n *\n * When the result of a query is identical regardless of who calls it, set\n * this to a literal (or `false`) so a single cache entry serves everyone.\n *\n * The function form intentionally takes `serverCtx` (not the full `QueryCtx`)\n * because identity is resolved before any DB read is issued.\n */\nexport type QueryIdentitySpec<TInput, TContext> =\n | false\n | string\n | ((serverCtx: TContext, input: TInput) => string | null | undefined);\n\nexport interface BaseProcedure<\n TInput, TResult,\n TType extends \"query\" | \"mutation\" | \"action\" | \"job\",\n TContext = unknown,\n TInternal extends boolean = boolean\n> {\n readonly _type: \"procedure\";\n readonly procedureType: TType;\n readonly inputSchema: ZodType<TInput>;\n readonly outputSchema?: ZodType<any>;\n readonly fn: QueryFn<TInput, TResult, TContext> | MutationFn<TInput, TResult, TContext> | ActionFn<TInput, TResult, TContext> | JobFn<TInput, TResult, TContext>;\n readonly internal: TInternal;\n}\n\nexport interface QueryProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"query\", TContext, TInternal> {\n readonly procedureType: \"query\";\n readonly fn: QueryFn<TInput, TResult, TContext>;\n readonly queryIdentity?: QueryIdentitySpec<TInput, TContext>;\n}\n\nexport interface MutationProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"mutation\", TContext, TInternal> {\n readonly procedureType: \"mutation\";\n readonly fn: MutationFn<TInput, TResult, TContext>;\n}\n\nexport interface ActionProcedure<\n TInput, TResult,\n TContext = unknown,\n TInternal extends boolean = boolean\n> extends BaseProcedure<TInput, TResult, \"action\", TContext, TInternal> {\n readonly procedureType: \"action\";\n readonly fn: ActionFn<TInput, TResult, TContext>;\n}\n\n/**\n * A scheduler-triggered, server-only procedure. Runs like an action (full\n * db, non-transactional, may do external work) but is dispatched by the\n * server's HTTP job endpoint on a cron tick or a precise one-shot rather\n * than over the client WebSocket. Always {@link internal}: true, so it is\n * never reachable via `call`/`subscribe`.\n */\nexport interface JobProcedure<\n TInput, TResult,\n TContext = unknown,\n> extends BaseProcedure<TInput, TResult, \"job\", TContext, true> {\n readonly procedureType: \"job\";\n readonly fn: JobFn<TInput, TResult, TContext>;\n /**\n * Cron expression for a recurring job (e.g. `\"0 3 * * *\"`). Declared crons\n * are synced to the scheduler at server startup. Omit for a job that is\n * only ever invoked as a precise one-shot via the scheduler API.\n */\n readonly cron?: string;\n}\n\nexport type AnyProcedure<TContext = unknown> =\n | QueryProcedure<any, any, TContext>\n | MutationProcedure<any, any, TContext>\n | ActionProcedure<any, any, TContext>\n | JobProcedure<any, any, TContext>;\n\n// ─── Procedure Configuration Types ───────────────────────────────────────────\n\nexport interface QueryConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The query handler function */\n handler: QueryFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n /**\n * Optional Zod schema describing return-type overrides for codegen.\n * Only the fields you specify are overridden; everything else is inferred\n * from the handler's TypeScript return type. Use `.modelName(\"Name\")`\n * on a Zod object to rename the generated model class.\n */\n returns?: ZodType<any>;\n /**\n * Override the cache/subscription segmentation key for this procedure.\n * See {@link QueryIdentitySpec}. Omit to keep the default (per-user) behavior.\n */\n queryIdentity?: QueryIdentitySpec<TInput, TContext>;\n}\n\nexport interface MutationConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The mutation handler function */\n handler: MutationFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n /**\n * Optional Zod schema describing return-type overrides for codegen.\n * Only the fields you specify are overridden; everything else is inferred\n * from the handler's TypeScript return type.\n */\n returns?: ZodType<any>;\n}\n\nexport interface ActionConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for input validation */\n args: ZodType<TInput>;\n /** The action handler function */\n handler: ActionFn<TInput, TResult, TContext>;\n /** Mark as internal (server-only). Default: false */\n internal?: boolean;\n /**\n * Optional Zod schema describing return-type overrides for codegen.\n * Only the fields you specify are overridden; everything else is inferred\n * from the handler's TypeScript return type.\n */\n returns?: ZodType<any>;\n}\n\nexport interface JobConfig<TInput, TResult, TContext = unknown> {\n /** Zod schema for the job payload */\n args: ZodType<TInput>;\n /** The job handler function */\n handler: JobFn<TInput, TResult, TContext>;\n /**\n * Cron expression for a recurring schedule (e.g. `\"0 3 * * *\"`). Omit for a\n * job that is only invoked as a precise one-shot.\n */\n cron?: string;\n}\n\n/** Extract input type from a procedure */\nexport type InputOf<T> = T extends BaseProcedure<infer I, any, any, any> ? I : never;\n\n/** Extract output type from a procedure */\nexport type OutputOf<T> = T extends BaseProcedure<any, infer O, any, any> ? O : never;\n\n/** Extract procedure type (query/mutation) */\nexport type TypeOf<T> = T extends BaseProcedure<any, any, infer Type, any> ? Type : never;\n\n/** Extract server context type from a procedure */\nexport type ContextOf<T> = T extends BaseProcedure<any, any, any, infer C> ? C : never;\n\n/**\n * Create a query builder with a pre-defined context type.\n * This allows you to define the context type once and have it inferred\n * automatically in all your query handlers.\n * \n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n * \n * // Create a typed query builder\n * const query = createQueryBuilder<ServerContext>();\n * \n * // Use it - context type is automatically inferred!\n * const getUser = query({\n * args: z.object({ id: z.string() }),\n * handler: async (ctx, { id }) => {\n * // ctx.db for database queries\n * const user = await ctx.db.query(UsersSchema).find(id);\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return user;\n * }\n * });\n */\nexport function createQueryBuilder<TContext = unknown>() {\n return function query<TInput, TResult, const TInternal extends boolean = false>(\n config: QueryConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): QueryProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"query\",\n inputSchema: config.args,\n outputSchema: config.returns,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n queryIdentity: config.queryIdentity,\n };\n };\n}\n\n// ─── Mutation Builder Factory ────────────────────────────────────────────────\n\n/**\n * Create a mutation builder with a pre-defined context type.\n * This allows you to define the context type once and have it inferred\n * automatically in all your mutation handlers.\n * \n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n * \n * // Create a typed mutation builder\n * const mutation = createMutationBuilder<ServerContext>();\n * \n * // Use it - context type is automatically inferred!\n * const createUser = mutation({\n * args: z.object({ name: z.string() }),\n * handler: async (ctx, { name }) => {\n * // ctx.db for mutations\n * await ctx.db.insert(UsersSchema, id, { name });\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return { success: true };\n * }\n * });\n */\nexport function createMutationBuilder<TContext = unknown>() {\n return function mutation<TInput, TResult, const TInternal extends boolean = false>(\n config: MutationConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): MutationProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"mutation\",\n inputSchema: config.args,\n outputSchema: config.returns,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n };\n };\n}\n\n// ─── Action Builder Factory ──────────────────────────────────────────────────\n\n/**\n * Create an action builder with a pre-defined context type.\n * Actions have access to the full SupaliveDb for both queries and mutations.\n *\n * @example\n * // Define your server context\n * interface ServerContext {\n * auth: { userId: string };\n * requestId: string;\n * }\n *\n * // Create a typed action builder\n * const action = createActionBuilder<ServerContext>();\n *\n * // Use it - context type is automatically inferred!\n * const processOrder = action({\n * args: z.object({ orderId: z.string() }),\n * handler: async (ctx, { orderId }) => {\n * // ctx.db for full database access\n * const order = await ctx.db.query(async (db) => {\n * return db.query(OrdersSchema).find(orderId);\n * });\n * await ctx.db.mutation(async (db) => {\n * await db.update(OrdersSchema, orderId, { status: \"processed\" });\n * });\n * // ctx.context for server context\n * console.log(ctx.context.requestId);\n * return { success: true };\n * }\n * });\n */\nexport function createActionBuilder<TContext = unknown>() {\n return function action<TInput, TResult, const TInternal extends boolean = false>(\n config: ActionConfig<TInput, TResult, TContext> & { internal?: TInternal }\n ): ActionProcedure<TInput, TResult, TContext, TInternal> {\n return {\n _type: \"procedure\",\n procedureType: \"action\",\n inputSchema: config.args,\n outputSchema: config.returns,\n fn: config.handler,\n internal: (config.internal ?? false) as TInternal,\n };\n };\n}\n\n// ─── Job Builder Factory ─────────────────────────────────────────────────────\n\n/**\n * Create a job builder with a pre-defined context type. A job is a\n * server-only procedure invoked by the scheduler over HTTP — either on its\n * declared `cron` schedule or as a precise one-shot enqueued via the\n * server's job API. Jobs run like actions (full db, non-transactional) and\n * are always internal, so they are never reachable from a client.\n *\n * @example\n * const job = createJobBuilder<ServerContext>();\n *\n * export const cleanupOtps = job({\n * cron: \"0 * * * *\", // hourly\n * args: z.object({}),\n * handler: async (ctx) => {\n * await ctx.db.mutation(async (db) => { ... });\n * return { ok: true };\n * },\n * });\n */\nexport function createJobBuilder<TContext = unknown>() {\n return function job<TInput, TResult>(\n config: JobConfig<TInput, TResult, TContext>\n ): JobProcedure<TInput, TResult, TContext> {\n return {\n _type: \"procedure\",\n procedureType: \"job\",\n inputSchema: config.args,\n fn: config.handler,\n internal: true,\n cron: config.cron,\n };\n };\n}"],"mappings":";;AAcA,IAAI,CAAE,WAAmB,4BAA4B;CACnD,MAAM,0BAAU,IAAI,IAAY;CAEhC,MAAM,UAAqB;EACzBA,IAAE,OAAO;EAAGA,IAAE,OAAO;EAAGA,IAAE,QAAQ;EAAGA,IAAE,OAAO;EAAGA,IAAE,KAAK;EACxDA,IAAE,OAAO,CAAC,CAAC;EAAGA,IAAE,MAAMA,IAAE,OAAO,CAAC;EAAGA,IAAE,KAAK,CAAC,GAAG,CAAC;EAC/CA,IAAE,QAAQ,GAAG;EAAGA,IAAE,KAAK;EAAGA,IAAE,UAAU;EAAGA,IAAE,IAAI;EAAGA,IAAE,QAAQ;EAC5DA,IAAE,KAAK;EAAGA,IAAE,MAAM;EAAGA,IAAE,IAAI;EAAGA,IAAE,OAAOA,IAAE,OAAO,GAAGA,IAAE,OAAO,CAAC;EAC7DA,IAAE,MAAM,CAACA,IAAE,OAAO,GAAGA,IAAE,OAAO,CAAC,CAAC;EAAGA,IAAE,aAAaA,IAAE,OAAO,GAAGA,IAAE,OAAO,CAAC;EACxEA,IAAE,MAAM,CAACA,IAAE,OAAO,CAAC,CAAC;EAAGA,IAAE,QAAQA,IAAE,OAAO,CAAC;EAAGA,IAAE,OAAO;EACvDA,IAAE,OAAO,OAAO;EAAGA,IAAE,OAAO,OAAO;EAAGA,IAAE,OAAO,QAAQ;EACvDA,IAAE,OAAO,OAAO;EAAGA,IAAE,OAAO,KAAK;EACjCA,IAAE,OAAO,CAAC,CAAC,SAAS;EAAGA,IAAE,OAAO,CAAC,CAAC,SAAS;EAAGA,IAAE,OAAO,CAAC,CAAC,QAAQ,EAAE;EACnEA,IAAE,OAAO,CAAC,CAAC,KAAKA,IAAE,OAAO,CAAC;EAAGA,IAAE,OAAO,CAAC,CAAC,gBAAgB,EAAE;CAC5D;CACA,KAAK,MAAM,QAAQ,SAAS;EAC1B,MAAM,QAAQ,OAAO,eAAe,IAAI;EACxC,IAAI,QAAQ,IAAI,KAAK,GAAG;EACxB,QAAQ,IAAI,KAAK;EACjB,MAAM,WAAW,OAAO,yBAAyB,OAAO,MAAM;EAC9D,IAAI,CAAC,YAAY,CAAC,SAAS,KAAK;EAChC,IAAK,MAAc,WAAW;EAC9B,OAAO,eAAe,OAAO,aAAa;GACxC,OAAO,SAAS,UAAU,MAAc;IACtC,OAAO,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC;GACtC;GACA,UAAU;GACV,cAAc;EAChB,CAAC;CACH;CACA,WAAoB,6BAA6B;AACnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoSA,SAAgB,qBAAyC;CACvD,OAAO,SAAS,MACd,QACsD;EACtD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,cAAc,OAAO;GACrB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;GAC9B,eAAe,OAAO;EACxB;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,wBAA4C;CAC1D,OAAO,SAAS,SACd,QACyD;EACzD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,cAAc,OAAO;GACrB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;EAChC;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,sBAA0C;CACxD,OAAO,SAAS,OACd,QACuD;EACvD,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,cAAc,OAAO;GACrB,IAAI,OAAO;GACX,UAAW,OAAO,YAAY;EAChC;CACF;AACF;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,mBAAuC;CACrD,OAAO,SAAS,IACd,QACyC;EACzC,OAAO;GACL,OAAO;GACP,eAAe;GACf,aAAa,OAAO;GACpB,IAAI,OAAO;GACX,UAAU;GACV,MAAM,OAAO;EACf;CACF;AACF"}