@sequenceholdings/orm 2.8.1 → 2.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.cts CHANGED
@@ -86,7 +86,10 @@ declare class TableQuery<Row extends Record<string, unknown>, Result = Row> {
86
86
  private filter;
87
87
  }
88
88
 
89
+ type OperationSelection = 'name';
90
+
89
91
  /** Runtime SQL inputs are values, never interpolated into the submitted SQL. */
92
+ declare const BUILTIN_SQL_READ_NAME = "BuiltinSqlRead";
90
93
  declare const BUILTIN_SQL_READ_HASH = "sha256:a50c477c952a5e0fe68ed158a4530e4aab573c09bcbb1a8ac454dc88a39a6258";
91
94
  type SqlQueryParameter = {
92
95
  type: 'text' | 'uuid' | 'date' | 'timestamptz' | 'numeric' | 'bigint';
@@ -115,9 +118,19 @@ interface SqlQueryResult {
115
118
  truncated: boolean;
116
119
  }
117
120
 
121
+ /**
122
+ * Persisted-operation client for the v2 data plane. The wire carries only
123
+ * `{ op: <name>, variables, idempotencyKey?, expectedSourceGeneration? }`. Runtime SQL contracts accept SQL in variables;
124
+ * GraphQL and fixed SQL operations keep their documents server-side. This runtime
125
+ * is deliberately free of node builtins and third-
126
+ * party deps (no @apollo/client import): Apollo integration happens through a
127
+ * fetch-compatible shim (`createOrmFetch`) handed to `HttpLink({ fetch })`.
128
+ */
129
+
118
130
  /** One entry of `operations.manifest.json` (generated by `orm generate`). */
119
131
  interface ManifestOperation {
120
- readonly hash: string;
132
+ /** Legacy manifests only; requests use the operation name. */
133
+ readonly hash?: string;
121
134
  readonly kind: 'query' | 'mutation';
122
135
  readonly requires: {
123
136
  readonly capability?: string;
@@ -125,7 +138,8 @@ interface ManifestOperation {
125
138
  } | null;
126
139
  }
127
140
  interface OperationsManifest {
128
- readonly schemaHash: string;
141
+ /** Legacy manifest metadata; absent from newly generated clients. */
142
+ readonly schemaHash?: string;
129
143
  readonly opsHash?: string;
130
144
  readonly operations: Readonly<Record<string, ManifestOperation>>;
131
145
  }
@@ -134,6 +148,8 @@ interface OperationExecutorConfig {
134
148
  baseUrl: string;
135
149
  namespace: string;
136
150
  manifest?: OperationsManifest;
151
+ /** Optional compatibility setting; only stable name selection is supported. */
152
+ operationSelection?: OperationSelection;
137
153
  /** App-user / session bearer → `Authorization: Bearer`. */
138
154
  getToken?: () => Promise<string | null> | string | null;
139
155
  /** Delegated, attenuated function token → the `ORM_DATA_TOKEN_HEADER`. */
@@ -147,7 +163,7 @@ interface OperationExecutionOptions {
147
163
  expectedSourceGeneration?: string;
148
164
  }
149
165
  interface OperationExecutor {
150
- /** Execute a manifest operation by name (or a raw `sha256:` hash). */
166
+ /** Execute a registered operation by its stable name. */
151
167
  execute<TData = Record<string, unknown>>(op: string, variables?: Record<string, unknown>, options?: OperationExecutionOptions): Promise<TData>;
152
168
  }
153
169
  /** Additive factory result; existing host wrappers implementing OperationExecutor remain valid. */
@@ -178,13 +194,19 @@ interface TypedReadReceiptOperationExecutor extends TypedOperationExecutor {
178
194
  }
179
195
  type TypedReadReceiptSqlOperationExecutor = TypedReadReceiptOperationExecutor & ReadReceiptSqlOperationExecutor;
180
196
  /** Generated handle identifies the registered contract; optional types are phantom. */
181
- interface OperationReference<TVariables extends Record<string, unknown>, TData> {
197
+ type OperationReference<TVariables extends Record<string, unknown>, TData> = {
182
198
  readonly namespace: string;
183
- readonly hash: string;
184
199
  readonly variables?: TVariables;
185
200
  readonly result?: TData;
186
- }
187
- declare function createOperationExecutor({ baseUrl, namespace, manifest, getToken, getDataToken, fetchImpl, }: OperationExecutorConfig): TypedReadReceiptSqlOperationExecutor;
201
+ readonly kind?: 'query' | 'mutation';
202
+ } & ({
203
+ readonly name: string;
204
+ readonly hash?: string;
205
+ } | {
206
+ readonly hash: string;
207
+ readonly name?: string;
208
+ });
209
+ declare function createOperationExecutor({ baseUrl, namespace, manifest, operationSelection, getToken, getDataToken, fetchImpl, }: OperationExecutorConfig): TypedReadReceiptSqlOperationExecutor;
188
210
  /**
189
211
  * Configure the process-wide executor the generated `db<Name>` server
190
212
  * functions call through. Call once at startup (server-side); browser apps
@@ -200,7 +222,7 @@ declare function executeOperation<TData = Record<string, unknown>>({ op, variabl
200
222
  /**
201
223
  * A fetch-compatible function for `new HttpLink({ uri: '/unused', fetch: createOrmFetch(...) })`.
202
224
  * Intercepts Apollo's GraphQL POST, swaps the body for the persisted-op
203
- * envelope (`{ op: <hash>, variables }`) resolved via the manifest's
225
+ * envelope (`{ op: <name>, variables }`) resolved via the manifest's
204
226
  * operationName, rewrites the URL to the data plane, and attaches auth.
205
227
  * The GraphQL-spec response body passes through untouched, so InMemoryCache
206
228
  * and error links behave exactly as they do against a GraphQL server.
@@ -213,6 +235,7 @@ interface OperationTransportRequest {
213
235
  variables: Record<string, unknown>;
214
236
  idempotencyKey?: string;
215
237
  expectedSourceGeneration?: string;
238
+ expectedKind?: 'query' | 'mutation';
216
239
  }
217
240
  interface OperationTransportResponse {
218
241
  ok: boolean;
@@ -220,14 +243,6 @@ interface OperationTransportResponse {
220
243
  body: unknown;
221
244
  }
222
245
  type OperationTransport = (request: OperationTransportRequest) => Promise<OperationTransportResponse>;
223
- /**
224
- * How a string selector reaches the server. `hash` (the default) resolves the
225
- * name through the manifest and sends the hash, pinning the exact contract the
226
- * caller was generated against. `name` sends the name itself, resolved by the
227
- * server against the namespace's active version when the request runs, so the
228
- * caller survives the rehash every schema change causes and needs no manifest.
229
- */
230
- type OperationSelection = 'hash' | 'name';
231
246
  /**
232
247
  * Execute generated operations through a host-owned authenticated transport.
233
248
  * No credential handling, retries, or global configuration. The manifest is
@@ -338,4 +353,4 @@ declare function createServiceOrmClient<Tables extends Record<string, Record<str
338
353
  transport?: OrmTransport;
339
354
  }): OrmClient<Tables, Actions>;
340
355
 
341
- export { BUILTIN_SQL_READ_HASH, type FilterValue, type ManifestOperation, type OperationErrorEntry, type OperationExecutionOptions, type OperationExecutor, type OperationExecutorConfig, type OperationReadReceipt, type OperationReference, type OperationSelection, type OperationTransport, type OperationTransportRequest, type OperationTransportResponse, type OperationsManifest, type OrmActionShape, type OrmActions, type OrmClient, OrmClientError, OrmOperationError, type OrmTransport, type QueryParam, type ReadReceiptOperationExecutor, type ReadReceiptSqlOperationExecutor, type ReadResponse, type SqlOperationExecutor, type SqlQueryParameter, type SqlQueryResult, type SqlQueryVariables, TableQuery, type TypedOperationExecutor, type TypedReadReceiptOperationExecutor, type TypedReadReceiptSqlOperationExecutor, type TypedSqlOperationExecutor, configureOrmOperations, createFetchTransport, createOperationExecutor, createOperationExecutorWithTransport, createOrmClient, createOrmFetch, createServiceOrmClient, executeOperation };
356
+ export { BUILTIN_SQL_READ_HASH, BUILTIN_SQL_READ_NAME, type FilterValue, type ManifestOperation, type OperationErrorEntry, type OperationExecutionOptions, type OperationExecutor, type OperationExecutorConfig, type OperationReadReceipt, type OperationReference, type OperationSelection, type OperationTransport, type OperationTransportRequest, type OperationTransportResponse, type OperationsManifest, type OrmActionShape, type OrmActions, type OrmClient, OrmClientError, OrmOperationError, type OrmTransport, type QueryParam, type ReadReceiptOperationExecutor, type ReadReceiptSqlOperationExecutor, type ReadResponse, type SqlOperationExecutor, type SqlQueryParameter, type SqlQueryResult, type SqlQueryVariables, TableQuery, type TypedOperationExecutor, type TypedReadReceiptOperationExecutor, type TypedReadReceiptSqlOperationExecutor, type TypedSqlOperationExecutor, configureOrmOperations, createFetchTransport, createOperationExecutor, createOperationExecutorWithTransport, createOrmClient, createOrmFetch, createServiceOrmClient, executeOperation };
package/dist/client.d.ts CHANGED
@@ -86,7 +86,10 @@ declare class TableQuery<Row extends Record<string, unknown>, Result = Row> {
86
86
  private filter;
87
87
  }
88
88
 
89
+ type OperationSelection = 'name';
90
+
89
91
  /** Runtime SQL inputs are values, never interpolated into the submitted SQL. */
92
+ declare const BUILTIN_SQL_READ_NAME = "BuiltinSqlRead";
90
93
  declare const BUILTIN_SQL_READ_HASH = "sha256:a50c477c952a5e0fe68ed158a4530e4aab573c09bcbb1a8ac454dc88a39a6258";
91
94
  type SqlQueryParameter = {
92
95
  type: 'text' | 'uuid' | 'date' | 'timestamptz' | 'numeric' | 'bigint';
@@ -115,9 +118,19 @@ interface SqlQueryResult {
115
118
  truncated: boolean;
116
119
  }
117
120
 
121
+ /**
122
+ * Persisted-operation client for the v2 data plane. The wire carries only
123
+ * `{ op: <name>, variables, idempotencyKey?, expectedSourceGeneration? }`. Runtime SQL contracts accept SQL in variables;
124
+ * GraphQL and fixed SQL operations keep their documents server-side. This runtime
125
+ * is deliberately free of node builtins and third-
126
+ * party deps (no @apollo/client import): Apollo integration happens through a
127
+ * fetch-compatible shim (`createOrmFetch`) handed to `HttpLink({ fetch })`.
128
+ */
129
+
118
130
  /** One entry of `operations.manifest.json` (generated by `orm generate`). */
119
131
  interface ManifestOperation {
120
- readonly hash: string;
132
+ /** Legacy manifests only; requests use the operation name. */
133
+ readonly hash?: string;
121
134
  readonly kind: 'query' | 'mutation';
122
135
  readonly requires: {
123
136
  readonly capability?: string;
@@ -125,7 +138,8 @@ interface ManifestOperation {
125
138
  } | null;
126
139
  }
127
140
  interface OperationsManifest {
128
- readonly schemaHash: string;
141
+ /** Legacy manifest metadata; absent from newly generated clients. */
142
+ readonly schemaHash?: string;
129
143
  readonly opsHash?: string;
130
144
  readonly operations: Readonly<Record<string, ManifestOperation>>;
131
145
  }
@@ -134,6 +148,8 @@ interface OperationExecutorConfig {
134
148
  baseUrl: string;
135
149
  namespace: string;
136
150
  manifest?: OperationsManifest;
151
+ /** Optional compatibility setting; only stable name selection is supported. */
152
+ operationSelection?: OperationSelection;
137
153
  /** App-user / session bearer → `Authorization: Bearer`. */
138
154
  getToken?: () => Promise<string | null> | string | null;
139
155
  /** Delegated, attenuated function token → the `ORM_DATA_TOKEN_HEADER`. */
@@ -147,7 +163,7 @@ interface OperationExecutionOptions {
147
163
  expectedSourceGeneration?: string;
148
164
  }
149
165
  interface OperationExecutor {
150
- /** Execute a manifest operation by name (or a raw `sha256:` hash). */
166
+ /** Execute a registered operation by its stable name. */
151
167
  execute<TData = Record<string, unknown>>(op: string, variables?: Record<string, unknown>, options?: OperationExecutionOptions): Promise<TData>;
152
168
  }
153
169
  /** Additive factory result; existing host wrappers implementing OperationExecutor remain valid. */
@@ -178,13 +194,19 @@ interface TypedReadReceiptOperationExecutor extends TypedOperationExecutor {
178
194
  }
179
195
  type TypedReadReceiptSqlOperationExecutor = TypedReadReceiptOperationExecutor & ReadReceiptSqlOperationExecutor;
180
196
  /** Generated handle identifies the registered contract; optional types are phantom. */
181
- interface OperationReference<TVariables extends Record<string, unknown>, TData> {
197
+ type OperationReference<TVariables extends Record<string, unknown>, TData> = {
182
198
  readonly namespace: string;
183
- readonly hash: string;
184
199
  readonly variables?: TVariables;
185
200
  readonly result?: TData;
186
- }
187
- declare function createOperationExecutor({ baseUrl, namespace, manifest, getToken, getDataToken, fetchImpl, }: OperationExecutorConfig): TypedReadReceiptSqlOperationExecutor;
201
+ readonly kind?: 'query' | 'mutation';
202
+ } & ({
203
+ readonly name: string;
204
+ readonly hash?: string;
205
+ } | {
206
+ readonly hash: string;
207
+ readonly name?: string;
208
+ });
209
+ declare function createOperationExecutor({ baseUrl, namespace, manifest, operationSelection, getToken, getDataToken, fetchImpl, }: OperationExecutorConfig): TypedReadReceiptSqlOperationExecutor;
188
210
  /**
189
211
  * Configure the process-wide executor the generated `db<Name>` server
190
212
  * functions call through. Call once at startup (server-side); browser apps
@@ -200,7 +222,7 @@ declare function executeOperation<TData = Record<string, unknown>>({ op, variabl
200
222
  /**
201
223
  * A fetch-compatible function for `new HttpLink({ uri: '/unused', fetch: createOrmFetch(...) })`.
202
224
  * Intercepts Apollo's GraphQL POST, swaps the body for the persisted-op
203
- * envelope (`{ op: <hash>, variables }`) resolved via the manifest's
225
+ * envelope (`{ op: <name>, variables }`) resolved via the manifest's
204
226
  * operationName, rewrites the URL to the data plane, and attaches auth.
205
227
  * The GraphQL-spec response body passes through untouched, so InMemoryCache
206
228
  * and error links behave exactly as they do against a GraphQL server.
@@ -213,6 +235,7 @@ interface OperationTransportRequest {
213
235
  variables: Record<string, unknown>;
214
236
  idempotencyKey?: string;
215
237
  expectedSourceGeneration?: string;
238
+ expectedKind?: 'query' | 'mutation';
216
239
  }
217
240
  interface OperationTransportResponse {
218
241
  ok: boolean;
@@ -220,14 +243,6 @@ interface OperationTransportResponse {
220
243
  body: unknown;
221
244
  }
222
245
  type OperationTransport = (request: OperationTransportRequest) => Promise<OperationTransportResponse>;
223
- /**
224
- * How a string selector reaches the server. `hash` (the default) resolves the
225
- * name through the manifest and sends the hash, pinning the exact contract the
226
- * caller was generated against. `name` sends the name itself, resolved by the
227
- * server against the namespace's active version when the request runs, so the
228
- * caller survives the rehash every schema change causes and needs no manifest.
229
- */
230
- type OperationSelection = 'hash' | 'name';
231
246
  /**
232
247
  * Execute generated operations through a host-owned authenticated transport.
233
248
  * No credential handling, retries, or global configuration. The manifest is
@@ -338,4 +353,4 @@ declare function createServiceOrmClient<Tables extends Record<string, Record<str
338
353
  transport?: OrmTransport;
339
354
  }): OrmClient<Tables, Actions>;
340
355
 
341
- export { BUILTIN_SQL_READ_HASH, type FilterValue, type ManifestOperation, type OperationErrorEntry, type OperationExecutionOptions, type OperationExecutor, type OperationExecutorConfig, type OperationReadReceipt, type OperationReference, type OperationSelection, type OperationTransport, type OperationTransportRequest, type OperationTransportResponse, type OperationsManifest, type OrmActionShape, type OrmActions, type OrmClient, OrmClientError, OrmOperationError, type OrmTransport, type QueryParam, type ReadReceiptOperationExecutor, type ReadReceiptSqlOperationExecutor, type ReadResponse, type SqlOperationExecutor, type SqlQueryParameter, type SqlQueryResult, type SqlQueryVariables, TableQuery, type TypedOperationExecutor, type TypedReadReceiptOperationExecutor, type TypedReadReceiptSqlOperationExecutor, type TypedSqlOperationExecutor, configureOrmOperations, createFetchTransport, createOperationExecutor, createOperationExecutorWithTransport, createOrmClient, createOrmFetch, createServiceOrmClient, executeOperation };
356
+ export { BUILTIN_SQL_READ_HASH, BUILTIN_SQL_READ_NAME, type FilterValue, type ManifestOperation, type OperationErrorEntry, type OperationExecutionOptions, type OperationExecutor, type OperationExecutorConfig, type OperationReadReceipt, type OperationReference, type OperationSelection, type OperationTransport, type OperationTransportRequest, type OperationTransportResponse, type OperationsManifest, type OrmActionShape, type OrmActions, type OrmClient, OrmClientError, OrmOperationError, type OrmTransport, type QueryParam, type ReadReceiptOperationExecutor, type ReadReceiptSqlOperationExecutor, type ReadResponse, type SqlOperationExecutor, type SqlQueryParameter, type SqlQueryResult, type SqlQueryVariables, TableQuery, type TypedOperationExecutor, type TypedReadReceiptOperationExecutor, type TypedReadReceiptSqlOperationExecutor, type TypedSqlOperationExecutor, configureOrmOperations, createFetchTransport, createOperationExecutor, createOperationExecutorWithTransport, createOrmClient, createOrmFetch, createServiceOrmClient, executeOperation };
package/dist/client.js CHANGED
@@ -159,6 +159,51 @@ var TableQuery = class _TableQuery {
159
159
  }
160
160
  };
161
161
 
162
+ // src/client/sql.ts
163
+ var BUILTIN_SQL_READ_NAME = "BuiltinSqlRead";
164
+ var BUILTIN_SQL_READ_HASH = "sha256:a50c477c952a5e0fe68ed158a4530e4aab573c09bcbb1a8ac454dc88a39a6258";
165
+
166
+ // src/client/operation-selection.ts
167
+ var NAME = /^[_A-Za-z][_0-9A-Za-z]{0,254}$/;
168
+ function selectorForReference(op) {
169
+ if (typeof op === "string") return op;
170
+ if (op.name) return op.name;
171
+ if (op.hash?.startsWith("sha256:")) return op.hash;
172
+ throw new OrmClientError("unknown operation reference \u2014 regenerate the client");
173
+ }
174
+ function manifestEntry({ selector, operations }) {
175
+ if (selector.startsWith("sha256:")) return [...operations].find(([, entry2]) => entry2.hash === selector);
176
+ const entry = operations.get(selector);
177
+ return entry ? [selector, entry] : void 0;
178
+ }
179
+ function referenceKind(op) {
180
+ return typeof op === "string" ? void 0 : op.kind;
181
+ }
182
+ function assertKnownName({ name, known, operations, selector }) {
183
+ if (!NAME.test(name) || !known || ["__proto__", "constructor", "prototype"].includes(name)) {
184
+ throw new OrmClientError(`unknown operation "${selector}" \u2014 not in the manifest (${operations.size} known); regenerate the typed operation reference`);
185
+ }
186
+ }
187
+ function assertReferenceKind({ op, kind }) {
188
+ const declared = referenceKind(op);
189
+ if (declared && kind !== declared) throw new OrmClientError("operation kind differs from the typed reference");
190
+ }
191
+ function selectOperationTarget({ op, operations, selection = "name", readReceipt = false }) {
192
+ if (selection !== "name") throw new OrmClientError("ORM calls use operation names; hash selection is no longer supported");
193
+ const selector = selectorForReference(op);
194
+ if (selector === BUILTIN_SQL_READ_HASH || selector === BUILTIN_SQL_READ_NAME) {
195
+ return { op: `query:${BUILTIN_SQL_READ_NAME}`, expectedKind: "query" };
196
+ }
197
+ const match = manifestEntry({ selector, operations });
198
+ const name = match?.[0] ?? selector;
199
+ const kind = match?.[1].kind ?? referenceKind(op);
200
+ assertKnownName({ name, known: operations.size === 0 || match !== void 0, operations, selector });
201
+ assertReferenceKind({ op, kind });
202
+ if (readReceipt && kind !== "query") throw new OrmClientError("read receipts require a registered query or the built-in SQL read");
203
+ const guarded = kind ? `${kind}:${name}` : name;
204
+ return { op: guarded, ...kind ? { expectedKind: kind } : {} };
205
+ }
206
+
162
207
  // src/client/response.ts
163
208
  function isRecord(value) {
164
209
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -206,9 +251,6 @@ function readOperationResponseWithReceipt({
206
251
  return { data, sourceGeneration };
207
252
  }
208
253
 
209
- // src/client/sql.ts
210
- var BUILTIN_SQL_READ_HASH = "sha256:a50c477c952a5e0fe68ed158a4530e4aab573c09bcbb1a8ac454dc88a39a6258";
211
-
212
254
  // src/client/operations.ts
213
255
  function validateIdempotencyKey(key) {
214
256
  if (key !== void 0 && !/^[A-Za-z0-9._:-]{1,128}$/.test(key)) {
@@ -221,38 +263,11 @@ function validateExpectedSourceGeneration(value) {
221
263
  }
222
264
  }
223
265
  var dataPlanePath = (namespace) => `/_data/v2/${namespace}`;
224
- function resolveOpHash(manifest, op) {
225
- if (op.startsWith("sha256:")) return op;
226
- const entry = manifest.operations[op];
227
- if (!entry) {
228
- const known = Object.keys(manifest.operations).sort();
229
- throw new OrmClientError(
230
- `unknown operation "${op}" \u2014 not in the manifest (${known.length} known). Re-run \`seq-studio orm generate\` after editing graphql documents.`
231
- );
232
- }
233
- return entry.hash;
234
- }
235
- function createReadReceiptOperationResolver({ operations }) {
236
- const hashesByName = /* @__PURE__ */ new Map();
237
- const readHashes = /* @__PURE__ */ new Set([BUILTIN_SQL_READ_HASH]);
238
- const mutationHashes = /* @__PURE__ */ new Set();
239
- for (const [name, entry] of operations) {
240
- hashesByName.set(name, entry.hash);
241
- if (entry.kind === "query" && /^sha256:[a-f0-9]{64}$/.test(entry.hash)) readHashes.add(entry.hash);
242
- if (entry.kind === "mutation") mutationHashes.add(entry.hash);
243
- }
244
- return ({ selector, hashOnly = false }) => {
245
- const hash = selector.startsWith("sha256:") ? selector : hashOnly ? void 0 : hashesByName.get(selector);
246
- if (!hash || !readHashes.has(hash) || mutationHashes.has(hash)) {
247
- throw new OrmClientError("read receipts require a registered query or the built-in SQL read");
248
- }
249
- return hash;
250
- };
251
- }
252
266
  function createOperationExecutor({
253
267
  baseUrl,
254
268
  namespace,
255
- manifest = { schemaHash: "builtin", operations: {} },
269
+ manifest = { operations: {} },
270
+ operationSelection = "name",
256
271
  getToken,
257
272
  getDataToken,
258
273
  fetchImpl = globalThis.fetch
@@ -262,12 +277,12 @@ function createOperationExecutor({
262
277
  throw new OrmClientError("provide exactly one of getToken (bearer) or getDataToken (delegated)");
263
278
  }
264
279
  const root = baseUrl.replace(/\/+$/, "");
265
- const resolveReceiptOperation = createReadReceiptOperationResolver({ operations: Object.entries(manifest.operations) });
280
+ const operations = new Map(Object.entries(manifest.operations).map(([name, entry]) => [name, { ...entry }]));
266
281
  async function request({ op, variables, options, requireReadReceipt = false }) {
267
282
  validateIdempotencyKey(options.idempotencyKey);
268
283
  validateExpectedSourceGeneration(options.expectedSourceGeneration);
269
284
  if (typeof op !== "string" && op.namespace !== namespace) throw new OrmClientError("operation belongs to a different namespace");
270
- const hash = requireReadReceipt ? resolveReceiptOperation({ selector: typeof op === "string" ? op : op.hash, hashOnly: typeof op !== "string" }) : typeof op === "string" ? resolveOpHash(manifest, op) : op.hash;
285
+ const target = selectOperationTarget({ op, operations, selection: operationSelection, readReceipt: requireReadReceipt });
271
286
  const token = await (getDataToken ?? getToken)();
272
287
  if (!token) throw new OrmClientError("not authenticated \u2014 no token available");
273
288
  const auth = getDataToken ? { [ORM_DATA_TOKEN_HEADER]: token } : { Authorization: `Bearer ${token}` };
@@ -275,7 +290,7 @@ function createOperationExecutor({
275
290
  method: "POST",
276
291
  headers: { ...auth, "Content-Type": "application/json" },
277
292
  body: JSON.stringify({
278
- op: hash,
293
+ ...target,
279
294
  variables,
280
295
  idempotencyKey: options.idempotencyKey,
281
296
  expectedSourceGeneration: options.expectedSourceGeneration
@@ -340,7 +355,7 @@ function createOrmFetch({
340
355
  "createOrmFetch requires named operations (Apollo sends operationName for named documents)"
341
356
  );
342
357
  }
343
- const hash = resolveOpHash(manifest, name);
358
+ const target = selectOperationTarget({ op: name, operations: new Map(Object.entries(manifest.operations)) });
344
359
  const idempotencyKey = new Headers(init?.headers).get("Idempotency-Key") ?? void 0;
345
360
  validateIdempotencyKey(idempotencyKey);
346
361
  const token = await (getDataToken ?? getToken)();
@@ -349,7 +364,7 @@ function createOrmFetch({
349
364
  return fetchImpl(url, {
350
365
  method: "POST",
351
366
  headers: { ...auth, "Content-Type": "application/json" },
352
- body: JSON.stringify({ op: hash, variables: parsed.variables ?? {}, idempotencyKey }),
367
+ body: JSON.stringify({ ...target, variables: parsed.variables ?? {}, idempotencyKey }),
353
368
  ...init?.signal ? { signal: init.signal } : {}
354
369
  });
355
370
  };
@@ -357,57 +372,37 @@ function createOrmFetch({
357
372
 
358
373
  // src/client/transport-executor.ts
359
374
  var operationHash = /^sha256:[a-f0-9]{64}$/;
360
- var operationName = /^[_A-Za-z][_0-9A-Za-z]{0,254}$/;
361
- function refusedAsUnknownSelector(response) {
362
- if (response.status !== 404 || !isRecord(response.body) || !Array.isArray(response.body.errors)) return false;
363
- const first = response.body.errors[0];
364
- const extensions = isRecord(first) && isRecord(first.extensions) ? first.extensions : void 0;
365
- return extensions?.code === "NOT_FOUND" && !(isRecord(extensions.details) && extensions.details.cause === "unknown_operation") && isRecord(first) && typeof first.message === "string" && first.message.startsWith("operation not found");
366
- }
367
- function readManifestHashes(manifest) {
368
- if (!isRecord(manifest) || typeof manifest.schemaHash !== "string" || !manifest.schemaHash || !isRecord(manifest.operations)) {
375
+ function readManifestOperations(manifest) {
376
+ if (!isRecord(manifest) || !isRecord(manifest.operations)) {
369
377
  throw new OrmClientError("invalid operations manifest \u2014 use operations.manifest.json from seq-studio orm generate");
370
378
  }
371
- const hashes = /* @__PURE__ */ new Map();
379
+ const operations = /* @__PURE__ */ new Map();
372
380
  for (const [name, entry] of Object.entries(manifest.operations)) {
373
- if (!/^[_A-Za-z][_0-9A-Za-z]*$/.test(name) || !isRecord(entry) || typeof entry.hash !== "string" || !operationHash.test(entry.hash) || entry.kind !== "query" && entry.kind !== "mutation") {
381
+ if (!/^[_A-Za-z][_0-9A-Za-z]*$/.test(name) || !isRecord(entry) || entry.hash !== void 0 && (typeof entry.hash !== "string" || !operationHash.test(entry.hash)) || entry.kind !== "query" && entry.kind !== "mutation") {
374
382
  throw new OrmClientError(`invalid operations manifest entry "${name}" \u2014 regenerate the manifest`);
375
383
  }
376
- hashes.set(name, { hash: entry.hash, kind: entry.kind });
384
+ operations.set(name, { ...typeof entry.hash === "string" ? { hash: entry.hash } : {}, kind: entry.kind });
377
385
  }
378
- return hashes;
386
+ return operations;
379
387
  }
380
- function createOperationExecutorWithTransport({ namespace, manifest, transport, operationSelection = "hash" }) {
381
- if (operationSelection !== "hash" && operationSelection !== "name") throw new OrmClientError("operationSelection must be 'hash' or 'name'");
388
+ function createOperationExecutorWithTransport({ namespace, manifest, transport, operationSelection = "name" }) {
389
+ if (operationSelection !== "name") throw new OrmClientError("ORM calls use operation names; hash selection is no longer supported");
382
390
  if (typeof namespace !== "string" || !NAMESPACE_PATTERN.test(namespace)) throw new OrmClientError("invalid ORM namespace \u2014 expected a lowercase identifier of at most 41 characters");
383
- const hashes = manifest === void 0 ? /* @__PURE__ */ new Map() : readManifestHashes(manifest);
384
- const knownHashes = new Set([...hashes.values()].map((entry) => entry.hash));
385
- const resolveReceiptOperation = createReadReceiptOperationResolver({ operations: hashes });
386
- function selectTarget({ op, requireReadReceipt }) {
387
- const selector = typeof op === "string" ? op : op.hash;
388
- if (operationSelection === "name" && !requireReadReceipt && typeof op === "string" && operationName.test(op)) {
389
- return { target: op, byName: true };
390
- }
391
- const hash = requireReadReceipt ? resolveReceiptOperation({ selector, hashOnly: typeof op !== "string" }) : selector === BUILTIN_SQL_READ_HASH ? selector : hashes.get(selector)?.hash ?? (knownHashes.has(selector) ? selector : void 0);
392
- if (!hash) throw new OrmClientError(`unknown operation "${String(op)}" \u2014 not in the manifest (${hashes.size} known). Re-run seq-studio orm generate.`);
393
- return { target: hash, byName: false };
394
- }
391
+ const operations = manifest === void 0 ? /* @__PURE__ */ new Map() : readManifestOperations(manifest);
395
392
  async function request({ op, variables, options, requireReadReceipt = false }) {
396
393
  validateIdempotencyKey(options.idempotencyKey);
397
394
  validateExpectedSourceGeneration(options.expectedSourceGeneration);
398
395
  if (typeof op !== "string" && op.namespace !== namespace) throw new OrmClientError("operation belongs to a different namespace");
399
- const { target: hash, byName } = selectTarget({ op, requireReadReceipt });
396
+ const target = selectOperationTarget({ op, operations, selection: operationSelection, readReceipt: requireReadReceipt });
400
397
  if (!isRecord(variables)) throw new OrmClientError("operation variables must be an object");
401
- const send = (target) => transport({
398
+ const send = () => transport({
402
399
  namespace,
403
- op: target,
400
+ ...target,
404
401
  variables,
405
402
  ...options.idempotencyKey === void 0 ? {} : { idempotencyKey: options.idempotencyKey },
406
403
  ...options.expectedSourceGeneration === void 0 ? {} : { expectedSourceGeneration: options.expectedSourceGeneration }
407
404
  });
408
- let response = await send(hash);
409
- const fallback = byName && typeof op === "string" ? hashes.get(op)?.hash : void 0;
410
- if (fallback && response && refusedAsUnknownSelector(response)) response = await send(fallback);
405
+ const response = await send();
411
406
  if (!response || typeof response.ok !== "boolean" || !Number.isInteger(response.status) || response.status < 100 || response.status > 599 || response.ok !== (response.status >= 200 && response.status < 300)) {
412
407
  throw new OrmOperationError("malformed transport response", null, null);
413
408
  }
@@ -493,6 +488,6 @@ function requireOption(value, name) {
493
488
  return value;
494
489
  }
495
490
 
496
- export { BUILTIN_SQL_READ_HASH, NAMESPACE_PATTERN, ORM_DATA_TOKEN_HEADER, ORM_SERVICE_DATA_TOKEN_HEADER, OrmClientError, OrmOperationError, TableQuery, configureOrmOperations, createFetchTransport, createOperationExecutor, createOperationExecutorWithTransport, createOrmClient, createOrmFetch, createServiceOrmClient, executeOperation };
491
+ export { BUILTIN_SQL_READ_HASH, BUILTIN_SQL_READ_NAME, NAMESPACE_PATTERN, ORM_DATA_TOKEN_HEADER, ORM_SERVICE_DATA_TOKEN_HEADER, OrmClientError, OrmOperationError, TableQuery, configureOrmOperations, createFetchTransport, createOperationExecutor, createOperationExecutorWithTransport, createOrmClient, createOrmFetch, createServiceOrmClient, executeOperation };
497
492
  //# sourceMappingURL=client.js.map
498
493
  //# sourceMappingURL=client.js.map