@burojs/hasura 0.4.0 → 0.5.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.
package/dist/index.d.cts CHANGED
@@ -28,22 +28,16 @@ interface HasuraDataProviderConfig {
28
28
  * with a newly obtained token, while false preserves the original 401
29
29
  * response.
30
30
  *
31
- * ⚠️ KNOWN GAP, stated here because this is where a consumer reads: HTTP 401
32
- * is NOT how the Hasura deployment this provider was distilled from rejects
33
- * a credential. The one capture in this repository of a real rejection
34
- * (`packages/mock-kit/fixtures/hasura/error-unauthorized.json`, taken from
35
- * the live backend with a deliberately malformed bearer token) came back
36
- * **HTTP 200** with an `invalid-jwt` errors envelope. Replayed through this
37
- * provider it surfaces as `{ kind: 'protocol', code: 'graphql-error' }` and
38
- * `recoverAuth` is never consulted — no refresh, no retry, and app logic
39
- * keyed on `kind: 'auth'` never fires either. Pinned by
40
- * `tests/fixture-fidelity.test.ts`'s `error-unauthorized` case.
41
- *
42
- * So this callback fires only for a deployment that really answers 401 (a
43
- * proxy or gateway in front of Hasura, typically). Keying recovery on the
44
- * error envelope instead is a product decision, deliberately not taken here;
45
- * the existing 401 tests use a FABRICATED 401 and must not be read as proof
46
- * that recovery works against Hasura itself.
31
+ * HTTP 401 is what a proxy or gateway in front of Hasura answers. Hasura
32
+ * itself rejects a credential with **HTTP 200** and an `invalid-jwt` errors
33
+ * envelope (`packages/mock-kit/fixtures/hasura/error-unauthorized.json`,
34
+ * captured from a live backend). This provider reports that envelope as
35
+ * `{ kind: 'auth', code: 'invalid-jwt' }`. When the app has an
36
+ * `authProvider`, the runtime hands it that error; if the provider chooses
37
+ * to refresh, a read is replayed once, and a mutation once when it is
38
+ * replay-safe. `recoverAuth` is
39
+ * not consulted for the envelope, so one rejection is never refreshed twice.
40
+ * Pinned by `tests/fixture-fidelity.test.ts`'s `error-unauthorized` case.
47
41
  */
48
42
  recoverAuth?: () => Promise<boolean>;
49
43
  /** Map our resource name → table + field selection. */
@@ -397,6 +391,31 @@ declare function flattenJsonbSpill(item: unknown, spill: JsonbSpillConfig): unkn
397
391
  * stable symbol.
398
392
  */
399
393
  declare const NOT_AUTHENTICATED_CODE = "not-authenticated";
394
+ /**
395
+ * The envelope codes with which Hasura reports a failure of work it ran OUTSIDE its own
396
+ * transaction — an Action's webhook or a remote schema — on a custom mutation. Such a side effect
397
+ * may have happened before the failure, so a custom mutation answered with one of them is
398
+ * `sent` (spec 4.7, P4-20). A table mutation keeps `protocol/graphql-error` for them: Hasura
399
+ * rolled its transaction back.
400
+ *
401
+ * Spellings confirmed against the Hasura GraphQL Engine v2 source, `instance ToJSON Code` in
402
+ * `server/lib/hasura-base/src/Hasura/Base/Error.hs` (hasura/graphql-engine@0a1dd53b):
403
+ * `Unexpected -> "unexpected"`, `RemoteSchemaError -> "remote-schema-error"`,
404
+ * `ParseFailed -> "parse-failed"`. Action failures are raised in
405
+ * `server/src-lib/Hasura/GraphQL/Execute/Action.hs`: an HTTP exception calling the webhook, a
406
+ * webhook 5xx, an unparsable webhook answer and a failed request or response transform are all
407
+ * `throw500…`, i.e. `unexpected`; a webhook that answered 2xx (its side effect done) with JSON
408
+ * that does not decode fails in `decodeValue` (`Action.hs:793`), which raises `ParseFailed`
409
+ * through `liftIResult` (`Error.hs:424`), i.e. `parse-failed`. Hasura has no
410
+ * `action-webhook-error` or `http-exception` code; a webhook's own 4xx answer carries the code
411
+ * the webhook chose (`ActionWebhookCode`), or `unexpected` when it chose none, and only that
412
+ * last case is caught here — a webhook-chosen code is the handler's own definite answer.
413
+ *
414
+ * Hasura gives no marker telling an Action-backed or remote-schema mutation apart from any
415
+ * other registered `operations` document, so every custom mutation is treated this way
416
+ * (fail-safe: a wrongly `sent` answer costs a "may have been applied" screen, never a duplicate).
417
+ */
418
+ declare const HASURA_EXTERNAL_FAILURE_CODES: ReadonlySet<string>;
400
419
  /**
401
420
  * Refusal code for "this mapping declares a `localeField` but the descriptor
402
421
  * carries no locale". Exported so an application can match a symbol rather
@@ -752,5 +771,5 @@ declare function hasuraWsUrl(endpoint: string): string;
752
771
  */
753
772
  declare function createHasuraLiveProvider(config: HasuraLiveProviderConfig): DataLiveProvider;
754
773
  //#endregion
755
- export { type CursorOrderingColumn, DEFAULT_HASURA_ENDPOINT, type DataBodyConfig, FILTER_OPERATOR_UNSUPPORTED_CODE, HASURA_CURSOR_CODES, type HasuraCustomOperation, type HasuraDataProviderConfig, type HasuraLiveProviderConfig, type HasuraOperationRegistry, type JsonbSpillConfig, LOCALE_REQUIRED_CODE, NOT_AUTHENTICATED_CODE, type ResourceMapping, aggregateRoot, assertCursorLimit, assertCursorOrderable, byPkRoot, coerceInt64Filter, createHasuraDataProvider, createHasuraLiveProvider, decodeCursor, effectiveCursorOrdering, encodeCursor, filtersToWhere, flattenJsonbSpill, hasuraWsUrl, keysetWhere, localeWhere, mergeWhere, orderingSignature, partitionDataBody, partitionJsonbSpill, scopeToWhere };
774
+ export { type CursorOrderingColumn, DEFAULT_HASURA_ENDPOINT, type DataBodyConfig, FILTER_OPERATOR_UNSUPPORTED_CODE, HASURA_CURSOR_CODES, HASURA_EXTERNAL_FAILURE_CODES, type HasuraCustomOperation, type HasuraDataProviderConfig, type HasuraLiveProviderConfig, type HasuraOperationRegistry, type JsonbSpillConfig, LOCALE_REQUIRED_CODE, NOT_AUTHENTICATED_CODE, type ResourceMapping, aggregateRoot, assertCursorLimit, assertCursorOrderable, byPkRoot, coerceInt64Filter, createHasuraDataProvider, createHasuraLiveProvider, decodeCursor, effectiveCursorOrdering, encodeCursor, filtersToWhere, flattenJsonbSpill, hasuraWsUrl, keysetWhere, localeWhere, mergeWhere, orderingSignature, partitionDataBody, partitionJsonbSpill, scopeToWhere };
756
775
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -28,22 +28,16 @@ interface HasuraDataProviderConfig {
28
28
  * with a newly obtained token, while false preserves the original 401
29
29
  * response.
30
30
  *
31
- * ⚠️ KNOWN GAP, stated here because this is where a consumer reads: HTTP 401
32
- * is NOT how the Hasura deployment this provider was distilled from rejects
33
- * a credential. The one capture in this repository of a real rejection
34
- * (`packages/mock-kit/fixtures/hasura/error-unauthorized.json`, taken from
35
- * the live backend with a deliberately malformed bearer token) came back
36
- * **HTTP 200** with an `invalid-jwt` errors envelope. Replayed through this
37
- * provider it surfaces as `{ kind: 'protocol', code: 'graphql-error' }` and
38
- * `recoverAuth` is never consulted — no refresh, no retry, and app logic
39
- * keyed on `kind: 'auth'` never fires either. Pinned by
40
- * `tests/fixture-fidelity.test.ts`'s `error-unauthorized` case.
41
- *
42
- * So this callback fires only for a deployment that really answers 401 (a
43
- * proxy or gateway in front of Hasura, typically). Keying recovery on the
44
- * error envelope instead is a product decision, deliberately not taken here;
45
- * the existing 401 tests use a FABRICATED 401 and must not be read as proof
46
- * that recovery works against Hasura itself.
31
+ * HTTP 401 is what a proxy or gateway in front of Hasura answers. Hasura
32
+ * itself rejects a credential with **HTTP 200** and an `invalid-jwt` errors
33
+ * envelope (`packages/mock-kit/fixtures/hasura/error-unauthorized.json`,
34
+ * captured from a live backend). This provider reports that envelope as
35
+ * `{ kind: 'auth', code: 'invalid-jwt' }`. When the app has an
36
+ * `authProvider`, the runtime hands it that error; if the provider chooses
37
+ * to refresh, a read is replayed once, and a mutation once when it is
38
+ * replay-safe. `recoverAuth` is
39
+ * not consulted for the envelope, so one rejection is never refreshed twice.
40
+ * Pinned by `tests/fixture-fidelity.test.ts`'s `error-unauthorized` case.
47
41
  */
48
42
  recoverAuth?: () => Promise<boolean>;
49
43
  /** Map our resource name → table + field selection. */
@@ -397,6 +391,31 @@ declare function flattenJsonbSpill(item: unknown, spill: JsonbSpillConfig): unkn
397
391
  * stable symbol.
398
392
  */
399
393
  declare const NOT_AUTHENTICATED_CODE = "not-authenticated";
394
+ /**
395
+ * The envelope codes with which Hasura reports a failure of work it ran OUTSIDE its own
396
+ * transaction — an Action's webhook or a remote schema — on a custom mutation. Such a side effect
397
+ * may have happened before the failure, so a custom mutation answered with one of them is
398
+ * `sent` (spec 4.7, P4-20). A table mutation keeps `protocol/graphql-error` for them: Hasura
399
+ * rolled its transaction back.
400
+ *
401
+ * Spellings confirmed against the Hasura GraphQL Engine v2 source, `instance ToJSON Code` in
402
+ * `server/lib/hasura-base/src/Hasura/Base/Error.hs` (hasura/graphql-engine@0a1dd53b):
403
+ * `Unexpected -> "unexpected"`, `RemoteSchemaError -> "remote-schema-error"`,
404
+ * `ParseFailed -> "parse-failed"`. Action failures are raised in
405
+ * `server/src-lib/Hasura/GraphQL/Execute/Action.hs`: an HTTP exception calling the webhook, a
406
+ * webhook 5xx, an unparsable webhook answer and a failed request or response transform are all
407
+ * `throw500…`, i.e. `unexpected`; a webhook that answered 2xx (its side effect done) with JSON
408
+ * that does not decode fails in `decodeValue` (`Action.hs:793`), which raises `ParseFailed`
409
+ * through `liftIResult` (`Error.hs:424`), i.e. `parse-failed`. Hasura has no
410
+ * `action-webhook-error` or `http-exception` code; a webhook's own 4xx answer carries the code
411
+ * the webhook chose (`ActionWebhookCode`), or `unexpected` when it chose none, and only that
412
+ * last case is caught here — a webhook-chosen code is the handler's own definite answer.
413
+ *
414
+ * Hasura gives no marker telling an Action-backed or remote-schema mutation apart from any
415
+ * other registered `operations` document, so every custom mutation is treated this way
416
+ * (fail-safe: a wrongly `sent` answer costs a "may have been applied" screen, never a duplicate).
417
+ */
418
+ declare const HASURA_EXTERNAL_FAILURE_CODES: ReadonlySet<string>;
400
419
  /**
401
420
  * Refusal code for "this mapping declares a `localeField` but the descriptor
402
421
  * carries no locale". Exported so an application can match a symbol rather
@@ -752,5 +771,5 @@ declare function hasuraWsUrl(endpoint: string): string;
752
771
  */
753
772
  declare function createHasuraLiveProvider(config: HasuraLiveProviderConfig): DataLiveProvider;
754
773
  //#endregion
755
- export { type CursorOrderingColumn, DEFAULT_HASURA_ENDPOINT, type DataBodyConfig, FILTER_OPERATOR_UNSUPPORTED_CODE, HASURA_CURSOR_CODES, type HasuraCustomOperation, type HasuraDataProviderConfig, type HasuraLiveProviderConfig, type HasuraOperationRegistry, type JsonbSpillConfig, LOCALE_REQUIRED_CODE, NOT_AUTHENTICATED_CODE, type ResourceMapping, aggregateRoot, assertCursorLimit, assertCursorOrderable, byPkRoot, coerceInt64Filter, createHasuraDataProvider, createHasuraLiveProvider, decodeCursor, effectiveCursorOrdering, encodeCursor, filtersToWhere, flattenJsonbSpill, hasuraWsUrl, keysetWhere, localeWhere, mergeWhere, orderingSignature, partitionDataBody, partitionJsonbSpill, scopeToWhere };
774
+ export { type CursorOrderingColumn, DEFAULT_HASURA_ENDPOINT, type DataBodyConfig, FILTER_OPERATOR_UNSUPPORTED_CODE, HASURA_CURSOR_CODES, HASURA_EXTERNAL_FAILURE_CODES, type HasuraCustomOperation, type HasuraDataProviderConfig, type HasuraLiveProviderConfig, type HasuraOperationRegistry, type JsonbSpillConfig, LOCALE_REQUIRED_CODE, NOT_AUTHENTICATED_CODE, type ResourceMapping, aggregateRoot, assertCursorLimit, assertCursorOrderable, byPkRoot, coerceInt64Filter, createHasuraDataProvider, createHasuraLiveProvider, decodeCursor, effectiveCursorOrdering, encodeCursor, filtersToWhere, flattenJsonbSpill, hasuraWsUrl, keysetWhere, localeWhere, mergeWhere, orderingSignature, partitionDataBody, partitionJsonbSpill, scopeToWhere };
756
775
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -342,6 +342,63 @@ function flattenJsonbSpill(item, spill) {
342
342
  return out;
343
343
  }
344
344
  const NOT_AUTHENTICATED_CODE = "not-authenticated";
345
+ const FORBIDDEN_CODES = new Set(["access-denied", "permission-error"]);
346
+ const HASURA_EXTERNAL_FAILURE_CODES = new Set([
347
+ "unexpected",
348
+ "remote-schema-error",
349
+ "parse-failed"
350
+ ]);
351
+ const MUTATION_REFUSAL_CODES = new Map([["constraint-violation", "conflict"], ["validation-failed", "validation"]]);
352
+ function graphqlError(errors, operation, external) {
353
+ const message = errors.map((e) => e.message).join("; ");
354
+ const codes = errors.flatMap((e) => typeof e.extensions?.code === "string" ? [e.extensions.code] : []);
355
+ if (codes.includes("invalid-jwt")) return {
356
+ kind: "auth",
357
+ code: "invalid-jwt",
358
+ message,
359
+ details: errors
360
+ };
361
+ const outside = operation === "mutation" && external ? codes.find((code) => HASURA_EXTERNAL_FAILURE_CODES.has(code) || MUTATION_REFUSAL_CODES.has(code) || FORBIDDEN_CODES.has(code)) : void 0;
362
+ if (outside !== void 0) return {
363
+ kind: "sent",
364
+ code: outside,
365
+ message,
366
+ retryable: false,
367
+ details: errors
368
+ };
369
+ const forbidden = codes.find((code) => FORBIDDEN_CODES.has(code));
370
+ if (forbidden !== void 0) return {
371
+ kind: "forbidden",
372
+ code: forbidden,
373
+ message,
374
+ details: errors
375
+ };
376
+ if (operation === "mutation") for (const code of codes) {
377
+ const kind = MUTATION_REFUSAL_CODES.get(code);
378
+ if (kind !== void 0) return {
379
+ kind,
380
+ code,
381
+ message,
382
+ details: errors
383
+ };
384
+ }
385
+ return {
386
+ kind: "protocol",
387
+ code: "graphql-error",
388
+ message,
389
+ details: errors
390
+ };
391
+ }
392
+ function answerLost(code, message, status, cause) {
393
+ return {
394
+ kind: "sent",
395
+ code,
396
+ message,
397
+ status,
398
+ retryable: false,
399
+ ...cause === void 0 ? {} : { cause }
400
+ };
401
+ }
345
402
  const LOCALE_REQUIRED_CODE = "locale-required";
346
403
  function localeWhere(m, locale) {
347
404
  if (m.localeField === void 0) return void 0;
@@ -498,8 +555,12 @@ function createHasuraDataProvider(config) {
498
555
  const operations = snapshotOperationRegistry(config.operations);
499
556
  const hasCustomQueries = hasRegisteredOperationKind(operations, "query");
500
557
  const hasCustomMutations = hasRegisteredOperationKind(operations, "mutation");
501
- async function gql(query, variables, role, signal) {
558
+ async function gql(query, variables, role, signal, operation, external = false) {
502
559
  try {
560
+ const requestBody = JSON.stringify({
561
+ query,
562
+ variables
563
+ });
503
564
  const request = async (token) => {
504
565
  const headers = {
505
566
  "Content-Type": "application/json",
@@ -507,15 +568,24 @@ function createHasuraDataProvider(config) {
507
568
  };
508
569
  const effectiveRole = role === void 0 ? defaultRole : normalizeRole(role);
509
570
  if (effectiveRole !== null) headers["X-Hasura-Role"] = effectiveRole;
510
- return (config.fetchImpl ?? fetch)(endpoint, {
511
- method: "POST",
512
- headers,
513
- body: JSON.stringify({
514
- query,
515
- variables
516
- }),
517
- signal
518
- });
571
+ const fetchImpl = config.fetchImpl ?? fetch;
572
+ try {
573
+ return await fetchImpl(endpoint, {
574
+ method: "POST",
575
+ headers,
576
+ body: requestBody,
577
+ signal
578
+ });
579
+ } catch (cause) {
580
+ if (operation === "mutation" && !signal.aborted) throw {
581
+ kind: "sent",
582
+ code: "hasura-request-sent",
583
+ message: "Hasura did not answer a mutation; it may have been applied.",
584
+ retryable: false,
585
+ cause
586
+ };
587
+ throw cause;
588
+ }
519
589
  };
520
590
  let token = await config.getToken();
521
591
  if (!token) throw {
@@ -533,24 +603,32 @@ function createHasuraDataProvider(config) {
533
603
  };
534
604
  res = await request(token);
535
605
  }
536
- if (!res.ok) throw {
537
- kind: "transport",
538
- code: "graphql-http-error",
539
- message: `GraphQL HTTP ${res.status}`,
540
- status: res.status
541
- };
542
- const body = await res.json();
543
- if (body.errors?.length) throw {
544
- kind: "protocol",
545
- code: "graphql-error",
546
- message: body.errors.map((e) => e.message).join("; "),
547
- details: body.errors
548
- };
549
- if (body.data === void 0) throw {
550
- kind: "protocol",
551
- code: "empty-graphql-response",
552
- message: "Empty GraphQL response."
553
- };
606
+ if (!res.ok) {
607
+ if (operation === "mutation" && res.status >= 500) throw answerLost("hasura-answer-lost", `GraphQL HTTP ${res.status} after a mutation was sent; it may have been applied.`, res.status);
608
+ throw {
609
+ kind: "transport",
610
+ code: "graphql-http-error",
611
+ message: `GraphQL HTTP ${res.status}`,
612
+ status: res.status
613
+ };
614
+ }
615
+ let body;
616
+ try {
617
+ body = await res.json();
618
+ if (body === null || typeof body !== "object") throw new TypeError("The GraphQL answer is not an object.");
619
+ } catch (cause) {
620
+ if (operation === "mutation" && !signal.aborted) throw answerLost("hasura-answer-unreadable", "Hasura answered a mutation with a body that could not be read; it may have been applied.", res.status, cause);
621
+ throw cause;
622
+ }
623
+ if (body.errors?.length) throw graphqlError(body.errors, operation, external);
624
+ if (body.data === void 0) {
625
+ if (operation === "mutation") throw answerLost("hasura-answer-unreadable", "Hasura answered a mutation without data or errors; it may have been applied.", res.status);
626
+ throw {
627
+ kind: "protocol",
628
+ code: "empty-graphql-response",
629
+ message: "Empty GraphQL response."
630
+ };
631
+ }
554
632
  return body.data;
555
633
  } catch (error) {
556
634
  throw hasuraError(error, signal, "Hasura request failed.");
@@ -576,8 +654,8 @@ function createHasuraDataProvider(config) {
576
654
  }
577
655
  async function executeCustomOperation(resource, operationName, input, kind, signal) {
578
656
  const operation = registeredOperation(resource, operationName, kind);
579
- const result = await gql(operation.document, operation.variables(input), operation.role ?? config.resources[resource]?.role, signal);
580
- return operation.mapResult?.(result) ?? result;
657
+ const result = await gql(operation.document, operation.variables(input), operation.role ?? config.resources[resource]?.role, signal, kind, kind === "mutation");
658
+ return operation.mapResult === void 0 ? result : operation.mapResult(result);
581
659
  }
582
660
  function composeListWhere(m, descriptor, context) {
583
661
  const userWhere = filtersToWhere(coerceInt64Filter(descriptor.filter, m.int64Fields));
@@ -596,7 +674,7 @@ function createHasuraDataProvider(config) {
596
674
  }`;
597
675
  const aggVars = {};
598
676
  if (where) aggVars.where = where;
599
- return (await gql(metaQuery, where ? aggVars : void 0, m.role, signal)).meta.aggregate.count;
677
+ return (await gql(metaQuery, where ? aggVars : void 0, m.role, signal, "query")).meta.aggregate.count;
600
678
  }
601
679
  async function upsertDataBody(db, parentId, body, role, signal) {
602
680
  await gql(`mutation UpsertDataBody($object: ${db.table}_insert_input!) {
@@ -607,11 +685,11 @@ function createHasuraDataProvider(config) {
607
685
  }`, { object: {
608
686
  [db.fk]: parentId,
609
687
  [db.column]: body
610
- } }, role, signal);
688
+ } }, role, signal, "mutation");
611
689
  }
612
690
  function mutationRecord(m, idField, item, resource, expectedId) {
613
691
  if (item === null || typeof item !== "object" || Array.isArray(item)) throw {
614
- kind: "protocol",
692
+ kind: "not-found",
615
693
  code: "record-not-found",
616
694
  message: `Not found: ${resource}`
617
695
  };
@@ -642,11 +720,11 @@ function createHasuraDataProvider(config) {
642
720
  const where = mergeWhere({ [pkField]: { _eq: id } }, m.fixedFilter);
643
721
  return (await gql(`query One_${m.table}($where: ${m.table}_bool_exp) {
644
722
  items: ${m.table}(where: $where, limit: 1) { ${fields} }
645
- }`, { where }, m.role, signal)).items?.[0] ?? null;
723
+ }`, { where }, m.role, signal, "query")).items?.[0] ?? null;
646
724
  }
647
725
  return (await gql(`query One_${m.table}($id: ${pkType}!) {
648
726
  item: ${root}(${pkField}: $id) { ${fields} }
649
- }`, { id }, m.role, signal)).item;
727
+ }`, { id }, m.role, signal, "query")).item;
650
728
  }
651
729
  async function listByCursor(m, descriptor, pagination, context) {
652
730
  if (pagination.before !== void 0) throw {
@@ -669,7 +747,7 @@ function createHasuraDataProvider(config) {
669
747
  }`;
670
748
  const itemsVars = { limit: pagination.limit + 1 };
671
749
  if (where) itemsVars.where = where;
672
- const fetched = (await gql(itemsQuery, itemsVars, m.role, context.signal)).items ?? [];
750
+ const fetched = (await gql(itemsQuery, itemsVars, m.role, context.signal, "query")).items ?? [];
673
751
  const hasNextPage = fetched.length > pagination.limit;
674
752
  const rows = hasNextPage ? fetched.slice(0, pagination.limit) : fetched;
675
753
  let total;
@@ -714,7 +792,7 @@ function createHasuraDataProvider(config) {
714
792
  offset
715
793
  };
716
794
  if (where) itemsVars.where = where;
717
- const itemsData = await gql(itemsQuery, itemsVars, m.role, context.signal);
795
+ const itemsData = await gql(itemsQuery, itemsVars, m.role, context.signal, "query");
718
796
  let total;
719
797
  const listAggRoot = aggregateRoot(m);
720
798
  if (!m.noAggregate && listAggRoot) try {
@@ -743,7 +821,7 @@ function createHasuraDataProvider(config) {
743
821
  const fields = m.selectFields.join(" ");
744
822
  const data = await gql(`query Many_${m.table}($where: ${m.table}_bool_exp) {
745
823
  items: ${m.table}(where: $where) { ${fields} }
746
- }`, { where }, m.role, context.signal);
824
+ }`, { where }, m.role, context.signal, "query");
747
825
  const spill = m.jsonbSpill;
748
826
  return { data: spill ? data.items.map((item) => flattenJsonbSpill(item, spill)) : data.items };
749
827
  },
@@ -760,12 +838,12 @@ function createHasuraDataProvider(config) {
760
838
  const where = mergeWhere(mergeWhere({ [pkField]: { _eq: descriptor.id } }, m.fixedFilter), localeSlice);
761
839
  item = (await gql(`query One_${m.table}($where: ${m.table}_bool_exp) {
762
840
  items: ${m.table}(where: $where, limit: 1) { ${fields} }
763
- }`, { where }, m.role, context.signal)).items?.[0] ?? null;
841
+ }`, { where }, m.role, context.signal, "query")).items?.[0] ?? null;
764
842
  } else item = (await gql(`query One_${m.table}($id: ${pkType}!) {
765
843
  item: ${root}(${pkField}: $id) { ${fields} }
766
- }`, { id: descriptor.id }, m.role, context.signal)).item;
844
+ }`, { id: descriptor.id }, m.role, context.signal, "query")).item;
767
845
  if (item == null) throw {
768
- kind: "protocol",
846
+ kind: "not-found",
769
847
  code: "record-not-found",
770
848
  message: `Not found: ${descriptor.resource}/${descriptor.id}`
771
849
  };
@@ -801,7 +879,7 @@ function createHasuraDataProvider(config) {
801
879
  const object = m.jsonbSpill ? partitionJsonbSpill(mainInput, m.jsonbSpill, m.selectFields) : mainInput;
802
880
  const data = await gql(`mutation Create_${m.table}($object: ${m.table}_insert_input!) {
803
881
  item: insert_${m.table}_one(object: $object) { ${fields} }
804
- }`, { object }, m.role, context.signal);
882
+ }`, { object }, m.role, context.signal, "mutation");
805
883
  const result = mutationRecord(m, descriptor.idField, data.item, descriptor.resource);
806
884
  if (m.dataBody && dataBody) await upsertDataBody(m.dataBody, result.id, dataBody, m.role, context.signal);
807
885
  return result;
@@ -830,7 +908,7 @@ function createHasuraDataProvider(config) {
830
908
  }`, {
831
909
  where,
832
910
  set
833
- }, m.role, context.signal);
911
+ }, m.role, context.signal, "mutation");
834
912
  if (ifUpdatedAt != null && ((data.result.affected_rows ?? 0) === 0 || (data.result.returning?.length ?? 0) === 0)) throw {
835
913
  kind: "conflict",
836
914
  code: "stale-record",
@@ -844,7 +922,7 @@ function createHasuraDataProvider(config) {
844
922
  }`, {
845
923
  id: descriptor.id,
846
924
  set
847
- }, m.role, context.signal)).item;
925
+ }, m.role, context.signal, "mutation")).item;
848
926
  }
849
927
  const result = mutationRecord(m, descriptor.idField, item, descriptor.resource, descriptor.id);
850
928
  if (m.dataBody && dataBody) await upsertDataBody(m.dataBody, result.id, dataBody, m.role, context.signal);
@@ -859,12 +937,12 @@ function createHasuraDataProvider(config) {
859
937
  const where = mergeWhere({ [pkField]: { _eq: descriptor.id } }, m.fixedFilter);
860
938
  item = (await gql(`mutation Delete_${m.table}($where: ${m.table}_bool_exp!) {
861
939
  result: delete_${m.table}(where: $where) { affected_rows returning { ${fields} } }
862
- }`, { where }, m.role, context.signal)).result.returning?.[0] ?? null;
940
+ }`, { where }, m.role, context.signal, "mutation")).result.returning?.[0] ?? null;
863
941
  } else {
864
942
  const pkType = m.pkType ?? "bigint";
865
943
  item = (await gql(`mutation Delete_${m.table}($id: ${pkType}!) {
866
944
  item: delete_${m.table}_by_pk(${pkField}: $id) { ${fields} }
867
- }`, { id: descriptor.id }, m.role, context.signal)).item;
945
+ }`, { id: descriptor.id }, m.role, context.signal, "mutation")).item;
868
946
  }
869
947
  mutationRecord(m, descriptor.idField, item, descriptor.resource, descriptor.id);
870
948
  return {
@@ -885,6 +963,6 @@ function createHasuraDataProvider(config) {
885
963
  });
886
964
  }
887
965
  //#endregion
888
- export { DEFAULT_HASURA_ENDPOINT, FILTER_OPERATOR_UNSUPPORTED_CODE, HASURA_CURSOR_CODES, LOCALE_REQUIRED_CODE, NOT_AUTHENTICATED_CODE, aggregateRoot, assertCursorLimit, assertCursorOrderable, byPkRoot, coerceInt64Filter, createHasuraDataProvider, createHasuraLiveProvider, decodeCursor, effectiveCursorOrdering, encodeCursor, filtersToWhere, flattenJsonbSpill, hasuraWsUrl, keysetWhere, localeWhere, mergeWhere, orderingSignature, partitionDataBody, partitionJsonbSpill, scopeToWhere };
966
+ export { DEFAULT_HASURA_ENDPOINT, FILTER_OPERATOR_UNSUPPORTED_CODE, HASURA_CURSOR_CODES, HASURA_EXTERNAL_FAILURE_CODES, LOCALE_REQUIRED_CODE, NOT_AUTHENTICATED_CODE, aggregateRoot, assertCursorLimit, assertCursorOrderable, byPkRoot, coerceInt64Filter, createHasuraDataProvider, createHasuraLiveProvider, decodeCursor, effectiveCursorOrdering, encodeCursor, filtersToWhere, flattenJsonbSpill, hasuraWsUrl, keysetWhere, localeWhere, mergeWhere, orderingSignature, partitionDataBody, partitionJsonbSpill, scopeToWhere };
889
967
 
890
968
  //# sourceMappingURL=index.js.map