@relyio/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.
@@ -536,6 +536,14 @@ function defineView(id, config) {
536
536
  if (!config.scope?.type) {
537
537
  throw new Error(`View '${id}' must have a valid scope`);
538
538
  }
539
+ const grouped = (config.filters ?? []).findIndex(
540
+ (filter) => typeof filter === "object" && filter !== null && "conditions" in filter
541
+ );
542
+ if (grouped !== -1) {
543
+ throw new Error(
544
+ `View '${id}' filter ${grouped} is a filter group: a view's filters are a flat list, joined by AND. List each of its conditions as a filter of its own, or use 'isAnyOf' for an OR within one field.`
545
+ );
546
+ }
539
547
  if (config.slug !== void 0 && !/^[a-z][a-z0-9-]*$/.test(config.slug)) {
540
548
  throw new Error(
541
549
  `View '${id}' slug '${config.slug}' must be lowercase, start with a letter, and contain only letters, numbers, and hyphens`
@@ -717,5 +725,5 @@ exports.isLocaleDefinition = isLocaleDefinition;
717
725
  exports.isRoleDefinition = isRoleDefinition;
718
726
  exports.isWorkflowDefinition = isWorkflowDefinition;
719
727
  exports.isWorkflowStageDefinition = isWorkflowStageDefinition;
720
- //# sourceMappingURL=chunk-72UK5U7T.cjs.map
721
- //# sourceMappingURL=chunk-72UK5U7T.cjs.map
728
+ //# sourceMappingURL=chunk-2HP566NI.cjs.map
729
+ //# sourceMappingURL=chunk-2HP566NI.cjs.map
@@ -410,7 +410,7 @@ var _InvalidPayloadError = class _InvalidPayloadError extends BaseValidationErro
410
410
  __name(_InvalidPayloadError, "InvalidPayloadError");
411
411
  var InvalidPayloadError = _InvalidPayloadError;
412
412
 
413
- // ../../platform/api-contract/dist/chunk-PYZCLRXR.js
413
+ // ../../platform/api-contract/dist/chunk-46347LG2.js
414
414
  function defineRoute(route) {
415
415
  if (route.kind === "raw" && route.standardShape === void 0) {
416
416
  throw new Error("kind 'raw' requires a named StandardShape");
@@ -424,6 +424,16 @@ function defineRoute(route) {
424
424
  if (route.kind === "collection" && route.page === void 0) {
425
425
  throw new Error("kind 'collection' requires a page dialect");
426
426
  }
427
+ if (route.queues === true) {
428
+ if (route.kind !== "object" && route.kind !== "empty") {
429
+ throw new Error(
430
+ `kind '${route.kind}' cannot declare \`queues\`: only an object or empty route answers 202 beside its own status`
431
+ );
432
+ }
433
+ if (route.kind === "object" && route.success === 202) {
434
+ throw new Error("a route whose own status is 202 cannot also declare `queues`");
435
+ }
436
+ }
427
437
  if ((route.kind === "object" || route.kind === "collection") && route.negotiated !== void 0) {
428
438
  refuseMismatchedAlternate(route, route.negotiated["text/event-stream"]);
429
439
  }
@@ -895,6 +905,7 @@ var DECLARED_PATHS = {
895
905
  "/internal/media/resolve": true,
896
906
  "/internal/usage/cycle": true,
897
907
  "/internal/usage/ingest": true,
908
+ "/internal/usage/stops": true,
898
909
  "/v1/{contentType}": true,
899
910
  "/v1/{contentType}/{id}": true,
900
911
  "/v1/{contentType}/{id}/children": true,
@@ -4862,6 +4873,7 @@ async function* pollChanges(http, options = {}) {
4862
4873
  const { signal } = options;
4863
4874
  let since = options.since;
4864
4875
  let resynced;
4876
+ let starting = since === void 0;
4865
4877
  for (; ; ) {
4866
4878
  if (isAborted(signal)) return;
4867
4879
  let response;
@@ -4892,6 +4904,10 @@ async function* pollChanges(http, options = {}) {
4892
4904
  yield { ...change, fresh: change.cursor };
4893
4905
  if (isAborted(signal)) return;
4894
4906
  }
4907
+ if (starting) {
4908
+ starting = false;
4909
+ options.reached?.(page.nextCursor);
4910
+ }
4895
4911
  if (data.length === 0) {
4896
4912
  const wait = parseRetryAfterMs(headerValue(response.headers, "Retry-After"), Date.now());
4897
4913
  if (wait !== void 0 && wait > 0) await sleep(wait, signal);
@@ -5019,23 +5035,12 @@ __name(originOf, "originOf");
5019
5035
 
5020
5036
  // src/changes/live-edge.ts
5021
5037
  var LIVE_KEEPALIVE_INTERVAL_MS = 3e4;
5038
+ var LIVE_SOCKET_OPEN_TIMEOUT_MS = VISITOR_POLL_INTERVAL_MS;
5022
5039
  var LIVE_POLLS_BEFORE_SOCKET = 4;
5023
5040
  async function* subscribeLiveEdge(client, options = {}) {
5024
5041
  const { signal } = options;
5025
5042
  if (isAborted(signal)) return;
5026
- const key = client.apiKey;
5027
- if (key === void 0 || !isPublishableKey(key)) {
5028
- throw new LiveEdgeError(NEEDS_PUBLISHABLE_KEY, { kind: "needs-publishable-key" }, "stop");
5029
- }
5030
- const address = liveEdgeAddress(client);
5031
- if (!address.ok) throw new LiveEdgeError(address.message, { kind: "needs-live-url" }, "stop");
5032
- const request = {
5033
- base: address.url,
5034
- key,
5035
- dataset: client.dataset,
5036
- types: options.types,
5037
- ids: options.ids
5038
- };
5043
+ const request = edgeRequest(client, options);
5039
5044
  const reach = { position: options.since };
5040
5045
  for (; ; ) {
5041
5046
  const socket = openSocket(client, edgeUrl(request, reach.position, "socket"));
@@ -5069,6 +5074,7 @@ async function* followSocket(socket, reach, options) {
5069
5074
  const { signal } = options;
5070
5075
  const inbox = socketInbox(socket, signal);
5071
5076
  let open = false;
5077
+ let caughtUp = false;
5072
5078
  try {
5073
5079
  for (; ; ) {
5074
5080
  const event = await inbox.next();
@@ -5094,6 +5100,10 @@ async function* followSocket(socket, reach, options) {
5094
5100
  "retry"
5095
5101
  );
5096
5102
  }
5103
+ case "late": {
5104
+ if (caughtUp) continue;
5105
+ return "unopened";
5106
+ }
5097
5107
  case "message": {
5098
5108
  if (event.data === VISITOR_KEEPALIVE.response) continue;
5099
5109
  const frame = typeof event.data === "string" ? parseVisitorFrame(event.data) : null;
@@ -5101,6 +5111,8 @@ async function* followSocket(socket, reach, options) {
5101
5111
  throw unreadable(`a frame the wire does not declare: ${sample(event.data)}`);
5102
5112
  switch (frame.type) {
5103
5113
  case VISITOR_FRAMES.opened: {
5114
+ caughtUp = true;
5115
+ inbox.caughtUp();
5104
5116
  reach.position = frame.cursor;
5105
5117
  options.opened?.();
5106
5118
  options.reached?.(frame.cursor);
@@ -5167,6 +5179,10 @@ function socketInbox(socket, signal) {
5167
5179
  });
5168
5180
  socket.addEventListener("error", () => push({ kind: "error" }));
5169
5181
  signal?.addEventListener("abort", rouse, { once: true });
5182
+ let connecting = setTimeout(() => {
5183
+ connecting = void 0;
5184
+ push({ kind: "late" });
5185
+ }, LIVE_SOCKET_OPEN_TIMEOUT_MS);
5170
5186
  return {
5171
5187
  async next() {
5172
5188
  for (; ; ) {
@@ -5188,8 +5204,13 @@ function socketInbox(socket, signal) {
5188
5204
  if (socket.readyState === SOCKET_OPEN) socket.send(VISITOR_KEEPALIVE.request);
5189
5205
  }, LIVE_KEEPALIVE_INTERVAL_MS);
5190
5206
  },
5207
+ caughtUp() {
5208
+ if (connecting !== void 0) clearTimeout(connecting);
5209
+ connecting = void 0;
5210
+ },
5191
5211
  dispose() {
5192
5212
  disposed = true;
5213
+ if (connecting !== void 0) clearTimeout(connecting);
5193
5214
  if (keepalive !== void 0) clearInterval(keepalive);
5194
5215
  signal?.removeEventListener("abort", rouse);
5195
5216
  if (socket.readyState === SOCKET_CONNECTING || socket.readyState === SOCKET_OPEN) {
@@ -5225,7 +5246,9 @@ var CLOSE_MEANING = {
5225
5246
  [VISITOR_CLOSE_CODES.keyRefused]: "the key is not a publishable key the edge accepts \u2014 unknown, revoked or expired",
5226
5247
  [VISITOR_CLOSE_CODES.originRefused]: "this page\u2019s origin is not on the publishable key\u2019s allowed origins",
5227
5248
  [VISITOR_CLOSE_CODES.datasetRefused]: "`dataset` names no dataset the key reaches",
5228
- [VISITOR_CLOSE_CODES.unavailable]: "the edge could not reach what it needed to decide just now",
5249
+ // Also how the edge hands a connection on when the project's live objects move to another
5250
+ // placement (reason `moved`, REL-1514): either way the same request succeeds again shortly.
5251
+ [VISITOR_CLOSE_CODES.unavailable]: "the edge could not serve this connection just now \u2014 it could not reach what it needed, or it moved the project\u2019s live connections elsewhere",
5229
5252
  [VISITOR_CLOSE_CODES.allowanceReached]: "the project holds as many live connections as its plan allows",
5230
5253
  [VISITOR_CLOSE_CODES.addressLimitReached]: "this address holds as many live connections to the project as one address may",
5231
5254
  [VISITOR_CLOSE_CODES.ceilingReached]: "the project is at its safety ceiling of live connections"
@@ -5332,6 +5355,22 @@ function refusedPoll(response, body, context) {
5332
5355
  );
5333
5356
  }
5334
5357
  __name(refusedPoll, "refusedPoll");
5358
+ function edgeRequest(client, filter) {
5359
+ const key = client.apiKey;
5360
+ if (key === void 0 || !isPublishableKey(key)) {
5361
+ throw new LiveEdgeError(NEEDS_PUBLISHABLE_KEY, { kind: "needs-publishable-key" }, "stop");
5362
+ }
5363
+ const address = liveEdgeAddress(client);
5364
+ if (!address.ok) throw new LiveEdgeError(address.message, { kind: "needs-live-url" }, "stop");
5365
+ return {
5366
+ base: address.url,
5367
+ key,
5368
+ dataset: client.dataset,
5369
+ types: filter.types,
5370
+ ids: filter.ids
5371
+ };
5372
+ }
5373
+ __name(edgeRequest, "edgeRequest");
5335
5374
  function edgeUrl(request, since, transport, clientId) {
5336
5375
  const url = new URL(request.base.href);
5337
5376
  url.pathname = `${url.pathname.replace(/\/+$/, "")}${VISITOR_LIVE_PATH}`;
@@ -5892,9 +5931,14 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
5892
5931
  * (`rly_pub_…`): each change as ids, in order — the transport a browser follows changes with.
5893
5932
  *
5894
5933
  * A WebSocket to the edge, from `since` or the dataset's current position; where a socket cannot
5895
- * open — the runtime has none, or the network refuses it — it polls the edge instead, about every
5896
- * fifteen seconds, from the same cursor. The edge is `liveUrl`, or derived from the default
5897
- * `baseUrl` (see `RelyIOConfig.liveUrl`).
5934
+ * open — the runtime has none, the network refuses it, or it has not opened and been told its
5935
+ * position within `LIVE_SOCKET_OPEN_TIMEOUT_MS` — it polls the edge instead, about every fifteen
5936
+ * seconds, from the same cursor. The edge is `liveUrl`, or derived from the default `baseUrl`
5937
+ * (see `RelyIOConfig.liveUrl`).
5938
+ *
5939
+ * Without `since` it starts at the dataset's current position, which it hands `reached` before
5940
+ * anything after it: read what you show after that call, and a publish your read did not see is
5941
+ * one this subscription announces (see `LiveChangesOptions.since`).
5898
5942
  *
5899
5943
  * One subscription ends only when `signal` aborts, which ends the `for await` cleanly; every other
5900
5944
  * end — a socket a deploy dropped, a refusal, a refused poll — is thrown as a `LiveEdgeError`
@@ -6240,6 +6284,6 @@ function randomClientId() {
6240
6284
  }
6241
6285
  __name(randomClientId, "randomClientId");
6242
6286
 
6243
- export { AdhocQueryBuilder, AdhocQueryClient, AssetClient, AssetFileBuilder, AssetUploadBuilder, AuthorizationError, AutocompleteBuilder, BaseValidationError, BatchBuilder, BatchClient, ChangesExpiredError, ConnectionError, ContentByIdBuilder, ContentClient, ContentQueryBuilder, ErrorMapper, FileUploadError, FileValidationError, HttpClient, InvalidApiKeyError, InvalidPayloadError, LIVE_KEEPALIVE_INTERVAL_MS, LiveEdgeError, MethodNotAllowedError, MissingApiKeyError, NetworkError, PUBLISHABLE_KEY_PREFIX, PayloadTooLargeError, PlanFeatureUnavailableError, RateLimitError, ReadOnlyKeyError, ResourceConflictError, ResourceExpiredError, ResourceNotFoundError, SDKError, SearchBuilder, SearchClient, ServerError, ServiceIndeterminateError, SettingsClient, SimilarBuilder, SingletonClient, TimeoutError, TransactionRolledBackError, TypedRelyIOClient, UnknownContractError, UsageQuotaExceededError, VISITOR_ADMISSION_RETRY_AFTER_SECONDS, ValidationError, createClient, entityTagOf, isAborted, isAssetEntry, isPublishableKey, isResourceNotFound, matchRoute, serviceInstructedDelayMs, sleep, validateFile };
6244
- //# sourceMappingURL=chunk-QFHVF3YF.js.map
6245
- //# sourceMappingURL=chunk-QFHVF3YF.js.map
6287
+ export { AdhocQueryBuilder, AdhocQueryClient, AssetClient, AssetFileBuilder, AssetUploadBuilder, AuthorizationError, AutocompleteBuilder, BaseValidationError, BatchBuilder, BatchClient, ChangesExpiredError, ConnectionError, ContentByIdBuilder, ContentClient, ContentQueryBuilder, ErrorMapper, FileUploadError, FileValidationError, HttpClient, InvalidApiKeyError, InvalidPayloadError, LIVE_KEEPALIVE_INTERVAL_MS, LIVE_SOCKET_OPEN_TIMEOUT_MS, LiveEdgeError, MethodNotAllowedError, MissingApiKeyError, NetworkError, PUBLISHABLE_KEY_PREFIX, PayloadTooLargeError, PlanFeatureUnavailableError, RateLimitError, ReadOnlyKeyError, ResourceConflictError, ResourceExpiredError, ResourceNotFoundError, SDKError, SearchBuilder, SearchClient, ServerError, ServiceIndeterminateError, SettingsClient, SimilarBuilder, SingletonClient, TimeoutError, TransactionRolledBackError, TypedRelyIOClient, UnknownContractError, UsageQuotaExceededError, VISITOR_ADMISSION_RETRY_AFTER_SECONDS, ValidationError, createClient, entityTagOf, isAborted, isAssetEntry, isPublishableKey, isResourceNotFound, matchRoute, serviceInstructedDelayMs, sleep, validateFile };
6288
+ //# sourceMappingURL=chunk-2L5JUW7O.js.map
6289
+ //# sourceMappingURL=chunk-2L5JUW7O.js.map
@@ -412,7 +412,7 @@ var _InvalidPayloadError = class _InvalidPayloadError extends BaseValidationErro
412
412
  chunkMWMSFIWN_cjs.__name(_InvalidPayloadError, "InvalidPayloadError");
413
413
  var InvalidPayloadError = _InvalidPayloadError;
414
414
 
415
- // ../../platform/api-contract/dist/chunk-PYZCLRXR.js
415
+ // ../../platform/api-contract/dist/chunk-46347LG2.js
416
416
  function defineRoute(route) {
417
417
  if (route.kind === "raw" && route.standardShape === void 0) {
418
418
  throw new Error("kind 'raw' requires a named StandardShape");
@@ -426,6 +426,16 @@ function defineRoute(route) {
426
426
  if (route.kind === "collection" && route.page === void 0) {
427
427
  throw new Error("kind 'collection' requires a page dialect");
428
428
  }
429
+ if (route.queues === true) {
430
+ if (route.kind !== "object" && route.kind !== "empty") {
431
+ throw new Error(
432
+ `kind '${route.kind}' cannot declare \`queues\`: only an object or empty route answers 202 beside its own status`
433
+ );
434
+ }
435
+ if (route.kind === "object" && route.success === 202) {
436
+ throw new Error("a route whose own status is 202 cannot also declare `queues`");
437
+ }
438
+ }
429
439
  if ((route.kind === "object" || route.kind === "collection") && route.negotiated !== void 0) {
430
440
  refuseMismatchedAlternate(route, route.negotiated["text/event-stream"]);
431
441
  }
@@ -897,6 +907,7 @@ var DECLARED_PATHS = {
897
907
  "/internal/media/resolve": true,
898
908
  "/internal/usage/cycle": true,
899
909
  "/internal/usage/ingest": true,
910
+ "/internal/usage/stops": true,
900
911
  "/v1/{contentType}": true,
901
912
  "/v1/{contentType}/{id}": true,
902
913
  "/v1/{contentType}/{id}/children": true,
@@ -4864,6 +4875,7 @@ async function* pollChanges(http, options = {}) {
4864
4875
  const { signal } = options;
4865
4876
  let since = options.since;
4866
4877
  let resynced;
4878
+ let starting = since === void 0;
4867
4879
  for (; ; ) {
4868
4880
  if (isAborted(signal)) return;
4869
4881
  let response;
@@ -4894,6 +4906,10 @@ async function* pollChanges(http, options = {}) {
4894
4906
  yield { ...change, fresh: change.cursor };
4895
4907
  if (isAborted(signal)) return;
4896
4908
  }
4909
+ if (starting) {
4910
+ starting = false;
4911
+ options.reached?.(page.nextCursor);
4912
+ }
4897
4913
  if (data.length === 0) {
4898
4914
  const wait = parseRetryAfterMs(headerValue(response.headers, "Retry-After"), Date.now());
4899
4915
  if (wait !== void 0 && wait > 0) await sleep(wait, signal);
@@ -5021,23 +5037,12 @@ chunkMWMSFIWN_cjs.__name(originOf, "originOf");
5021
5037
 
5022
5038
  // src/changes/live-edge.ts
5023
5039
  var LIVE_KEEPALIVE_INTERVAL_MS = 3e4;
5040
+ var LIVE_SOCKET_OPEN_TIMEOUT_MS = VISITOR_POLL_INTERVAL_MS;
5024
5041
  var LIVE_POLLS_BEFORE_SOCKET = 4;
5025
5042
  async function* subscribeLiveEdge(client, options = {}) {
5026
5043
  const { signal } = options;
5027
5044
  if (isAborted(signal)) return;
5028
- const key = client.apiKey;
5029
- if (key === void 0 || !isPublishableKey(key)) {
5030
- throw new LiveEdgeError(NEEDS_PUBLISHABLE_KEY, { kind: "needs-publishable-key" }, "stop");
5031
- }
5032
- const address = liveEdgeAddress(client);
5033
- if (!address.ok) throw new LiveEdgeError(address.message, { kind: "needs-live-url" }, "stop");
5034
- const request = {
5035
- base: address.url,
5036
- key,
5037
- dataset: client.dataset,
5038
- types: options.types,
5039
- ids: options.ids
5040
- };
5045
+ const request = edgeRequest(client, options);
5041
5046
  const reach = { position: options.since };
5042
5047
  for (; ; ) {
5043
5048
  const socket = openSocket(client, edgeUrl(request, reach.position, "socket"));
@@ -5071,6 +5076,7 @@ async function* followSocket(socket, reach, options) {
5071
5076
  const { signal } = options;
5072
5077
  const inbox = socketInbox(socket, signal);
5073
5078
  let open = false;
5079
+ let caughtUp = false;
5074
5080
  try {
5075
5081
  for (; ; ) {
5076
5082
  const event = await inbox.next();
@@ -5096,6 +5102,10 @@ async function* followSocket(socket, reach, options) {
5096
5102
  "retry"
5097
5103
  );
5098
5104
  }
5105
+ case "late": {
5106
+ if (caughtUp) continue;
5107
+ return "unopened";
5108
+ }
5099
5109
  case "message": {
5100
5110
  if (event.data === VISITOR_KEEPALIVE.response) continue;
5101
5111
  const frame = typeof event.data === "string" ? parseVisitorFrame(event.data) : null;
@@ -5103,6 +5113,8 @@ async function* followSocket(socket, reach, options) {
5103
5113
  throw unreadable(`a frame the wire does not declare: ${sample(event.data)}`);
5104
5114
  switch (frame.type) {
5105
5115
  case VISITOR_FRAMES.opened: {
5116
+ caughtUp = true;
5117
+ inbox.caughtUp();
5106
5118
  reach.position = frame.cursor;
5107
5119
  options.opened?.();
5108
5120
  options.reached?.(frame.cursor);
@@ -5169,6 +5181,10 @@ function socketInbox(socket, signal) {
5169
5181
  });
5170
5182
  socket.addEventListener("error", () => push({ kind: "error" }));
5171
5183
  signal?.addEventListener("abort", rouse, { once: true });
5184
+ let connecting = setTimeout(() => {
5185
+ connecting = void 0;
5186
+ push({ kind: "late" });
5187
+ }, LIVE_SOCKET_OPEN_TIMEOUT_MS);
5172
5188
  return {
5173
5189
  async next() {
5174
5190
  for (; ; ) {
@@ -5190,8 +5206,13 @@ function socketInbox(socket, signal) {
5190
5206
  if (socket.readyState === SOCKET_OPEN) socket.send(VISITOR_KEEPALIVE.request);
5191
5207
  }, LIVE_KEEPALIVE_INTERVAL_MS);
5192
5208
  },
5209
+ caughtUp() {
5210
+ if (connecting !== void 0) clearTimeout(connecting);
5211
+ connecting = void 0;
5212
+ },
5193
5213
  dispose() {
5194
5214
  disposed = true;
5215
+ if (connecting !== void 0) clearTimeout(connecting);
5195
5216
  if (keepalive !== void 0) clearInterval(keepalive);
5196
5217
  signal?.removeEventListener("abort", rouse);
5197
5218
  if (socket.readyState === SOCKET_CONNECTING || socket.readyState === SOCKET_OPEN) {
@@ -5227,7 +5248,9 @@ var CLOSE_MEANING = {
5227
5248
  [VISITOR_CLOSE_CODES.keyRefused]: "the key is not a publishable key the edge accepts \u2014 unknown, revoked or expired",
5228
5249
  [VISITOR_CLOSE_CODES.originRefused]: "this page\u2019s origin is not on the publishable key\u2019s allowed origins",
5229
5250
  [VISITOR_CLOSE_CODES.datasetRefused]: "`dataset` names no dataset the key reaches",
5230
- [VISITOR_CLOSE_CODES.unavailable]: "the edge could not reach what it needed to decide just now",
5251
+ // Also how the edge hands a connection on when the project's live objects move to another
5252
+ // placement (reason `moved`, REL-1514): either way the same request succeeds again shortly.
5253
+ [VISITOR_CLOSE_CODES.unavailable]: "the edge could not serve this connection just now \u2014 it could not reach what it needed, or it moved the project\u2019s live connections elsewhere",
5231
5254
  [VISITOR_CLOSE_CODES.allowanceReached]: "the project holds as many live connections as its plan allows",
5232
5255
  [VISITOR_CLOSE_CODES.addressLimitReached]: "this address holds as many live connections to the project as one address may",
5233
5256
  [VISITOR_CLOSE_CODES.ceilingReached]: "the project is at its safety ceiling of live connections"
@@ -5334,6 +5357,22 @@ function refusedPoll(response, body, context) {
5334
5357
  );
5335
5358
  }
5336
5359
  chunkMWMSFIWN_cjs.__name(refusedPoll, "refusedPoll");
5360
+ function edgeRequest(client, filter) {
5361
+ const key = client.apiKey;
5362
+ if (key === void 0 || !isPublishableKey(key)) {
5363
+ throw new LiveEdgeError(NEEDS_PUBLISHABLE_KEY, { kind: "needs-publishable-key" }, "stop");
5364
+ }
5365
+ const address = liveEdgeAddress(client);
5366
+ if (!address.ok) throw new LiveEdgeError(address.message, { kind: "needs-live-url" }, "stop");
5367
+ return {
5368
+ base: address.url,
5369
+ key,
5370
+ dataset: client.dataset,
5371
+ types: filter.types,
5372
+ ids: filter.ids
5373
+ };
5374
+ }
5375
+ chunkMWMSFIWN_cjs.__name(edgeRequest, "edgeRequest");
5337
5376
  function edgeUrl(request, since, transport, clientId) {
5338
5377
  const url = new URL(request.base.href);
5339
5378
  url.pathname = `${url.pathname.replace(/\/+$/, "")}${VISITOR_LIVE_PATH}`;
@@ -5894,9 +5933,14 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
5894
5933
  * (`rly_pub_…`): each change as ids, in order — the transport a browser follows changes with.
5895
5934
  *
5896
5935
  * A WebSocket to the edge, from `since` or the dataset's current position; where a socket cannot
5897
- * open — the runtime has none, or the network refuses it — it polls the edge instead, about every
5898
- * fifteen seconds, from the same cursor. The edge is `liveUrl`, or derived from the default
5899
- * `baseUrl` (see `RelyIOConfig.liveUrl`).
5936
+ * open — the runtime has none, the network refuses it, or it has not opened and been told its
5937
+ * position within `LIVE_SOCKET_OPEN_TIMEOUT_MS` — it polls the edge instead, about every fifteen
5938
+ * seconds, from the same cursor. The edge is `liveUrl`, or derived from the default `baseUrl`
5939
+ * (see `RelyIOConfig.liveUrl`).
5940
+ *
5941
+ * Without `since` it starts at the dataset's current position, which it hands `reached` before
5942
+ * anything after it: read what you show after that call, and a publish your read did not see is
5943
+ * one this subscription announces (see `LiveChangesOptions.since`).
5900
5944
  *
5901
5945
  * One subscription ends only when `signal` aborts, which ends the `for await` cleanly; every other
5902
5946
  * end — a socket a deploy dropped, a refusal, a refused poll — is thrown as a `LiveEdgeError`
@@ -6264,6 +6308,7 @@ exports.HttpClient = HttpClient;
6264
6308
  exports.InvalidApiKeyError = InvalidApiKeyError;
6265
6309
  exports.InvalidPayloadError = InvalidPayloadError;
6266
6310
  exports.LIVE_KEEPALIVE_INTERVAL_MS = LIVE_KEEPALIVE_INTERVAL_MS;
6311
+ exports.LIVE_SOCKET_OPEN_TIMEOUT_MS = LIVE_SOCKET_OPEN_TIMEOUT_MS;
6267
6312
  exports.LiveEdgeError = LiveEdgeError;
6268
6313
  exports.MethodNotAllowedError = MethodNotAllowedError;
6269
6314
  exports.MissingApiKeyError = MissingApiKeyError;
@@ -6301,5 +6346,5 @@ exports.matchRoute = matchRoute;
6301
6346
  exports.serviceInstructedDelayMs = serviceInstructedDelayMs;
6302
6347
  exports.sleep = sleep;
6303
6348
  exports.validateFile = validateFile;
6304
- //# sourceMappingURL=chunk-XIE7WJV3.cjs.map
6305
- //# sourceMappingURL=chunk-XIE7WJV3.cjs.map
6349
+ //# sourceMappingURL=chunk-DC4QLAI3.cjs.map
6350
+ //# sourceMappingURL=chunk-DC4QLAI3.cjs.map
@@ -534,6 +534,14 @@ function defineView(id, config) {
534
534
  if (!config.scope?.type) {
535
535
  throw new Error(`View '${id}' must have a valid scope`);
536
536
  }
537
+ const grouped = (config.filters ?? []).findIndex(
538
+ (filter) => typeof filter === "object" && filter !== null && "conditions" in filter
539
+ );
540
+ if (grouped !== -1) {
541
+ throw new Error(
542
+ `View '${id}' filter ${grouped} is a filter group: a view's filters are a flat list, joined by AND. List each of its conditions as a filter of its own, or use 'isAnyOf' for an OR within one field.`
543
+ );
544
+ }
537
545
  if (config.slug !== void 0 && !/^[a-z][a-z0-9-]*$/.test(config.slug)) {
538
546
  throw new Error(
539
547
  `View '${id}' slug '${config.slug}' must be lowercase, start with a letter, and contain only letters, numbers, and hyphens`
@@ -682,5 +690,5 @@ __name(component, "component");
682
690
  var fields = fields_exports;
683
691
 
684
692
  export { BUILT_IN_ROLES, BUILT_IN_ROLE_ACTIONS, ROLE_ACTIONS, buildFallbackChain, defineAssetType, defineComponent, defineContentType, defineContentTypeWorkflow, defineLocale, defineQuery, defineRole, defineSchema, defineSettingsGroup, defineSingleton, defineSingletonContentType, defineView, defineWorkflow, defineWorkflowStage, fields, fieldset, findDefaultLocale, findWorkflowStage, getActiveLocales, getBuiltInRoleActions, getFirstWorkflowStage, getLocaleCodes, getNextWorkflowStage, getWorkflowStageIds, isBuiltInRole, isFinalWorkflowStage, isLocaleDefinition, isRoleDefinition, isWorkflowDefinition, isWorkflowStageDefinition };
685
- //# sourceMappingURL=chunk-YEJUMW4X.js.map
686
- //# sourceMappingURL=chunk-YEJUMW4X.js.map
693
+ //# sourceMappingURL=chunk-IGHYC2WM.js.map
694
+ //# sourceMappingURL=chunk-IGHYC2WM.js.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkXIE7WJV3_cjs = require('../chunk-XIE7WJV3.cjs');
3
+ var chunkDC4QLAI3_cjs = require('../chunk-DC4QLAI3.cjs');
4
4
  require('../chunk-LSRPMNPT.cjs');
5
5
  require('../chunk-TZL374LS.cjs');
6
6
  require('../chunk-MWMSFIWN.cjs');
@@ -9,11 +9,11 @@ require('../chunk-MWMSFIWN.cjs');
9
9
 
10
10
  Object.defineProperty(exports, "TypedRelyIOClient", {
11
11
  enumerable: true,
12
- get: function () { return chunkXIE7WJV3_cjs.TypedRelyIOClient; }
12
+ get: function () { return chunkDC4QLAI3_cjs.TypedRelyIOClient; }
13
13
  });
14
14
  Object.defineProperty(exports, "createClient", {
15
15
  enumerable: true,
16
- get: function () { return chunkXIE7WJV3_cjs.createClient; }
16
+ get: function () { return chunkDC4QLAI3_cjs.createClient; }
17
17
  });
18
18
  //# sourceMappingURL=index.cjs.map
19
19
  //# sourceMappingURL=index.cjs.map
@@ -1,6 +1,6 @@
1
- export { e as ClientSchema, R as Register, f as RegisteredSchema, d as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-DBoPPlT1.cjs';
2
- import '../index-B_rIWO_l.cjs';
3
- import '../define-content-type-cEGjIwT5.cjs';
4
- import '../define-schema-DgbJ5Kwn.cjs';
1
+ export { e as ClientSchema, R as Register, f as RegisteredSchema, d as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-KuYgc7eG.cjs';
2
+ import '../index-NnLCwSqF.cjs';
3
+ import '../define-content-type-DfnTu26S.cjs';
4
+ import '../define-schema-W-0u1Jg1.cjs';
5
5
  import './live-visitor.js';
6
6
  import '../dev-handshake/index.cjs';
@@ -1,6 +1,6 @@
1
- export { e as ClientSchema, R as Register, f as RegisteredSchema, d as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-yRJ2IqM_.js';
2
- import '../index-Cv4tmcrw.js';
3
- import '../define-content-type-cEGjIwT5.js';
4
- import '../define-schema-BPj2srgh.js';
1
+ export { e as ClientSchema, R as Register, f as RegisteredSchema, d as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-rLEBSFvK.js';
2
+ import '../index-B9hDmCho.js';
3
+ import '../define-content-type-DfnTu26S.js';
4
+ import '../define-schema-rbTrXxNN.js';
5
5
  import './live-visitor.js';
6
6
  import '../dev-handshake/index.js';
@@ -1,4 +1,4 @@
1
- export { TypedRelyIOClient, createClient } from '../chunk-QFHVF3YF.js';
1
+ export { TypedRelyIOClient, createClient } from '../chunk-2L5JUW7O.js';
2
2
  import '../chunk-BBUB7C2Z.js';
3
3
  import '../chunk-H6IBQSMM.js';
4
4
  import '../chunk-XQ4QHWZE.js';
@@ -208,6 +208,23 @@ interface paths {
208
208
  patch?: never;
209
209
  trace?: never;
210
210
  };
211
+ '/internal/usage/stops': {
212
+ parameters: {
213
+ query?: never;
214
+ header?: never;
215
+ path?: never;
216
+ cookie?: never;
217
+ };
218
+ get?: never;
219
+ put?: never;
220
+ /** Record the Usage Limit stops an edge refused */
221
+ post: operations['recordUsageStops'];
222
+ delete?: never;
223
+ options?: never;
224
+ head?: never;
225
+ patch?: never;
226
+ trace?: never;
227
+ };
211
228
  '/v1/{contentType}': {
212
229
  parameters: {
213
230
  query?: never;
@@ -1094,7 +1111,7 @@ interface components {
1094
1111
  ErrorResponse: {
1095
1112
  error: {
1096
1113
  /** @enum {string} */
1097
- code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_DELETE_BLOCKED' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | 'RATE_LIMIT_EXCEEDED' | 'READ_ONLY_KEY' | 'REQUEST_INVALID' | 'REQUEST_TIMEOUT' | 'RESOURCE_CONFLICT' | 'RESOURCE_EXPIRED' | 'RESOURCE_NOT_FOUND' | 'REVERIFICATION_REQUIRED' | 'SERVICE_INDETERMINATE' | 'TRANSACTION_ROLLED_BACK' | 'USAGE_QUOTA_EXCEEDED';
1114
+ code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_DELETE_BLOCKED' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | 'RATE_LIMIT_EXCEEDED' | 'READ_ONLY_KEY' | 'REQUEST_INVALID' | 'REQUEST_TIMEOUT' | 'RESOURCE_CONFLICT' | 'RESOURCE_EXPIRED' | 'RESOURCE_NOT_FOUND' | 'REVERIFICATION_REQUIRED' | 'SERVICE_INDETERMINATE' | 'TRANSACTION_ROLLED_BACK' | 'USAGE_QUOTA_EXCEEDED' | 'USER_NOT_PROVISIONED';
1098
1115
  messages: string[];
1099
1116
  details?: {
1100
1117
  [key: string]: unknown;
@@ -1495,7 +1512,7 @@ interface components {
1495
1512
  id?: string;
1496
1513
  error: {
1497
1514
  /** @enum {string} */
1498
- code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_DELETE_BLOCKED' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | 'RATE_LIMIT_EXCEEDED' | 'READ_ONLY_KEY' | 'REQUEST_INVALID' | 'REQUEST_TIMEOUT' | 'RESOURCE_CONFLICT' | 'RESOURCE_EXPIRED' | 'RESOURCE_NOT_FOUND' | 'REVERIFICATION_REQUIRED' | 'SERVICE_INDETERMINATE' | 'TRANSACTION_ROLLED_BACK' | 'USAGE_QUOTA_EXCEEDED';
1515
+ code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_DELETE_BLOCKED' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | 'RATE_LIMIT_EXCEEDED' | 'READ_ONLY_KEY' | 'REQUEST_INVALID' | 'REQUEST_TIMEOUT' | 'RESOURCE_CONFLICT' | 'RESOURCE_EXPIRED' | 'RESOURCE_NOT_FOUND' | 'REVERIFICATION_REQUIRED' | 'SERVICE_INDETERMINATE' | 'TRANSACTION_ROLLED_BACK' | 'USAGE_QUOTA_EXCEEDED' | 'USER_NOT_PROVISIONED';
1499
1516
  messages: string[];
1500
1517
  details?: {
1501
1518
  [key: string]: unknown;
@@ -2140,6 +2157,65 @@ interface operations {
2140
2157
  };
2141
2158
  };
2142
2159
  };
2160
+ recordUsageStops: {
2161
+ parameters: {
2162
+ query?: never;
2163
+ header?: never;
2164
+ path?: never;
2165
+ cookie?: never;
2166
+ };
2167
+ requestBody?: never;
2168
+ responses: {
2169
+ /** @description Success. */
2170
+ 200: {
2171
+ headers: {
2172
+ [name: string]: unknown;
2173
+ };
2174
+ content: {
2175
+ 'application/json': {
2176
+ /** @description The payload itself. */
2177
+ data: unknown;
2178
+ };
2179
+ };
2180
+ };
2181
+ /** @description REQUEST_INVALID */
2182
+ 400: {
2183
+ headers: {
2184
+ [name: string]: unknown;
2185
+ };
2186
+ content: {
2187
+ 'application/json': components['schemas']['RefusalRequestInvalid'];
2188
+ };
2189
+ };
2190
+ /** @description ACCESS_DENIED */
2191
+ 403: {
2192
+ headers: {
2193
+ [name: string]: unknown;
2194
+ };
2195
+ content: {
2196
+ 'application/json': components['schemas']['RefusalAccessDenied'];
2197
+ };
2198
+ };
2199
+ /** @description RESOURCE_NOT_FOUND */
2200
+ 404: {
2201
+ headers: {
2202
+ [name: string]: unknown;
2203
+ };
2204
+ content: {
2205
+ 'application/json': components['schemas']['RefusalResourceNotFound'];
2206
+ };
2207
+ };
2208
+ /** @description INTERNAL_ERROR */
2209
+ 500: {
2210
+ headers: {
2211
+ [name: string]: unknown;
2212
+ };
2213
+ content: {
2214
+ 'application/json': components['schemas']['RefusalInternalError'];
2215
+ };
2216
+ };
2217
+ };
2218
+ };
2143
2219
  listEntries: {
2144
2220
  parameters: {
2145
2221
  query?: {