@foir/sdk 0.8.0 → 0.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 (57) hide show
  1. package/CHANGELOG.md +550 -28
  2. package/README.md +111 -0
  3. package/dist/auth/auth.d.ts +72 -1
  4. package/dist/auth/hosted.d.ts +93 -4
  5. package/dist/auth/index.d.ts +4 -4
  6. package/dist/auth/operations.d.ts +84 -0
  7. package/dist/auth/ops.d.ts +10 -0
  8. package/dist/auth.js +138 -19
  9. package/dist/client.js +63 -6
  10. package/dist/codegen/block-registry.d.ts +1 -1
  11. package/dist/codegen/block-scaffold.d.ts +1 -1
  12. package/dist/codegen/index.d.ts +1 -1
  13. package/dist/codegen/item-registry.d.ts +1 -1
  14. package/dist/codegen/item-scaffold.d.ts +1 -1
  15. package/dist/content/content-renderer.d.ts +4 -5
  16. package/dist/content/index.d.ts +1 -1
  17. package/dist/content/richtext.d.ts +1 -1
  18. package/dist/data/builtins.d.ts +131 -12
  19. package/dist/data/client.d.ts +82 -1
  20. package/dist/data/decimal.d.ts +212 -0
  21. package/dist/data/document.d.ts +1 -1
  22. package/dist/data/index.d.ts +11 -9
  23. package/dist/data/manifest.d.ts +33 -6
  24. package/dist/data/schema.d.ts +2 -2
  25. package/dist/data/subscriptions.d.ts +36 -10
  26. package/dist/data/transport.d.ts +120 -3
  27. package/dist/data.js +377 -16
  28. package/dist/graphql/cdn-route.d.ts +1 -1
  29. package/dist/graphql/foir-request.d.ts +1 -1
  30. package/dist/live/coalesce.d.ts +57 -0
  31. package/dist/live/drift.d.ts +59 -0
  32. package/dist/live/events.d.ts +13 -0
  33. package/dist/live/headers.d.ts +53 -0
  34. package/dist/live/index.d.ts +54 -0
  35. package/dist/live/keys.d.ts +72 -0
  36. package/dist/live/manager.d.ts +77 -0
  37. package/dist/live/react/index.d.ts +143 -0
  38. package/dist/live/reconcile.d.ts +82 -0
  39. package/dist/live/resync.d.ts +59 -0
  40. package/dist/live/store.d.ts +134 -0
  41. package/dist/live/tagIndex.d.ts +29 -0
  42. package/dist/live/tanstack.d.ts +127 -0
  43. package/dist/live/writetoken.d.ts +86 -0
  44. package/dist/live-react.js +395 -0
  45. package/dist/live.js +845 -0
  46. package/dist/next/cacheTags.d.ts +245 -0
  47. package/dist/next/index.d.ts +7 -0
  48. package/dist/next.js +179 -6
  49. package/dist/push.js +81 -8
  50. package/dist/react.js +76 -5
  51. package/dist/realtime/index.d.ts +4 -5
  52. package/dist/server/events-client.d.ts +54 -4
  53. package/dist/server/index.d.ts +3 -2
  54. package/dist/server/require-scoped-token.d.ts +1 -1
  55. package/dist/server.js +454 -2
  56. package/dist/transport/foir-http.d.ts +113 -10
  57. package/package.json +10 -2
package/dist/auth.js CHANGED
@@ -11,11 +11,30 @@ function isFoirPreview(env) {
11
11
  function resolveFoirApiKey(env) {
12
12
  return isFoirPreview(env) ? env.PLATFORM_PREVIEW_API_KEY ?? env.PLATFORM_API_KEY : env.PLATFORM_API_KEY;
13
13
  }
14
+ var MALFORMED_PRUNE_REASONS = /* @__PURE__ */ new Set([
15
+ "unknown_field",
16
+ "subselections_on_scalar",
17
+ "missing_subselections"
18
+ ]);
14
19
  var FoirRequestError = class extends Error {
15
20
  /** HTTP status code, when the request failed at the HTTP layer. */
16
21
  status;
17
22
  /** GraphQL errors, when the request failed with a no-data error envelope. */
18
23
  graphQLErrors;
24
+ /**
25
+ * The `data` the server did return, when a STRICT read refused a partial
26
+ * response. Present only on that path: without it, opting into strictness
27
+ * would trade a silent wrong answer for a thrown one that discards the answer,
28
+ * and a caller that wants to log what it nearly rendered could not.
29
+ */
30
+ partialData;
31
+ /**
32
+ * The selections the server stripped, when the refusal was a pruned document
33
+ * rather than a partial error. Same purpose as `partialData`: a caller that
34
+ * wants to log what it nearly rendered, or name the offending path in a
35
+ * developer-facing message, has it without re-parsing anything.
36
+ */
37
+ prunedSelections;
19
38
  cause;
20
39
  constructor(message, options) {
21
40
  super(message);
@@ -23,6 +42,8 @@ var FoirRequestError = class extends Error {
23
42
  this.cause = options?.cause;
24
43
  this.status = options?.status;
25
44
  this.graphQLErrors = options?.graphQLErrors;
45
+ this.partialData = options?.partialData;
46
+ this.prunedSelections = options?.prunedSelections;
26
47
  }
27
48
  /**
28
49
  * The code of the first error, if the response carried one.
@@ -93,6 +114,9 @@ function buildFoirHeaders(input) {
93
114
  if (input.bearerToken) {
94
115
  headers["Authorization"] = `Bearer ${input.bearerToken}`;
95
116
  }
117
+ if (input.orgId) {
118
+ headers["X-Org-Id"] = input.orgId;
119
+ }
96
120
  if (input.extra) {
97
121
  for (const [key, value] of Object.entries(input.extra)) {
98
122
  headers[key] = value;
@@ -107,14 +131,45 @@ function foirApiEndpoint(apiUrl, path) {
107
131
  }
108
132
  return base + path;
109
133
  }
110
- function readFoirEnvelope(json) {
134
+ var warnedDowngrade = null;
135
+ function reportAuthDowngrade(envelope) {
136
+ const downgrade = envelope.extensions?.auth;
137
+ if (!downgrade) {
138
+ warnedDowngrade = null;
139
+ return;
140
+ }
141
+ if (warnedDowngrade === downgrade.reason) return;
142
+ warnedDowngrade = downgrade.reason;
143
+ console.warn(
144
+ `[foir] your customer token was ${downgrade.customerToken} (${downgrade.reason}) \u2014 this request was served as ${downgrade.servedAs}, so auth-targeted content resolved to its anonymous variant. ` + (downgrade.reason === "expired" ? "Re-exchange the token and retry." : "Check which credential you are sending.")
145
+ );
146
+ }
147
+ function refusePrunedDocument(json, options) {
148
+ const selections = json.extensions?.pruned?.selections;
149
+ if (!selections?.length) return;
150
+ const describe = (s) => `${s.path}${s.type ? ` on ${s.type}` : ""} (${s.reason})`;
151
+ const malformed = selections.filter((s) => MALFORMED_PRUNE_REASONS.has(s.reason));
152
+ if (malformed.length && options?.strict !== false) {
153
+ throw new FoirRequestError(
154
+ `[foir] the server could not serve part of this query and returned the rest without it: ${malformed.map(describe).join(", ")}. Those selections do not exist on the schema this project is serving. Pass strict: false to get the partial answer instead of this error.`,
155
+ { prunedSelections: selections }
156
+ );
157
+ }
158
+ console.warn(
159
+ `[foir] selections stripped from this query: ${selections.map(describe).join(", ")}`
160
+ );
161
+ }
162
+ function readFoirEnvelope(json, options) {
163
+ reportAuthDowngrade(json);
164
+ refusePrunedDocument(json, options);
111
165
  if (json.errors?.length) {
112
166
  const msg = json.errors.map((e) => e.message).join("; ");
113
- if (json.data) {
167
+ if (json.data && !options?.strict) {
114
168
  console.warn(`[foir] GraphQL partial errors (data returned): ${msg}`);
115
169
  } else {
116
170
  throw new FoirRequestError(`[foir] GraphQL errors: ${msg}`, {
117
- graphQLErrors: json.errors
171
+ graphQLErrors: json.errors,
172
+ partialData: json.data ?? void 0
118
173
  });
119
174
  }
120
175
  }
@@ -155,8 +210,9 @@ async function hasFoirErrorCode(res, ...codes) {
155
210
  }
156
211
 
157
212
  // src/graphql/cdn-route.ts
158
- function isCdnEligible(env, documentText, bearerToken) {
213
+ function isCdnEligible(env, documentText, bearerToken, orgId) {
159
214
  if (bearerToken) return false;
215
+ if (orgId) return false;
160
216
  if (isFoirPreview(env)) return false;
161
217
  const apiKey = resolveFoirApiKey(env);
162
218
  if (!apiKey?.startsWith("pk_")) return false;
@@ -175,12 +231,13 @@ async function foirRequest(env, document, variables, options) {
175
231
  const headers = buildFoirHeaders({
176
232
  apiKey,
177
233
  draftChannel: isFoirPreview(env),
178
- bearerToken: options?.bearerToken
234
+ bearerToken: options?.bearerToken,
235
+ orgId: options?.orgId
179
236
  });
180
237
  const documentText = print2(document);
181
238
  let res;
182
239
  try {
183
- if (isCdnEligible(env, documentText, options?.bearerToken)) {
240
+ if (isCdnEligible(env, documentText, options?.bearerToken, options?.orgId)) {
184
241
  const hash = await documentHash(documentText);
185
242
  let shared = await fetch(buildCdnUrl(endpoint, apiKey, hash, variables), {
186
243
  method: "GET",
@@ -739,7 +796,9 @@ async function resolveBearerToken(config) {
739
796
  function foirRoute(input) {
740
797
  if (!input.apiKey.startsWith("pk_")) return { lane: "origin", reason: "key" };
741
798
  if (input.bearerToken) return { lane: "origin", reason: "bearer" };
799
+ if (input.orgId) return { lane: "origin", reason: "org" };
742
800
  if (input.mutation) return { lane: "origin", reason: "operation" };
801
+ if (input.writeToken) return { lane: "origin", reason: "floor" };
743
802
  if (input.channel === "draft") return { lane: "origin", reason: "channel" };
744
803
  return { lane: "shared" };
745
804
  }
@@ -752,7 +811,7 @@ async function executeFoirDocument(config, plan) {
752
811
  }
753
812
  return data[plan.rootField];
754
813
  }
755
- async function runFoirDocument(config, document, mutation, variables) {
814
+ async function runFoirDocument(config, document, mutation, variables, options) {
756
815
  const doFetch = config.fetch ?? globalThis.fetch;
757
816
  const endpoint = foirDataEndpoint(config.apiUrl, "/graphql");
758
817
  const bearerToken = await resolveBearerToken(config);
@@ -760,12 +819,14 @@ async function runFoirDocument(config, document, mutation, variables) {
760
819
  apiKey: config.apiKey,
761
820
  draftChannel: config.channel === "draft",
762
821
  bearerToken,
822
+ orgId: config.orgId,
763
823
  extra: config.headers
764
824
  });
765
825
  const hash = await documentHash(document);
766
826
  const route = foirRoute({
767
827
  apiKey: config.apiKey,
768
828
  bearerToken,
829
+ orgId: config.orgId,
769
830
  mutation,
770
831
  channel: config.channel
771
832
  });
@@ -805,7 +866,7 @@ async function runFoirDocument(config, document, mutation, variables) {
805
866
  });
806
867
  }
807
868
  const json = await res.json();
808
- return readFoirEnvelope(json);
869
+ return readFoirEnvelope(json, options);
809
870
  }
810
871
  async function readErrorBody(res) {
811
872
  try {
@@ -828,6 +889,7 @@ async function fetchFoirManifest(config) {
828
889
  apiKey: config.apiKey,
829
890
  draftChannel: config.channel === "draft",
830
891
  bearerToken: await resolveBearerToken(config),
892
+ orgId: config.orgId,
831
893
  extra: config.headers
832
894
  }),
833
895
  ...config.requestInit
@@ -869,6 +931,16 @@ var AUTH_OPS = {
869
931
  customerUpdatePassword: "customerUpdatePassword",
870
932
  customerVerifyEmail: "customerVerifyEmail",
871
933
  deleteMyAccount: "deleteMyAccount",
934
+ // The operator's organization context. TWO ops and no third: one to read
935
+ // which organizations the caller may stand in, one to say which. There is
936
+ // deliberately no per-call org argument anywhere in this SDK — the claim the
937
+ // row layer reads is resolved from the caller's own membership row on every
938
+ // request, so an application that never names an org cannot name the wrong
939
+ // one.
940
+ myOrganizations: "myOrganizations",
941
+ selectMyOrganization: "selectMyOrganization",
942
+ // Founding one. Present in a manifest only when the project opted in.
943
+ registerOperatorOrganization: "registerOperatorOrganization",
872
944
  // External identity providers.
873
945
  customerLoginWithProvider: "customerLoginWithProvider",
874
946
  customerProviderCallback: "customerProviderCallback",
@@ -890,6 +962,7 @@ function authClientConfig(env, options) {
890
962
  apiKey,
891
963
  channel: isFoirPreview(env) ? "draft" : "published",
892
964
  bearerToken: options?.bearerToken,
965
+ orgId: options?.orgId,
893
966
  headers: options?.headers,
894
967
  fetch: options?.fetch
895
968
  };
@@ -998,6 +1071,15 @@ async function customerLogout(env, options) {
998
1071
  async function deleteMyAccount(env, vars, options) {
999
1072
  return authOp(env, AUTH_OPS.deleteMyAccount, vars, options);
1000
1073
  }
1074
+ async function myOrganizations(env, vars, options) {
1075
+ return authOp(env, AUTH_OPS.myOrganizations, vars ?? {}, options);
1076
+ }
1077
+ async function selectOrganization(env, vars, options) {
1078
+ return authOp(env, AUTH_OPS.selectMyOrganization, vars, options);
1079
+ }
1080
+ async function registerOrganization(env, vars, options) {
1081
+ return authOp(env, AUTH_OPS.registerOperatorOrganization, vars, options);
1082
+ }
1001
1083
  async function saveSession(adapter, result) {
1002
1084
  await adapter.set(TOKEN_KEY, result.token);
1003
1085
  await adapter.set(REFRESH_KEY, result.refreshToken);
@@ -1111,6 +1193,7 @@ async function requireAdmin(adapter, options) {
1111
1193
  // src/auth/hosted.ts
1112
1194
  var DEFAULT_COOKIE_NAME = "foir_customer_session";
1113
1195
  var DEFAULT_SESSION_PATH = "/session/token";
1196
+ var DEFAULT_END_SESSION_PATH = "/session/end-session";
1114
1197
  function hostedLoginUrl(config, returnTo) {
1115
1198
  const dest = new URL(config.loginOrigin);
1116
1199
  if (returnTo && returnTo !== "/") {
@@ -1118,6 +1201,15 @@ function hostedLoginUrl(config, returnTo) {
1118
1201
  }
1119
1202
  return dest.toString();
1120
1203
  }
1204
+ function hostedLogoutUrl(config, clientId, returnTo) {
1205
+ const path = config.endSessionPath ?? DEFAULT_END_SESSION_PATH;
1206
+ const dest = new URL(path, config.loginOrigin);
1207
+ dest.searchParams.set("client_id", clientId);
1208
+ if (returnTo) {
1209
+ dest.searchParams.set("post_logout_redirect_uri", returnTo);
1210
+ }
1211
+ return dest.toString();
1212
+ }
1121
1213
  async function fetchHostedSession(request, config) {
1122
1214
  const cookieName = config.cookieName ?? DEFAULT_COOKIE_NAME;
1123
1215
  const sessionPath = config.sessionPath ?? DEFAULT_SESSION_PATH;
@@ -1125,25 +1217,48 @@ async function fetchHostedSession(request, config) {
1125
1217
  const match = cookie.match(
1126
1218
  new RegExp(`(?:^|;\\s*)${escapeRegExp(cookieName)}=([^;]+)`)
1127
1219
  );
1128
- if (!match) return null;
1220
+ if (!match) return { outcome: "signed-out", reason: "no-cookie" };
1221
+ let res;
1129
1222
  try {
1130
- const res = await fetch(`${config.loginOrigin}${sessionPath}`, {
1223
+ res = await fetch(`${config.loginOrigin}${sessionPath}`, {
1131
1224
  headers: {
1132
1225
  Cookie: `${cookieName}=${match[1]}`,
1133
1226
  "X-Foir-Session": "1"
1134
1227
  }
1135
1228
  });
1136
- if (!res.ok) return null;
1137
- const json = await res.json();
1138
- if (!json.access_token || !json.customer_id) return null;
1139
- return {
1140
- token: json.access_token,
1141
- customerId: json.customer_id,
1142
- email: json.email ?? ""
1143
- };
1229
+ } catch (cause) {
1230
+ return { outcome: "unavailable", reason: "network", cause };
1231
+ }
1232
+ if (!res.ok) {
1233
+ if (res.status === 401) {
1234
+ return { outcome: "signed-out", reason: "rejected" };
1235
+ }
1236
+ if (res.status === 403) {
1237
+ return { outcome: "unavailable", reason: "forbidden", httpStatus: res.status };
1238
+ }
1239
+ if (res.status === 429) {
1240
+ return { outcome: "unavailable", reason: "rate-limited", httpStatus: res.status };
1241
+ }
1242
+ return { outcome: "unavailable", reason: "server-error", httpStatus: res.status };
1243
+ }
1244
+ let json;
1245
+ try {
1246
+ json = await res.json();
1144
1247
  } catch {
1145
- return null;
1248
+ return { outcome: "unavailable", reason: "malformed", httpStatus: res.status };
1146
1249
  }
1250
+ if (!json.access_token || !json.customer_id) {
1251
+ return { outcome: "unavailable", reason: "malformed", httpStatus: res.status };
1252
+ }
1253
+ return {
1254
+ outcome: "active",
1255
+ session: {
1256
+ token: json.access_token,
1257
+ customerId: json.customer_id,
1258
+ email: json.email ?? "",
1259
+ expiresIn: typeof json.expires_in === "number" ? json.expires_in : 0
1260
+ }
1261
+ };
1147
1262
  }
1148
1263
  function escapeRegExp(s) {
1149
1264
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -1313,14 +1428,18 @@ export {
1313
1428
  getSessionCustomer,
1314
1429
  getSessionToken,
1315
1430
  hostedLoginUrl,
1431
+ hostedLogoutUrl,
1316
1432
  loginWithOTP,
1317
1433
  loginWithPassword,
1434
+ myOrganizations,
1318
1435
  myProviderToken,
1319
1436
  refreshSession,
1437
+ registerOrganization,
1320
1438
  registerWithPassword,
1321
1439
  requireAdmin,
1322
1440
  requireAuth,
1323
1441
  resetPasswordAndSignIn,
1324
1442
  saveSession,
1443
+ selectOrganization,
1325
1444
  signOut
1326
1445
  };
package/dist/client.js CHANGED
@@ -11,11 +11,30 @@ function isFoirPreview(env) {
11
11
  function resolveFoirApiKey(env) {
12
12
  return isFoirPreview(env) ? env.PLATFORM_PREVIEW_API_KEY ?? env.PLATFORM_API_KEY : env.PLATFORM_API_KEY;
13
13
  }
14
+ var MALFORMED_PRUNE_REASONS = /* @__PURE__ */ new Set([
15
+ "unknown_field",
16
+ "subselections_on_scalar",
17
+ "missing_subselections"
18
+ ]);
14
19
  var FoirRequestError = class extends Error {
15
20
  /** HTTP status code, when the request failed at the HTTP layer. */
16
21
  status;
17
22
  /** GraphQL errors, when the request failed with a no-data error envelope. */
18
23
  graphQLErrors;
24
+ /**
25
+ * The `data` the server did return, when a STRICT read refused a partial
26
+ * response. Present only on that path: without it, opting into strictness
27
+ * would trade a silent wrong answer for a thrown one that discards the answer,
28
+ * and a caller that wants to log what it nearly rendered could not.
29
+ */
30
+ partialData;
31
+ /**
32
+ * The selections the server stripped, when the refusal was a pruned document
33
+ * rather than a partial error. Same purpose as `partialData`: a caller that
34
+ * wants to log what it nearly rendered, or name the offending path in a
35
+ * developer-facing message, has it without re-parsing anything.
36
+ */
37
+ prunedSelections;
19
38
  cause;
20
39
  constructor(message, options) {
21
40
  super(message);
@@ -23,6 +42,8 @@ var FoirRequestError = class extends Error {
23
42
  this.cause = options?.cause;
24
43
  this.status = options?.status;
25
44
  this.graphQLErrors = options?.graphQLErrors;
45
+ this.partialData = options?.partialData;
46
+ this.prunedSelections = options?.prunedSelections;
26
47
  }
27
48
  /**
28
49
  * The code of the first error, if the response carried one.
@@ -105,6 +126,9 @@ function buildFoirHeaders(input) {
105
126
  if (input.bearerToken) {
106
127
  headers["Authorization"] = `Bearer ${input.bearerToken}`;
107
128
  }
129
+ if (input.orgId) {
130
+ headers["X-Org-Id"] = input.orgId;
131
+ }
108
132
  if (input.extra) {
109
133
  for (const [key, value] of Object.entries(input.extra)) {
110
134
  headers[key] = value;
@@ -112,14 +136,45 @@ function buildFoirHeaders(input) {
112
136
  }
113
137
  return headers;
114
138
  }
115
- function readFoirEnvelope(json) {
139
+ var warnedDowngrade = null;
140
+ function reportAuthDowngrade(envelope) {
141
+ const downgrade = envelope.extensions?.auth;
142
+ if (!downgrade) {
143
+ warnedDowngrade = null;
144
+ return;
145
+ }
146
+ if (warnedDowngrade === downgrade.reason) return;
147
+ warnedDowngrade = downgrade.reason;
148
+ console.warn(
149
+ `[foir] your customer token was ${downgrade.customerToken} (${downgrade.reason}) \u2014 this request was served as ${downgrade.servedAs}, so auth-targeted content resolved to its anonymous variant. ` + (downgrade.reason === "expired" ? "Re-exchange the token and retry." : "Check which credential you are sending.")
150
+ );
151
+ }
152
+ function refusePrunedDocument(json, options) {
153
+ const selections = json.extensions?.pruned?.selections;
154
+ if (!selections?.length) return;
155
+ const describe = (s) => `${s.path}${s.type ? ` on ${s.type}` : ""} (${s.reason})`;
156
+ const malformed = selections.filter((s) => MALFORMED_PRUNE_REASONS.has(s.reason));
157
+ if (malformed.length && options?.strict !== false) {
158
+ throw new FoirRequestError(
159
+ `[foir] the server could not serve part of this query and returned the rest without it: ${malformed.map(describe).join(", ")}. Those selections do not exist on the schema this project is serving. Pass strict: false to get the partial answer instead of this error.`,
160
+ { prunedSelections: selections }
161
+ );
162
+ }
163
+ console.warn(
164
+ `[foir] selections stripped from this query: ${selections.map(describe).join(", ")}`
165
+ );
166
+ }
167
+ function readFoirEnvelope(json, options) {
168
+ reportAuthDowngrade(json);
169
+ refusePrunedDocument(json, options);
116
170
  if (json.errors?.length) {
117
171
  const msg = json.errors.map((e) => e.message).join("; ");
118
- if (json.data) {
172
+ if (json.data && !options?.strict) {
119
173
  console.warn(`[foir] GraphQL partial errors (data returned): ${msg}`);
120
174
  } else {
121
175
  throw new FoirRequestError(`[foir] GraphQL errors: ${msg}`, {
122
- graphQLErrors: json.errors
176
+ graphQLErrors: json.errors,
177
+ partialData: json.data ?? void 0
123
178
  });
124
179
  }
125
180
  }
@@ -160,8 +215,9 @@ async function hasFoirErrorCode(res, ...codes) {
160
215
  }
161
216
 
162
217
  // src/graphql/cdn-route.ts
163
- function isCdnEligible(env, documentText, bearerToken) {
218
+ function isCdnEligible(env, documentText, bearerToken, orgId) {
164
219
  if (bearerToken) return false;
220
+ if (orgId) return false;
165
221
  if (isFoirPreview(env)) return false;
166
222
  const apiKey = resolveFoirApiKey(env);
167
223
  if (!apiKey?.startsWith("pk_")) return false;
@@ -214,12 +270,13 @@ async function foirRequest(env, document, variables, options) {
214
270
  const headers = buildFoirHeaders({
215
271
  apiKey,
216
272
  draftChannel: isFoirPreview(env),
217
- bearerToken: options?.bearerToken
273
+ bearerToken: options?.bearerToken,
274
+ orgId: options?.orgId
218
275
  });
219
276
  const documentText = print2(document);
220
277
  let res;
221
278
  try {
222
- if (isCdnEligible(env, documentText, options?.bearerToken)) {
279
+ if (isCdnEligible(env, documentText, options?.bearerToken, options?.orgId)) {
223
280
  const hash = await documentHash(documentText);
224
281
  let shared = await fetch(buildCdnUrl(endpoint, apiKey, hash, variables), {
225
282
  method: "GET",
@@ -2,7 +2,7 @@
2
2
  * `@foir/sdk/codegen/block-registry` — DEPRECATED alias.
3
3
  *
4
4
  * `block` was one project's name for a flexible field, never a platform
5
- * concept (TTS-1391). The plugin moved to `@foir/sdk/codegen/item-registry`;
5
+ * concept. The plugin moved to `@foir/sdk/codegen/item-registry`;
6
6
  * this path re-exports it unchanged so an existing `codegen.ts` keeps working.
7
7
  * Repoint the `plugins:` entry when convenient — this will be removed in a
8
8
  * future major.
@@ -2,7 +2,7 @@
2
2
  * `@foir/sdk/codegen/block-scaffold` — DEPRECATED alias.
3
3
  *
4
4
  * `block` was one project's name for a flexible field, never a platform
5
- * concept (TTS-1391). The plugin moved to `@foir/sdk/codegen/item-scaffold`;
5
+ * concept. The plugin moved to `@foir/sdk/codegen/item-scaffold`;
6
6
  * this path re-exports it unchanged so an existing `codegen.ts` keeps working.
7
7
  * Repoint the `plugins:` entry when convenient — this will be removed in a
8
8
  * future major.
@@ -6,7 +6,7 @@
6
6
  * and item-scaffold plugins are wired by the preset and also available at
7
7
  * `@foir/sdk/codegen/item-registry` / `@foir/sdk/codegen/item-scaffold`.
8
8
  *
9
- * The pre-TTS-1391 paths `@foir/sdk/codegen/block-registry` and
9
+ * The pre-rename paths `@foir/sdk/codegen/block-registry` and
10
10
  * `/block-scaffold` still resolve, re-exporting those modules unchanged.
11
11
  */
12
12
  export { foirCodegen, foirScaffold } from './preset';
@@ -13,7 +13,7 @@
13
13
  * types from the codegen output (`./graphql`) and `ItemComponent` from
14
14
  * `@foir/sdk/content`, so it pairs directly with `createContentRenderer`.
15
15
  *
16
- * Reachable at the pre-TTS-1391 path `@foir/sdk/codegen/block-registry` too,
16
+ * Reachable at the pre-rename path `@foir/sdk/codegen/block-registry` too,
17
17
  * which re-exports this module unchanged.
18
18
  */
19
19
  import type { GraphQLSchema } from 'graphql';
@@ -10,7 +10,7 @@
10
10
  * in. Adding a new item type later surfaces as a compile error on
11
11
  * `itemRegistry` (via the regenerated `ItemRegistry` type), not here.
12
12
  *
13
- * Reachable at the pre-TTS-1391 path `@foir/sdk/codegen/block-scaffold` too,
13
+ * Reachable at the pre-rename path `@foir/sdk/codegen/block-scaffold` too,
14
14
  * which re-exports this module unchanged.
15
15
  */
16
16
  import type { GraphQLSchema } from 'graphql';
@@ -15,7 +15,7 @@
15
15
  *
16
16
  * The "switch" is a typed object lookup. Exhaustiveness is enforced where the
17
17
  * registry is BUILT — against the exhaustive `ItemRegistry` type the codegen
18
- * plugin (EID-92) generates per project, so omitting an item type is a compile
18
+ * plugin generates per project, so omitting an item type is a compile
19
19
  * error there, not a runtime surprise here. The consumer can supply different
20
20
  * registries per surface (e.g. web vs email).
21
21
  *
@@ -24,8 +24,7 @@
24
24
  * A prose field holds ENTRIES. A modeller may name the field `blocks`,
25
25
  * `sections`, `modules` or anything else, and this renderer must not care:
26
26
  * dispatch is on `__typename` and never on a field name. The `Block*` spellings
27
- * below are deprecated aliases kept so existing consumers compile — see
28
- * TTS-1391.
27
+ * below are deprecated aliases kept so existing consumers compile.
29
28
  */
30
29
  import { type ReactNode } from 'react';
31
30
  import { type PassageLike } from './richtext';
@@ -41,7 +40,7 @@ export interface ItemComponentProps<TItem, TCtx = unknown> {
41
40
  /**
42
41
  * The same value as `item`.
43
42
  *
44
- * @deprecated Use `item`. Kept so components scaffolded before TTS-1391
43
+ * @deprecated Use `item`. Kept so components scaffolded before the rename
45
44
  * keep compiling; it is passed on every render and will be removed in a
46
45
  * future major.
47
46
  */
@@ -67,7 +66,7 @@ export interface EntriesLike {
67
66
  * The prose field's entries — the projection wrapper (`{ entries }`), or a
68
67
  * plain array — plus the context threaded to every component.
69
68
  *
70
- * `items` is canonical. `blocks` is the pre-TTS-1391 spelling and still
69
+ * `items` is canonical. `blocks` is the pre-rename spelling and still
71
70
  * accepted; passing both is a type error rather than a silent precedence rule,
72
71
  * because a caller who set both cannot be told which one this honoured.
73
72
  */
@@ -9,7 +9,7 @@
9
9
  export { createContentRenderer } from './content-renderer';
10
10
  export type { ItemLike, EntriesLike, ItemComponent, ItemComponentProps, ItemRegistry, ContentRendererProps, ContentRendererOptions, PassageRunProps, } from './content-renderer';
11
11
  /**
12
- * Pre-TTS-1391 spellings. `Block` was one project's name for a flexible field,
12
+ * Pre-rename spellings. `Block` was one project's name for a flexible field,
13
13
  * never a platform concept; these are kept so existing consumers compile and
14
14
  * will be removed in a future major.
15
15
  */
@@ -25,7 +25,7 @@
25
25
  import { type ReactNode, type JSX } from 'react';
26
26
  /**
27
27
  * safeHref allow-lists link schemes so stored prose can't smuggle a
28
- * `javascript:` (or `data:`/`vbscript:`) URL that executes on click (EID-207).
28
+ * `javascript:` (or `data:`/`vbscript:`) URL that executes on click.
29
29
  * Relative URLs, anchors, and the http(s)/mailto/tel schemes pass; anything
30
30
  * else collapses to '#'. Editors are not fully trusted, so this runs on the
31
31
  * structured render path, not only the html fallback.