@relyio/sdk 0.18.0 → 0.20.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 (58) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/automations/index.cjs +18 -17
  3. package/dist/automations/index.d.cts +2 -1307
  4. package/dist/automations/index.d.ts +2 -1307
  5. package/dist/automations/index.js +3 -2
  6. package/dist/{chunk-ZAMAR3X2.cjs → chunk-5F3YYPLZ.cjs} +11249 -10771
  7. package/dist/{chunk-ZO6QDYJG.cjs → chunk-5WGMIQBH.cjs} +2 -2
  8. package/dist/{chunk-LSI26ZN2.cjs → chunk-DBYMG6MQ.cjs} +5 -5
  9. package/dist/{chunk-W2A4OTCI.js → chunk-EQUZNVAR.js} +2 -2
  10. package/dist/{chunk-IFKF72VJ.cjs → chunk-K66MBRI4.cjs} +147 -71
  11. package/dist/{chunk-ZHTJ7GXH.js → chunk-L42C4G2S.js} +106 -31
  12. package/dist/{chunk-EDE2H37D.js → chunk-OUR7OUUZ.js} +174 -12
  13. package/dist/{chunk-W7JFHSFM.js → chunk-PZCDJFMA.js} +11249 -10772
  14. package/dist/{chunk-SHSK7UUY.cjs → chunk-UO2QRYKV.cjs} +177 -11
  15. package/dist/{chunk-R6E4HE7R.js → chunk-W2GRVXDG.js} +3 -3
  16. package/dist/client/index.cjs +5 -5
  17. package/dist/client/index.d.cts +4 -4
  18. package/dist/client/index.d.ts +4 -4
  19. package/dist/client/index.js +3 -3
  20. package/dist/{define-content-type-NEQDrvdq.d.cts → define-content-type-C2HnCYYX.d.cts} +1324 -156
  21. package/dist/{define-content-type-fb-WCD5e.d.ts → define-content-type-CVLUusfx.d.ts} +1324 -156
  22. package/dist/dev-handshake/index.cjs +8 -8
  23. package/dist/dev-handshake/index.d.cts +1 -1
  24. package/dist/dev-handshake/index.d.ts +1 -1
  25. package/dist/dev-handshake/index.js +1 -1
  26. package/dist/extensions/index.cjs +26 -6
  27. package/dist/extensions/index.d.cts +3 -791
  28. package/dist/extensions/index.d.ts +3 -791
  29. package/dist/extensions/index.js +24 -4
  30. package/dist/functions/index.cjs +7 -4
  31. package/dist/functions/index.d.cts +2 -4
  32. package/dist/functions/index.d.ts +2 -4
  33. package/dist/functions/index.js +5 -2
  34. package/dist/{index-DwHcL6x5.d.cts → index-BLVNMYUU.d.cts} +142 -79
  35. package/dist/{index-C4LqrNd1.d.ts → index-BY1xU93u.d.ts} +1 -1
  36. package/dist/{index-Dnmt_UOo.d.cts → index-Cmup6HJY.d.cts} +1 -1
  37. package/dist/index-D1fiaQlK.d.ts +2284 -0
  38. package/dist/index-DImzg3ew.d.cts +2284 -0
  39. package/dist/{index-M3luH06A.d.ts → index-IjSyBr8f.d.ts} +142 -79
  40. package/dist/index.cjs +89 -85
  41. package/dist/index.d.cts +64 -15
  42. package/dist/index.d.ts +64 -15
  43. package/dist/index.js +5 -5
  44. package/dist/preview/index.cjs +3 -3
  45. package/dist/preview/index.js +1 -1
  46. package/dist/rich-text/index.d.cts +2 -2
  47. package/dist/rich-text/index.d.ts +2 -2
  48. package/dist/schema/index.cjs +41 -40
  49. package/dist/schema/index.d.cts +948 -118
  50. package/dist/schema/index.d.ts +948 -118
  51. package/dist/schema/index.js +2 -1
  52. package/dist/types/index.d.cts +1 -1
  53. package/dist/types/index.d.ts +1 -1
  54. package/package.json +5 -5
  55. package/dist/define-schema-DZhtvLiK.d.cts +0 -846
  56. package/dist/define-schema-Dlwh6l_J.d.ts +0 -846
  57. package/dist/register-B53i97A9.d.ts +0 -677
  58. package/dist/register-BYCs0FpF.d.cts +0 -677
@@ -1,7 +1,7 @@
1
1
  import { isBrowser } from './chunk-NJQK5STK.js';
2
- import { parseDevEnv, DEV_CONTEXT_DIR, DEV_CONTEXT_FILENAME, parseDevContextFile } from './chunk-W2A4OTCI.js';
2
+ import { parseDevEnv, DEV_CONTEXT_DIR, DEV_CONTEXT_FILENAME, parseDevContextFile } from './chunk-EQUZNVAR.js';
3
3
  import { UNKNOWN_PREVIEW_RECHECK_MS, previewAtRequest } from './chunk-HDHBYYEY.js';
4
- import { VISITOR_CLOSE_CODES, HEADER_RETRY_AFTER, HEADER_IDEMPOTENCY_KEY, entityTag, HEADER_IF_MATCH, FRESH_PARAMETER, VISITOR_KEEPALIVE, parseVisitorFrame, VISITOR_FRAMES, VISITOR_POLL_INTERVAL_MS, VISITOR_CLOSE_RETRY, readVisitorPollAnswer, VISITOR_POLL_RETRY, VISITOR_LIVE_PATH, VISITOR_QUERY, previewDatasetSlug } from './chunk-EDE2H37D.js';
4
+ import { HEADER_END_USER, VISITOR_CLOSE_CODES, HEADER_RETRY_AFTER, END_USER_TOKEN_REFUSAL_REASONS, HEADER_IDEMPOTENCY_KEY, entityTag, HEADER_IF_MATCH, FRESH_PARAMETER, VISITOR_KEEPALIVE, parseVisitorFrame, VISITOR_FRAMES, VISITOR_POLL_INTERVAL_MS, VISITOR_CLOSE_RETRY, readVisitorPollAnswer, VISITOR_POLL_RETRY, VISITOR_LIVE_PATH, VISITOR_QUERY, previewDatasetSlug } from './chunk-OUR7OUUZ.js';
5
5
  import { __name, __publicField } from './chunk-DI6KFDBO.js';
6
6
 
7
7
  /* RelyIO SDK - Built with ❤️ by the RelyIO Team */
@@ -169,13 +169,13 @@ var _ReadOnlyKeyError = class _ReadOnlyKeyError extends SDKError {
169
169
  __name(_ReadOnlyKeyError, "ReadOnlyKeyError");
170
170
  var ReadOnlyKeyError = _ReadOnlyKeyError;
171
171
  var _PublishableKeyRefusedError = class _PublishableKeyRefusedError extends SDKError {
172
- constructor(message = "A publishable key cannot read or write Records or run Functions", context) {
172
+ constructor(message = "A publishable key writes a Record only for a signed-in End user", context) {
173
173
  super(message, 403, void 0, context);
174
174
  __publicField(this, "code", "PUBLISHABLE_KEY_REFUSED");
175
175
  __publicField(this, "retryable", false);
176
176
  }
177
177
  getUserMessage() {
178
- return "A publishable key cannot reach Records or Functions. Call them from your server with a secret key.";
178
+ return "A publishable key writes a Record only with a signed-in End user's token, and runs only a Function declaring endUsers. Send the End user's token, declare endUsers on the Function, or call it from your server with a secret key.";
179
179
  }
180
180
  };
181
181
  __name(_PublishableKeyRefusedError, "PublishableKeyRefusedError");
@@ -392,6 +392,19 @@ var _InvalidApiKeyError = class _InvalidApiKeyError extends SDKError {
392
392
  };
393
393
  __name(_InvalidApiKeyError, "InvalidApiKeyError");
394
394
  var InvalidApiKeyError = _InvalidApiKeyError;
395
+ var _EndUserTokenInvalidError = class _EndUserTokenInvalidError extends SDKError {
396
+ constructor(message, reason, context) {
397
+ super(message, 401, void 0, context);
398
+ this.reason = reason;
399
+ __publicField(this, "code", "END_USER_TOKEN_INVALID");
400
+ __publicField(this, "retryable", false);
401
+ }
402
+ getUserMessage() {
403
+ return "Your session is not valid. Please sign in again.";
404
+ }
405
+ };
406
+ __name(_EndUserTokenInvalidError, "EndUserTokenInvalidError");
407
+ var EndUserTokenInvalidError = _EndUserTokenInvalidError;
395
408
 
396
409
  // src/errors/network-errors.ts
397
410
  var _NetworkError = class _NetworkError extends SDKError {
@@ -593,6 +606,9 @@ var _ErrorMapper = class _ErrorMapper {
593
606
  case "INVALID_API_KEY": {
594
607
  return new InvalidApiKeyError(message, void 0, context);
595
608
  }
609
+ case "END_USER_TOKEN_INVALID": {
610
+ return new EndUserTokenInvalidError(message, endUserTokenReasonOf(refusal), context);
611
+ }
596
612
  case "ACCESS_DENIED": {
597
613
  return new AuthorizationError(message, 403, void 0, context);
598
614
  }
@@ -800,6 +816,15 @@ function violationsOf(refusal) {
800
816
  }));
801
817
  }
802
818
  __name(violationsOf, "violationsOf");
819
+ function endUserTokenReasonOf(refusal) {
820
+ const reason = detailString(refusal, "reason");
821
+ return isEndUserTokenReason(reason) ? reason : void 0;
822
+ }
823
+ __name(endUserTokenReasonOf, "endUserTokenReasonOf");
824
+ function isEndUserTokenReason(value) {
825
+ return value !== void 0 && END_USER_TOKEN_REFUSAL_REASONS.includes(value);
826
+ }
827
+ __name(isEndUserTokenReason, "isEndUserTokenReason");
803
828
 
804
829
  // src/http/api-routes.ts
805
830
  function fillPath(template, params) {
@@ -1172,22 +1197,33 @@ var _HttpClient = class _HttpClient {
1172
1197
  * constructor accepts one so that a module-scope client can be evaluated by a
1173
1198
  * build that holds no key (REL-1120) — and so does one whose `setApiKey` was
1174
1199
  * given none.
1200
+ *
1201
+ * The End user's token is asked for once, after the key is known to be there and before the first
1202
+ * attempt — of `getToken`, the nearest view's function, or the configuration's — so every retry
1203
+ * of one call sends the token its first attempt sent. See `RelyIOConfig.getToken`.
1175
1204
  */
1176
- async request(config) {
1205
+ async request(config, getToken) {
1177
1206
  if (this.view !== void 0) {
1178
- return this.view.client.request({
1179
- ...config,
1180
- headers: layerHeaders(this.view.headers, config.headers)
1181
- });
1207
+ return this.view.client.request(
1208
+ { ...config, headers: layerHeaders(this.view.headers, config.headers) },
1209
+ getToken ?? this.view.getToken
1210
+ );
1182
1211
  }
1183
1212
  if (config.timeout !== void 0) assertRequestTimeout(config.timeout);
1184
1213
  const mergedConfig = this.mergeRequestConfig(config);
1185
- if (presentKey(headerValue(mergedConfig.headers, API_KEY_HEADER)) === void 0) {
1214
+ if (presentCredential(headerValue(mergedConfig.headers, API_KEY_HEADER)) === void 0) {
1186
1215
  throw new MissingApiKeyError(
1187
1216
  "`apiKey` is missing: this client holds no API key, so the request was not sent. Pass `apiKey` to createClient \u2014 the documented setup reads it from RELYIO_API_KEY.",
1188
1217
  { url: mergedConfig.url, method: mergedConfig.method, sent: false }
1189
1218
  );
1190
1219
  }
1220
+ const tokenSource = getToken ?? this.connection.config.getToken;
1221
+ if (tokenSource !== void 0) {
1222
+ const token = presentCredential(await tokenSource());
1223
+ mergedConfig.headers = layerHeaders(mergedConfig.headers ?? {}, {
1224
+ [END_USER_HEADER]: token ?? null
1225
+ });
1226
+ }
1191
1227
  this.log("debug", "Making request", {
1192
1228
  method: mergedConfig.method,
1193
1229
  url: mergedConfig.url
@@ -1231,7 +1267,7 @@ var _HttpClient = class _HttpClient {
1231
1267
  });
1232
1268
  if (preview !== void 0 && answersUnknownDataset(sdkError, preview)) {
1233
1269
  rememberUnknownPreview(preview);
1234
- return this.request(config);
1270
+ return this.request(config, getToken);
1235
1271
  }
1236
1272
  this.log("error", "Request failed after all retries", {
1237
1273
  error: sdkError.toJSON(),
@@ -1452,10 +1488,17 @@ var _ControlledHttpClient = class _ControlledHttpClient extends HttpClient {
1452
1488
  * retries and `fetch` are this client's as they are when each request is sent, so a later
1453
1489
  * `configure()` or `setApiKey()` on this client reaches the view, and one on the view reaches
1454
1490
  * this client. `client.with({ dataset })` is one (REL-2417).
1491
+ *
1492
+ * `options.getToken` is the End user's token function the view asks in place of this client's,
1493
+ * and of any view it is made from: `client.with({ getToken })` (REL-3882).
1455
1494
  */
1456
- withHeaders(headers) {
1495
+ withHeaders(headers, options = {}) {
1457
1496
  const view = new _ControlledHttpClient(this.connection.config);
1458
- view.view = { client: this, headers: { ...headers } };
1497
+ view.view = {
1498
+ client: this,
1499
+ headers: { ...headers },
1500
+ ...options.getToken === void 0 ? {} : { getToken: options.getToken }
1501
+ };
1459
1502
  return view;
1460
1503
  }
1461
1504
  /**
@@ -1477,7 +1520,7 @@ var _ControlledHttpClient = class _ControlledHttpClient extends HttpClient {
1477
1520
  * Replace the key every later request sends as `X-API-Key`, and the `apiKey` the configuration
1478
1521
  * reports.
1479
1522
  *
1480
- * The key is read the way construction reads it (`presentKey`): an absent, empty or blank key is
1523
+ * The key is read the way construction reads it (`presentCredential`): an absent, empty or blank key is
1481
1524
  * no key, so the header is dropped and the next request is refused with `MissingApiKeyError`
1482
1525
  * before anything is sent. A key header of any other spelling — one given in `headers` — goes
1483
1526
  * too, from the headers sent and from the headers the configuration reports, so the old key is
@@ -1498,7 +1541,7 @@ var _ControlledHttpClient = class _ControlledHttpClient extends HttpClient {
1498
1541
  this.connection = {
1499
1542
  ...this.connection,
1500
1543
  defaultHeaders: layerHeaders(this.connection.defaultHeaders, {
1501
- [API_KEY_HEADER]: presentKey(apiKey) ?? null
1544
+ [API_KEY_HEADER]: presentCredential(apiKey) ?? null
1502
1545
  })
1503
1546
  };
1504
1547
  }
@@ -1507,6 +1550,7 @@ __name(_ControlledHttpClient, "ControlledHttpClient");
1507
1550
  var ControlledHttpClient = _ControlledHttpClient;
1508
1551
  var API_KEY_HEADER = "X-API-Key";
1509
1552
  var DATASET_HEADER = "X-RelyIO-Dataset";
1553
+ var END_USER_HEADER = HEADER_END_USER.name;
1510
1554
  function derivedPreviewIn(headers) {
1511
1555
  const dataset = headerValue(headers, DATASET_HEADER);
1512
1556
  return dataset !== void 0 && isDerivedPreview(dataset) ? dataset : void 0;
@@ -1525,7 +1569,7 @@ function connectionFor(config) {
1525
1569
  const defaultHeaders = layerHeaders(
1526
1570
  layerHeaders({ "Content-Type": "application/json" }, config.headers),
1527
1571
  {
1528
- [API_KEY_HEADER]: presentKey(config.apiKey),
1572
+ [API_KEY_HEADER]: presentCredential(config.apiKey),
1529
1573
  [DATASET_HEADER]: config.dataset,
1530
1574
  // Only outside a browser, which controls this header. "A browser" is the core's one
1531
1575
  // definition, `isBrowser()` — every environment question in this file asks it.
@@ -1557,10 +1601,10 @@ function layerHeaders(base, over) {
1557
1601
  return layered;
1558
1602
  }
1559
1603
  __name(layerHeaders, "layerHeaders");
1560
- function presentKey(value) {
1604
+ function presentCredential(value) {
1561
1605
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
1562
1606
  }
1563
- __name(presentKey, "presentKey");
1607
+ __name(presentCredential, "presentCredential");
1564
1608
  function credentialsModeFor(includeCredentials) {
1565
1609
  return includeCredentials ? "include" : "same-origin";
1566
1610
  }
@@ -1972,6 +2016,18 @@ var _ContentClient = class _ContentClient extends EntryHandle {
1972
2016
  __name(_ContentClient, "ContentClient");
1973
2017
  var ContentClient = _ContentClient;
1974
2018
 
2019
+ // src/errors/mime-matches.ts
2020
+ function mimeMatches(fileType, pattern) {
2021
+ const actual = (fileType.split(";")[0] ?? "").trim().toLowerCase();
2022
+ const allowed = (pattern.split(";")[0] ?? "").trim().toLowerCase();
2023
+ if (allowed === "*" || allowed === "*/*") return true;
2024
+ if (allowed === actual) return true;
2025
+ const [allowedType, allowedSubtype] = allowed.split("/");
2026
+ const [actualType] = actual.split("/");
2027
+ return allowedSubtype === "*" && allowedType === actualType;
2028
+ }
2029
+ __name(mimeMatches, "mimeMatches");
2030
+
1975
2031
  // src/errors/file-errors.ts
1976
2032
  var _FileUploadError = class _FileUploadError extends SDKError {
1977
2033
  constructor(code, message, options = {}) {
@@ -2002,12 +2058,13 @@ var FileValidationError = _FileValidationError;
2002
2058
  function validateFile(file, constraints = {}) {
2003
2059
  const violations = [];
2004
2060
  const { allowedMimeTypes, maxSizeBytes } = constraints;
2005
- if (allowedMimeTypes && allowedMimeTypes.length > 0 && file.type != null && file.type !== "" && !allowedMimeTypes.includes(file.type)) {
2061
+ const { type } = file;
2062
+ if (allowedMimeTypes && allowedMimeTypes.length > 0 && type != null && type !== "" && !allowedMimeTypes.some((pattern) => mimeMatches(type, pattern))) {
2006
2063
  violations.push({
2007
2064
  field: "file",
2008
2065
  code: "UNSUPPORTED_MIME",
2009
- message: `Unsupported file type "${file.type}". Allowed: ${allowedMimeTypes.join(", ")}`,
2010
- value: file.type
2066
+ message: `Unsupported file type "${type}". Allowed: ${allowedMimeTypes.join(", ")}`,
2067
+ value: type
2011
2068
  });
2012
2069
  }
2013
2070
  if (typeof maxSizeBytes === "number" && maxSizeBytes > 0 && typeof file.size === "number" && file.size > maxSizeBytes) {
@@ -2876,7 +2933,8 @@ var _RecordsClient = class _RecordsClient {
2876
2933
  * Store a Record, live the moment it lands. Values that break the Record type's fields are
2877
2934
  * refused with `ValidationError` naming each field, and nothing is stored. Values a unique set of
2878
2935
  * the type claims, held by another Record, are refused with `ResourceConflictError` — its
2879
- * `blockage` is `{ kind: 'value-taken', facts: { fields, recordId } }` (REL-3782).
2936
+ * `blockage` is `{ kind: 'value-taken', facts: { fields, recordId } }` (REL-3782) — with no
2937
+ * `recordId` for an End user's write, whose read Policy may hide the holder (REL-3863).
2880
2938
  */
2881
2939
  async create(fields, options = {}) {
2882
2940
  return this.httpClient.fetchPayload(
@@ -4117,6 +4175,9 @@ function validateConfig(config) {
4117
4175
  if (config.webSocket != null && typeof config.webSocket !== "function") {
4118
4176
  throw new Error("webSocket must be a WebSocket class");
4119
4177
  }
4178
+ if (config.getToken != null && typeof config.getToken !== "function") {
4179
+ throw new Error("getToken must be a function that answers the End user\u2019s token, or null");
4180
+ }
4120
4181
  if (config.timeout != null) assertRequestTimeout(config.timeout);
4121
4182
  if (config.retryAttempts != null && !(Number.isInteger(config.retryAttempts) && config.retryAttempts >= 1)) {
4122
4183
  throw new Error(
@@ -4245,7 +4306,10 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4245
4306
  * `createClient()` made, which reads its own.
4246
4307
  */
4247
4308
  __publicField(this, "parent");
4248
- /** What `with()` gave this client over its parent's: the locale and dataset it names, and no other. */
4309
+ /**
4310
+ * What `with()` gave this client over its parent's: the locale, dataset and End user's token
4311
+ * function it names, and no other.
4312
+ */
4249
4313
  __publicField(this, "defaults", {});
4250
4314
  /** The live edge's poll client id: chosen once, when first needed, and kept for this client's life. */
4251
4315
  __publicField(this, "_liveClientId");
@@ -4256,7 +4320,9 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4256
4320
  * all or none (REL-3774).
4257
4321
  *
4258
4322
  * A Record is an app's data, written by your server with a secret key and live the moment it
4259
- * lands; a publishable key is refused on every Record route (`PUBLISHABLE_KEY_REFUSED`).
4323
+ * lands. A publishable key reads the Records a Record type's read Policy grants it (spec 4,
4324
+ * REL-3883), and writes them only for the End user whose token it carries, as the type's write
4325
+ * Policy allows (REL-3884); with no token it writes nothing (`PUBLISHABLE_KEY_REFUSED`).
4260
4326
  *
4261
4327
  * @example
4262
4328
  * ```typescript
@@ -4284,9 +4350,13 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4284
4350
  * `FunctionRunFailedError` and one past five minutes `FunctionRunTimedOutError`, each naming the
4285
4351
  * run. Never retried: a Function may write.
4286
4352
  *
4353
+ * Once `relyio generate-types` has run, its `schema.ts` registers each Function's input and output
4354
+ * Fields (REL-4059): only the project's Functions are named here, and each call takes and answers
4355
+ * what its Fields declare, so a misnamed or mistyped input field is a type error.
4356
+ *
4287
4357
  * @example
4288
4358
  * ```typescript
4289
- * const { orderId } = (await relyio.functions.checkout({ cartId })) as { orderId: string }
4359
+ * const { orderId } = await relyio.functions.checkout({ cartId })
4290
4360
  * ```
4291
4361
  */
4292
4362
  // Read when called, never when made: `with()` and `updateConfig()` move `httpClient`
@@ -4740,6 +4810,9 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4740
4810
  * const { data } = await staging.content('post').list({ limit: 10 })
4741
4811
  *
4742
4812
  * const french = relyio.with({ locale: 'fr-FR' }) // ← autocompletes the schema's locales
4813
+ *
4814
+ * // Every request this one sends carries the signed-in End user's token (REL-3882)
4815
+ * const visitor = relyio.with({ getToken: () => session.getToken() })
4743
4816
  * ```
4744
4817
  */
4745
4818
  with(defaults) {
@@ -4753,14 +4826,16 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
4753
4826
  }
4754
4827
  /** Make this client one `with()` made from `parent`: see {@link with}. */
4755
4828
  follow(parent, defaults) {
4756
- const { locale, dataset } = defaults;
4829
+ const { locale, dataset, getToken } = defaults;
4757
4830
  this.parent = parent;
4758
4831
  this.defaults = {
4759
4832
  ...locale === void 0 ? {} : { locale },
4760
- ...dataset === void 0 ? {} : { dataset }
4833
+ ...dataset === void 0 ? {} : { dataset },
4834
+ ...getToken === void 0 ? {} : { getToken }
4761
4835
  };
4762
4836
  this.httpClient = parent.httpClient.withHeaders(
4763
- dataset === void 0 ? {} : { [DATASET_HEADER]: dataset }
4837
+ dataset === void 0 ? {} : { [DATASET_HEADER]: dataset },
4838
+ getToken === void 0 ? {} : { getToken }
4764
4839
  );
4765
4840
  }
4766
4841
  /**
@@ -4811,6 +4886,6 @@ function randomClientId() {
4811
4886
  }
4812
4887
  __name(randomClientId, "randomClientId");
4813
4888
 
4814
- export { AssetClient, AssetFileBuilder, AssetUploadBuilder, AuthorizationError, BaseValidationError, ChangesExpiredError, ConnectionError, ContentClient, DefaultRetryPolicy, ErrorMapper, FileUploadError, FileValidationError, FunctionContainersBusyError, FunctionRunFailedError, FunctionRunTimedOutError, HttpClient, InvalidApiKeyError, InvalidPayloadError, LIVE_KEEPALIVE_INTERVAL_MS, LIVE_SOCKET_OPEN_TIMEOUT_MS, LiveEdgeError, MethodNotAllowedError, MissingApiKeyError, NetworkError, PREVIEW_KEY_PREFIX, PUBLISHABLE_KEY_PREFIX, PayloadTooLargeError, PlanFeatureUnavailableError, PublishableKeyRefusedError, RateLimitError, ReadOnlyKeyError, RecordsClient, ResourceConflictError, ResourceExpiredError, ResourceNotFoundError, SDKError, ServerError, ServiceIndeterminateError, SettingsClient, SingletonClient, TimeoutError, TransactionRolledBackError, TypedRelyIOClient, UnknownContractError, UsageQuotaExceededError, ValidationError, createClient, isAborted, isAssetEntry, isMissingEntry, isPreviewKey, isPublishableKey, isReplaySafe, isResourceNotFound, matchRoute, refusedOperationOf, retryPolicyFor, serviceInstructedDelayMs, sleep, validateFile, versionCheckOf };
4815
- //# sourceMappingURL=chunk-ZHTJ7GXH.js.map
4816
- //# sourceMappingURL=chunk-ZHTJ7GXH.js.map
4889
+ export { AssetClient, AssetFileBuilder, AssetUploadBuilder, AuthorizationError, BaseValidationError, ChangesExpiredError, ConnectionError, ContentClient, DefaultRetryPolicy, EndUserTokenInvalidError, ErrorMapper, FileUploadError, FileValidationError, FunctionContainersBusyError, FunctionRunFailedError, FunctionRunTimedOutError, HttpClient, InvalidApiKeyError, InvalidPayloadError, LIVE_KEEPALIVE_INTERVAL_MS, LIVE_SOCKET_OPEN_TIMEOUT_MS, LiveEdgeError, MethodNotAllowedError, MissingApiKeyError, NetworkError, PREVIEW_KEY_PREFIX, PUBLISHABLE_KEY_PREFIX, PayloadTooLargeError, PlanFeatureUnavailableError, PublishableKeyRefusedError, RateLimitError, ReadOnlyKeyError, RecordsClient, ResourceConflictError, ResourceExpiredError, ResourceNotFoundError, SDKError, ServerError, ServiceIndeterminateError, SettingsClient, SingletonClient, TimeoutError, TransactionRolledBackError, TypedRelyIOClient, UnknownContractError, UsageQuotaExceededError, ValidationError, createClient, isAborted, isAssetEntry, isMissingEntry, isPreviewKey, isPublishableKey, isReplaySafe, isResourceNotFound, matchRoute, refusedOperationOf, retryPolicyFor, serviceInstructedDelayMs, sleep, validateFile, versionCheckOf };
4890
+ //# sourceMappingURL=chunk-L42C4G2S.js.map
4891
+ //# sourceMappingURL=chunk-L42C4G2S.js.map
@@ -51,6 +51,26 @@ function refuseMismatchedAlternate(route, stream) {
51
51
  }
52
52
  __name(refuseMismatchedAlternate, "refuseMismatchedAlternate");
53
53
 
54
+ // ../../platform/api-contract/dist/chunk-4KRF3DVJ.js
55
+ var HEADER_END_USER = {
56
+ name: "X-RelyIO-End-User",
57
+ in: "request",
58
+ required: false
59
+ };
60
+ var END_USER_TOKEN_REFUSAL_REASONS = [
61
+ "missing",
62
+ "no-identity-source",
63
+ "malformed",
64
+ "unsupported-algorithm",
65
+ "wrong-issuer",
66
+ "unknown-key",
67
+ "bad-signature",
68
+ "wrong-audience",
69
+ "expired",
70
+ "not-yet-valid",
71
+ "missing-subject"
72
+ ];
73
+
54
74
  // ../../platform/api-contract/dist/index.js
55
75
  var HEADER_RETRY_AFTER = { name: "Retry-After" };
56
76
  var HEADER_IF_MATCH = {
@@ -398,6 +418,26 @@ var STRIPE_EVENT_FIELDS = [
398
418
  { path: "data.object.object", type: "string", required: true },
399
419
  { path: "data.object.metadata", type: "object", required: false, values: "string" }
400
420
  ];
421
+ var STRIPE_SUBSCRIPTION_FIELDS = [
422
+ ...STRIPE_EVENT_FIELDS,
423
+ { path: "data.object.status", type: "string", required: true },
424
+ { path: "data.object.customer", type: "string", required: true },
425
+ { path: "data.object.cancel_at_period_end", type: "boolean", required: false },
426
+ { path: "data.object.cancel_at", type: "number", required: false },
427
+ { path: "data.object.canceled_at", type: "number", required: false },
428
+ { path: "data.object.ended_at", type: "number", required: false },
429
+ { path: "data.object.start_date", type: "number", required: false },
430
+ { path: "data.object.trial_end", type: "number", required: false }
431
+ ];
432
+ var IDENTITY_CLAIMS_SETTING = "claims";
433
+ var IDENTITY_CLAIMS_SETTING_FIELD = {
434
+ key: IDENTITY_CLAIMS_SETTING,
435
+ label: "Claims",
436
+ type: "text",
437
+ maxLength: 512,
438
+ required: false,
439
+ helpText: "The Claims your Policies read off an End user\u2019s token, by name, separated by commas: `plan, role`. A Claim not named here is never read; one named and missing from a token is absent."
440
+ };
401
441
  var EXTENSION_SURFACES = {
402
442
  webhook: {
403
443
  settings: [],
@@ -447,7 +487,9 @@ var EXTENSION_SURFACES = {
447
487
  }
448
488
  }
449
489
  },
450
- triggers: {}
490
+ triggers: {},
491
+ fieldKinds: {},
492
+ recordTypes: {}
451
493
  },
452
494
  vercel: {
453
495
  settings: [],
@@ -466,7 +508,9 @@ var EXTENSION_SURFACES = {
466
508
  { path: "payload.target", type: "string", required: false }
467
509
  ]
468
510
  }
469
- }
511
+ },
512
+ fieldKinds: {},
513
+ recordTypes: {}
470
514
  },
471
515
  netlify: {
472
516
  settings: [],
@@ -486,11 +530,14 @@ var EXTENSION_SURFACES = {
486
530
  { path: "deploy_ssl_url", type: "string", required: false }
487
531
  ]
488
532
  }
489
- }
533
+ },
534
+ fieldKinds: {},
535
+ recordTypes: {}
490
536
  },
491
- // Triggers only in slice one (spec 3, REL-3853): Stripe tells RelyIO a payment succeeded, failed, a
492
- // Checkout completed or a charge was refunded. No Action: checkout keeps calling Stripe from a
493
- // Function with its own Secret (spec 2).
537
+ // Triggers only (spec 3, REL-3853): Stripe tells RelyIO a payment succeeded, failed, a Checkout
538
+ // completed or a charge was refunded — and, since spec 4 (REL-3893), that a subscription was
539
+ // created, changed or ended. No Action: checkout keeps calling Stripe from a Function with its own
540
+ // Secret (spec 2).
494
541
  stripe: {
495
542
  settings: [],
496
543
  actions: {},
@@ -544,8 +591,26 @@ var EXTENSION_SURFACES = {
544
591
  { path: "data.object.refunded", type: "boolean", required: true },
545
592
  { path: "data.object.payment_intent", type: "string", required: false }
546
593
  ]
594
+ },
595
+ customerSubscriptionCreated: {
596
+ trigger: "customer.subscription.created",
597
+ payload: STRIPE_SUBSCRIPTION_FIELDS
598
+ },
599
+ customerSubscriptionUpdated: {
600
+ trigger: "customer.subscription.updated",
601
+ payload: [
602
+ ...STRIPE_SUBSCRIPTION_FIELDS,
603
+ // The status it had before this change, when the change was to its status
604
+ { path: "data.previous_attributes.status", type: "string", required: false }
605
+ ]
606
+ },
607
+ customerSubscriptionDeleted: {
608
+ trigger: "customer.subscription.deleted",
609
+ payload: STRIPE_SUBSCRIPTION_FIELDS
547
610
  }
548
- }
611
+ },
612
+ fieldKinds: {},
613
+ recordTypes: {}
549
614
  },
550
615
  slack: {
551
616
  settings: [
@@ -609,7 +674,9 @@ var EXTENSION_SURFACES = {
609
674
  }
610
675
  }
611
676
  },
612
- triggers: {}
677
+ triggers: {},
678
+ fieldKinds: {},
679
+ recordTypes: {}
613
680
  },
614
681
  // Resend (spec 3, REL-3854): an email, its Files attached. The sender is the step's, else the
615
682
  // Project's `from`; `html` or `text` is the body, at least one of them.
@@ -677,10 +744,105 @@ var EXTENSION_SURFACES = {
677
744
  }
678
745
  }
679
746
  },
680
- triggers: {}
747
+ triggers: {},
748
+ fieldKinds: {},
749
+ recordTypes: {}
750
+ },
751
+ /**
752
+ * The plain OIDC identity source (spec 4, REL-3880): any issuer that publishes a discovery
753
+ * document — Auth0, Supabase Auth, an own one. Its Connection, per Environment, holds the issuer
754
+ * and the audience; it has no Action and no Trigger. Its one setting is the Claims the Project
755
+ * relies on ({@link IDENTITY_CLAIMS_SETTING}).
756
+ */
757
+ oidc: {
758
+ settings: [IDENTITY_CLAIMS_SETTING_FIELD],
759
+ actions: {},
760
+ triggers: {},
761
+ fieldKinds: {},
762
+ recordTypes: {}
763
+ },
764
+ /**
765
+ * Clerk as an identity source (spec 4, REL-3881): its Connection, per Environment, holds the
766
+ * instance's publishable key — which encodes the Frontend API, and so the issuer — its secret key,
767
+ * its webhook signing secret and the origins its tokens may be minted for. Its one setting so far
768
+ * is the Claims the Project relies on, as `oidc`'s; its Triggers come with its users (spec 4, E3).
769
+ *
770
+ * Its Action, `updateUserMetadata` (REL-3893), merges `publicMetadata` into a Clerk user's public
771
+ * metadata with the Connection's secret key — the newsletter's `syncPlan` sets `{ plan: 'paid' }` —
772
+ * and a session token carries it once the customer adds the Claim to Clerk's session token
773
+ * (`"plan": "{{user.public_metadata.plan}}"`, the Clerk Extension's guide).
774
+ */
775
+ clerk: {
776
+ settings: [IDENTITY_CLAIMS_SETTING_FIELD],
777
+ actions: {
778
+ updateUserMetadata: {
779
+ action: "updateUserMetadata",
780
+ step: {
781
+ input: [
782
+ {
783
+ key: "userId",
784
+ type: "text",
785
+ required: true,
786
+ description: "The Clerk user\u2019s id, `user_\u2026`: a token\u2019s `sub`."
787
+ },
788
+ {
789
+ key: "publicMetadata",
790
+ type: "json",
791
+ required: true,
792
+ description: "An object merged into the user\u2019s public metadata: each key given replaces theirs, a nested object is merged, and a key set to `null` is removed. Keys not given are kept."
793
+ }
794
+ ],
795
+ output: [
796
+ {
797
+ key: "id",
798
+ type: "text",
799
+ required: true,
800
+ description: "The id of the user Clerk updated."
801
+ }
802
+ ],
803
+ sample: { id: "user_sample" },
804
+ // Clerk's Backend API keys nothing to dedupe a request on: an update that succeeded is never
805
+ // sent again, and one whose outcome is unknown is not either.
806
+ idempotencyHeader: null
807
+ }
808
+ }
809
+ },
810
+ triggers: {},
811
+ /**
812
+ * Its one field kind (REL-3894): `clerk.userRef()`, a reference to `clerkUser` that the Studio
813
+ * picks by name or email rather than by pasting an id.
814
+ */
815
+ fieldKinds: {
816
+ userRef: {
817
+ base: { type: "reference", to: "clerkUser" },
818
+ picker: {
819
+ search: ["email", "firstName", "lastName"],
820
+ title: ["firstName", "lastName"],
821
+ description: "email",
822
+ image: "imageUrl"
823
+ }
824
+ }
825
+ },
826
+ /** Its Managed user type (REL-3888): `clerk.user`, the Record kept for each Clerk user. */
827
+ recordTypes: { user: "clerkUser" }
681
828
  }
682
829
  };
830
+ var CONTRIBUTED_FIELD_KIND_OPTION = "fieldKind";
831
+ function contributedFieldKindName(extension, kind) {
832
+ return `${extension}.${kind}`;
833
+ }
834
+ __name(contributedFieldKindName, "contributedFieldKindName");
835
+ var EXTENSION_BACKFILL_REFUSALS = [
836
+ "connection-gone",
837
+ "connection-inactive",
838
+ "connection-unreadable",
839
+ "vendor-refused",
840
+ "vendor-unavailable",
841
+ "vendor-answer-unreadable",
842
+ "extension-not-backfilled"
843
+ ];
844
+ new Set(EXTENSION_BACKFILL_REFUSALS);
683
845
 
684
- export { EXTENSION_SURFACES, FRESH_PARAMETER, HEADER_IDEMPOTENCY_KEY, HEADER_IF_MATCH, HEADER_RETRY_AFTER, PREVIEW_DATASET_PREFIX, VISITOR_ADMISSION_RETRY_AFTER_SECONDS, VISITOR_CLOSE_CODES, VISITOR_CLOSE_RETRY, VISITOR_FRAMES, VISITOR_KEEPALIVE, VISITOR_LIVE_PATH, VISITOR_POLL_INTERVAL_MS, VISITOR_POLL_RETRY, VISITOR_QUERY, entityTag, parseVisitorFrame, previewDatasetSlug, readVisitorPollAnswer };
685
- //# sourceMappingURL=chunk-EDE2H37D.js.map
686
- //# sourceMappingURL=chunk-EDE2H37D.js.map
846
+ export { CONTRIBUTED_FIELD_KIND_OPTION, END_USER_TOKEN_REFUSAL_REASONS, EXTENSION_SURFACES, FRESH_PARAMETER, HEADER_END_USER, HEADER_IDEMPOTENCY_KEY, HEADER_IF_MATCH, HEADER_RETRY_AFTER, PREVIEW_DATASET_PREFIX, VISITOR_ADMISSION_RETRY_AFTER_SECONDS, VISITOR_CLOSE_CODES, VISITOR_CLOSE_RETRY, VISITOR_FRAMES, VISITOR_KEEPALIVE, VISITOR_LIVE_PATH, VISITOR_POLL_INTERVAL_MS, VISITOR_POLL_RETRY, VISITOR_QUERY, contributedFieldKindName, entityTag, parseVisitorFrame, previewDatasetSlug, readVisitorPollAnswer };
847
+ //# sourceMappingURL=chunk-OUR7OUUZ.js.map
848
+ //# sourceMappingURL=chunk-OUR7OUUZ.js.map