@relyio/sdk 0.8.0 → 0.9.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.
@@ -4862,6 +4862,7 @@ async function* pollChanges(http, options = {}) {
4862
4862
  const { signal } = options;
4863
4863
  let since = options.since;
4864
4864
  let resynced;
4865
+ let starting = since === void 0;
4865
4866
  for (; ; ) {
4866
4867
  if (isAborted(signal)) return;
4867
4868
  let response;
@@ -4892,6 +4893,10 @@ async function* pollChanges(http, options = {}) {
4892
4893
  yield { ...change, fresh: change.cursor };
4893
4894
  if (isAborted(signal)) return;
4894
4895
  }
4896
+ if (starting) {
4897
+ starting = false;
4898
+ options.reached?.(page.nextCursor);
4899
+ }
4895
4900
  if (data.length === 0) {
4896
4901
  const wait = parseRetryAfterMs(headerValue(response.headers, "Retry-After"), Date.now());
4897
4902
  if (wait !== void 0 && wait > 0) await sleep(wait, signal);
@@ -5019,23 +5024,12 @@ __name(originOf, "originOf");
5019
5024
 
5020
5025
  // src/changes/live-edge.ts
5021
5026
  var LIVE_KEEPALIVE_INTERVAL_MS = 3e4;
5027
+ var LIVE_SOCKET_OPEN_TIMEOUT_MS = VISITOR_POLL_INTERVAL_MS;
5022
5028
  var LIVE_POLLS_BEFORE_SOCKET = 4;
5023
5029
  async function* subscribeLiveEdge(client, options = {}) {
5024
5030
  const { signal } = options;
5025
5031
  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
- };
5032
+ const request = edgeRequest(client, options);
5039
5033
  const reach = { position: options.since };
5040
5034
  for (; ; ) {
5041
5035
  const socket = openSocket(client, edgeUrl(request, reach.position, "socket"));
@@ -5069,6 +5063,7 @@ async function* followSocket(socket, reach, options) {
5069
5063
  const { signal } = options;
5070
5064
  const inbox = socketInbox(socket, signal);
5071
5065
  let open = false;
5066
+ let caughtUp = false;
5072
5067
  try {
5073
5068
  for (; ; ) {
5074
5069
  const event = await inbox.next();
@@ -5094,6 +5089,10 @@ async function* followSocket(socket, reach, options) {
5094
5089
  "retry"
5095
5090
  );
5096
5091
  }
5092
+ case "late": {
5093
+ if (caughtUp) continue;
5094
+ return "unopened";
5095
+ }
5097
5096
  case "message": {
5098
5097
  if (event.data === VISITOR_KEEPALIVE.response) continue;
5099
5098
  const frame = typeof event.data === "string" ? parseVisitorFrame(event.data) : null;
@@ -5101,6 +5100,8 @@ async function* followSocket(socket, reach, options) {
5101
5100
  throw unreadable(`a frame the wire does not declare: ${sample(event.data)}`);
5102
5101
  switch (frame.type) {
5103
5102
  case VISITOR_FRAMES.opened: {
5103
+ caughtUp = true;
5104
+ inbox.caughtUp();
5104
5105
  reach.position = frame.cursor;
5105
5106
  options.opened?.();
5106
5107
  options.reached?.(frame.cursor);
@@ -5167,6 +5168,10 @@ function socketInbox(socket, signal) {
5167
5168
  });
5168
5169
  socket.addEventListener("error", () => push({ kind: "error" }));
5169
5170
  signal?.addEventListener("abort", rouse, { once: true });
5171
+ let connecting = setTimeout(() => {
5172
+ connecting = void 0;
5173
+ push({ kind: "late" });
5174
+ }, LIVE_SOCKET_OPEN_TIMEOUT_MS);
5170
5175
  return {
5171
5176
  async next() {
5172
5177
  for (; ; ) {
@@ -5188,8 +5193,13 @@ function socketInbox(socket, signal) {
5188
5193
  if (socket.readyState === SOCKET_OPEN) socket.send(VISITOR_KEEPALIVE.request);
5189
5194
  }, LIVE_KEEPALIVE_INTERVAL_MS);
5190
5195
  },
5196
+ caughtUp() {
5197
+ if (connecting !== void 0) clearTimeout(connecting);
5198
+ connecting = void 0;
5199
+ },
5191
5200
  dispose() {
5192
5201
  disposed = true;
5202
+ if (connecting !== void 0) clearTimeout(connecting);
5193
5203
  if (keepalive !== void 0) clearInterval(keepalive);
5194
5204
  signal?.removeEventListener("abort", rouse);
5195
5205
  if (socket.readyState === SOCKET_CONNECTING || socket.readyState === SOCKET_OPEN) {
@@ -5225,7 +5235,9 @@ var CLOSE_MEANING = {
5225
5235
  [VISITOR_CLOSE_CODES.keyRefused]: "the key is not a publishable key the edge accepts \u2014 unknown, revoked or expired",
5226
5236
  [VISITOR_CLOSE_CODES.originRefused]: "this page\u2019s origin is not on the publishable key\u2019s allowed origins",
5227
5237
  [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",
5238
+ // Also how the edge hands a connection on when the project's live objects move to another
5239
+ // placement (reason `moved`, REL-1514): either way the same request succeeds again shortly.
5240
+ [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
5241
  [VISITOR_CLOSE_CODES.allowanceReached]: "the project holds as many live connections as its plan allows",
5230
5242
  [VISITOR_CLOSE_CODES.addressLimitReached]: "this address holds as many live connections to the project as one address may",
5231
5243
  [VISITOR_CLOSE_CODES.ceilingReached]: "the project is at its safety ceiling of live connections"
@@ -5332,6 +5344,22 @@ function refusedPoll(response, body, context) {
5332
5344
  );
5333
5345
  }
5334
5346
  __name(refusedPoll, "refusedPoll");
5347
+ function edgeRequest(client, filter) {
5348
+ const key = client.apiKey;
5349
+ if (key === void 0 || !isPublishableKey(key)) {
5350
+ throw new LiveEdgeError(NEEDS_PUBLISHABLE_KEY, { kind: "needs-publishable-key" }, "stop");
5351
+ }
5352
+ const address = liveEdgeAddress(client);
5353
+ if (!address.ok) throw new LiveEdgeError(address.message, { kind: "needs-live-url" }, "stop");
5354
+ return {
5355
+ base: address.url,
5356
+ key,
5357
+ dataset: client.dataset,
5358
+ types: filter.types,
5359
+ ids: filter.ids
5360
+ };
5361
+ }
5362
+ __name(edgeRequest, "edgeRequest");
5335
5363
  function edgeUrl(request, since, transport, clientId) {
5336
5364
  const url = new URL(request.base.href);
5337
5365
  url.pathname = `${url.pathname.replace(/\/+$/, "")}${VISITOR_LIVE_PATH}`;
@@ -5892,9 +5920,14 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
5892
5920
  * (`rly_pub_…`): each change as ids, in order — the transport a browser follows changes with.
5893
5921
  *
5894
5922
  * 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`).
5923
+ * open — the runtime has none, the network refuses it, or it has not opened and been told its
5924
+ * position within `LIVE_SOCKET_OPEN_TIMEOUT_MS` — it polls the edge instead, about every fifteen
5925
+ * seconds, from the same cursor. The edge is `liveUrl`, or derived from the default `baseUrl`
5926
+ * (see `RelyIOConfig.liveUrl`).
5927
+ *
5928
+ * Without `since` it starts at the dataset's current position, which it hands `reached` before
5929
+ * anything after it: read what you show after that call, and a publish your read did not see is
5930
+ * one this subscription announces (see `LiveChangesOptions.since`).
5898
5931
  *
5899
5932
  * One subscription ends only when `signal` aborts, which ends the `for await` cleanly; every other
5900
5933
  * end — a socket a deploy dropped, a refusal, a refused poll — is thrown as a `LiveEdgeError`
@@ -6240,6 +6273,6 @@ function randomClientId() {
6240
6273
  }
6241
6274
  __name(randomClientId, "randomClientId");
6242
6275
 
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
6276
+ 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 };
6277
+ //# sourceMappingURL=chunk-LGNJIGHL.js.map
6278
+ //# sourceMappingURL=chunk-LGNJIGHL.js.map
@@ -4864,6 +4864,7 @@ async function* pollChanges(http, options = {}) {
4864
4864
  const { signal } = options;
4865
4865
  let since = options.since;
4866
4866
  let resynced;
4867
+ let starting = since === void 0;
4867
4868
  for (; ; ) {
4868
4869
  if (isAborted(signal)) return;
4869
4870
  let response;
@@ -4894,6 +4895,10 @@ async function* pollChanges(http, options = {}) {
4894
4895
  yield { ...change, fresh: change.cursor };
4895
4896
  if (isAborted(signal)) return;
4896
4897
  }
4898
+ if (starting) {
4899
+ starting = false;
4900
+ options.reached?.(page.nextCursor);
4901
+ }
4897
4902
  if (data.length === 0) {
4898
4903
  const wait = parseRetryAfterMs(headerValue(response.headers, "Retry-After"), Date.now());
4899
4904
  if (wait !== void 0 && wait > 0) await sleep(wait, signal);
@@ -5021,23 +5026,12 @@ chunkMWMSFIWN_cjs.__name(originOf, "originOf");
5021
5026
 
5022
5027
  // src/changes/live-edge.ts
5023
5028
  var LIVE_KEEPALIVE_INTERVAL_MS = 3e4;
5029
+ var LIVE_SOCKET_OPEN_TIMEOUT_MS = VISITOR_POLL_INTERVAL_MS;
5024
5030
  var LIVE_POLLS_BEFORE_SOCKET = 4;
5025
5031
  async function* subscribeLiveEdge(client, options = {}) {
5026
5032
  const { signal } = options;
5027
5033
  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
- };
5034
+ const request = edgeRequest(client, options);
5041
5035
  const reach = { position: options.since };
5042
5036
  for (; ; ) {
5043
5037
  const socket = openSocket(client, edgeUrl(request, reach.position, "socket"));
@@ -5071,6 +5065,7 @@ async function* followSocket(socket, reach, options) {
5071
5065
  const { signal } = options;
5072
5066
  const inbox = socketInbox(socket, signal);
5073
5067
  let open = false;
5068
+ let caughtUp = false;
5074
5069
  try {
5075
5070
  for (; ; ) {
5076
5071
  const event = await inbox.next();
@@ -5096,6 +5091,10 @@ async function* followSocket(socket, reach, options) {
5096
5091
  "retry"
5097
5092
  );
5098
5093
  }
5094
+ case "late": {
5095
+ if (caughtUp) continue;
5096
+ return "unopened";
5097
+ }
5099
5098
  case "message": {
5100
5099
  if (event.data === VISITOR_KEEPALIVE.response) continue;
5101
5100
  const frame = typeof event.data === "string" ? parseVisitorFrame(event.data) : null;
@@ -5103,6 +5102,8 @@ async function* followSocket(socket, reach, options) {
5103
5102
  throw unreadable(`a frame the wire does not declare: ${sample(event.data)}`);
5104
5103
  switch (frame.type) {
5105
5104
  case VISITOR_FRAMES.opened: {
5105
+ caughtUp = true;
5106
+ inbox.caughtUp();
5106
5107
  reach.position = frame.cursor;
5107
5108
  options.opened?.();
5108
5109
  options.reached?.(frame.cursor);
@@ -5169,6 +5170,10 @@ function socketInbox(socket, signal) {
5169
5170
  });
5170
5171
  socket.addEventListener("error", () => push({ kind: "error" }));
5171
5172
  signal?.addEventListener("abort", rouse, { once: true });
5173
+ let connecting = setTimeout(() => {
5174
+ connecting = void 0;
5175
+ push({ kind: "late" });
5176
+ }, LIVE_SOCKET_OPEN_TIMEOUT_MS);
5172
5177
  return {
5173
5178
  async next() {
5174
5179
  for (; ; ) {
@@ -5190,8 +5195,13 @@ function socketInbox(socket, signal) {
5190
5195
  if (socket.readyState === SOCKET_OPEN) socket.send(VISITOR_KEEPALIVE.request);
5191
5196
  }, LIVE_KEEPALIVE_INTERVAL_MS);
5192
5197
  },
5198
+ caughtUp() {
5199
+ if (connecting !== void 0) clearTimeout(connecting);
5200
+ connecting = void 0;
5201
+ },
5193
5202
  dispose() {
5194
5203
  disposed = true;
5204
+ if (connecting !== void 0) clearTimeout(connecting);
5195
5205
  if (keepalive !== void 0) clearInterval(keepalive);
5196
5206
  signal?.removeEventListener("abort", rouse);
5197
5207
  if (socket.readyState === SOCKET_CONNECTING || socket.readyState === SOCKET_OPEN) {
@@ -5227,7 +5237,9 @@ var CLOSE_MEANING = {
5227
5237
  [VISITOR_CLOSE_CODES.keyRefused]: "the key is not a publishable key the edge accepts \u2014 unknown, revoked or expired",
5228
5238
  [VISITOR_CLOSE_CODES.originRefused]: "this page\u2019s origin is not on the publishable key\u2019s allowed origins",
5229
5239
  [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",
5240
+ // Also how the edge hands a connection on when the project's live objects move to another
5241
+ // placement (reason `moved`, REL-1514): either way the same request succeeds again shortly.
5242
+ [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
5243
  [VISITOR_CLOSE_CODES.allowanceReached]: "the project holds as many live connections as its plan allows",
5232
5244
  [VISITOR_CLOSE_CODES.addressLimitReached]: "this address holds as many live connections to the project as one address may",
5233
5245
  [VISITOR_CLOSE_CODES.ceilingReached]: "the project is at its safety ceiling of live connections"
@@ -5334,6 +5346,22 @@ function refusedPoll(response, body, context) {
5334
5346
  );
5335
5347
  }
5336
5348
  chunkMWMSFIWN_cjs.__name(refusedPoll, "refusedPoll");
5349
+ function edgeRequest(client, filter) {
5350
+ const key = client.apiKey;
5351
+ if (key === void 0 || !isPublishableKey(key)) {
5352
+ throw new LiveEdgeError(NEEDS_PUBLISHABLE_KEY, { kind: "needs-publishable-key" }, "stop");
5353
+ }
5354
+ const address = liveEdgeAddress(client);
5355
+ if (!address.ok) throw new LiveEdgeError(address.message, { kind: "needs-live-url" }, "stop");
5356
+ return {
5357
+ base: address.url,
5358
+ key,
5359
+ dataset: client.dataset,
5360
+ types: filter.types,
5361
+ ids: filter.ids
5362
+ };
5363
+ }
5364
+ chunkMWMSFIWN_cjs.__name(edgeRequest, "edgeRequest");
5337
5365
  function edgeUrl(request, since, transport, clientId) {
5338
5366
  const url = new URL(request.base.href);
5339
5367
  url.pathname = `${url.pathname.replace(/\/+$/, "")}${VISITOR_LIVE_PATH}`;
@@ -5894,9 +5922,14 @@ var _TypedRelyIOClient = class _TypedRelyIOClient {
5894
5922
  * (`rly_pub_…`): each change as ids, in order — the transport a browser follows changes with.
5895
5923
  *
5896
5924
  * 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`).
5925
+ * open — the runtime has none, the network refuses it, or it has not opened and been told its
5926
+ * position within `LIVE_SOCKET_OPEN_TIMEOUT_MS` — it polls the edge instead, about every fifteen
5927
+ * seconds, from the same cursor. The edge is `liveUrl`, or derived from the default `baseUrl`
5928
+ * (see `RelyIOConfig.liveUrl`).
5929
+ *
5930
+ * Without `since` it starts at the dataset's current position, which it hands `reached` before
5931
+ * anything after it: read what you show after that call, and a publish your read did not see is
5932
+ * one this subscription announces (see `LiveChangesOptions.since`).
5900
5933
  *
5901
5934
  * One subscription ends only when `signal` aborts, which ends the `for await` cleanly; every other
5902
5935
  * end — a socket a deploy dropped, a refusal, a refused poll — is thrown as a `LiveEdgeError`
@@ -6264,6 +6297,7 @@ exports.HttpClient = HttpClient;
6264
6297
  exports.InvalidApiKeyError = InvalidApiKeyError;
6265
6298
  exports.InvalidPayloadError = InvalidPayloadError;
6266
6299
  exports.LIVE_KEEPALIVE_INTERVAL_MS = LIVE_KEEPALIVE_INTERVAL_MS;
6300
+ exports.LIVE_SOCKET_OPEN_TIMEOUT_MS = LIVE_SOCKET_OPEN_TIMEOUT_MS;
6267
6301
  exports.LiveEdgeError = LiveEdgeError;
6268
6302
  exports.MethodNotAllowedError = MethodNotAllowedError;
6269
6303
  exports.MissingApiKeyError = MissingApiKeyError;
@@ -6301,5 +6335,5 @@ exports.matchRoute = matchRoute;
6301
6335
  exports.serviceInstructedDelayMs = serviceInstructedDelayMs;
6302
6336
  exports.sleep = sleep;
6303
6337
  exports.validateFile = validateFile;
6304
- //# sourceMappingURL=chunk-XIE7WJV3.cjs.map
6305
- //# sourceMappingURL=chunk-XIE7WJV3.cjs.map
6338
+ //# sourceMappingURL=chunk-SPFRDXAF.cjs.map
6339
+ //# sourceMappingURL=chunk-SPFRDXAF.cjs.map
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkXIE7WJV3_cjs = require('../chunk-XIE7WJV3.cjs');
3
+ var chunkSPFRDXAF_cjs = require('../chunk-SPFRDXAF.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 chunkSPFRDXAF_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 chunkSPFRDXAF_cjs.createClient; }
17
17
  });
18
18
  //# sourceMappingURL=index.cjs.map
19
19
  //# sourceMappingURL=index.cjs.map
@@ -1,4 +1,4 @@
1
- export { e as ClientSchema, R as Register, f as RegisteredSchema, d as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-DBoPPlT1.cjs';
1
+ export { e as ClientSchema, R as Register, f as RegisteredSchema, d as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-B9axQW8s.cjs';
2
2
  import '../index-B_rIWO_l.cjs';
3
3
  import '../define-content-type-cEGjIwT5.cjs';
4
4
  import '../define-schema-DgbJ5Kwn.cjs';
@@ -1,4 +1,4 @@
1
- export { e as ClientSchema, R as Register, f as RegisteredSchema, d as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-yRJ2IqM_.js';
1
+ export { e as ClientSchema, R as Register, f as RegisteredSchema, d as TypedClientConfig, T as TypedRelyIOClient, c as createClient } from '../index-GIfaMlQ7.js';
2
2
  import '../index-Cv4tmcrw.js';
3
3
  import '../define-content-type-cEGjIwT5.js';
4
4
  import '../define-schema-BPj2srgh.js';
@@ -1,4 +1,4 @@
1
- export { TypedRelyIOClient, createClient } from '../chunk-QFHVF3YF.js';
1
+ export { TypedRelyIOClient, createClient } from '../chunk-LGNJIGHL.js';
2
2
  import '../chunk-BBUB7C2Z.js';
3
3
  import '../chunk-H6IBQSMM.js';
4
4
  import '../chunk-XQ4QHWZE.js';
@@ -2960,6 +2960,18 @@ interface ChangesOptions {
2960
2960
  * the new position, on every refetch. The iterator waits for it.
2961
2961
  */
2962
2962
  onExpired?: 'throw' | 'resync' | ((expired: ChangesExpiredError) => void | Promise<void>);
2963
+ /**
2964
+ * Called once, when the feed was opened without `since`, with the position it starts from: the
2965
+ * first poll's answer, the dataset's head — before the next poll is sent. Read what you show
2966
+ * **after** it and a write your read did not see is after the position, so this feed delivers it,
2967
+ * with no second request to take the position first (`changesHead()` is that request) (REL-1513).
2968
+ *
2969
+ * `followChanges()` passes it (`ChangeSourceOptions.reached`), so a feed that drops before its first
2970
+ * change reopens from there rather than re-reading everything. Never called with a later empty
2971
+ * page's cursor: filtered, that cursor is past rows the filter hid, and a caller that widens the
2972
+ * filter must not reopen from it.
2973
+ */
2974
+ reached?: (cursor: string) => void;
2963
2975
  }
2964
2976
  interface ChangesHeadOptions {
2965
2977
  /** Cancels the request; the promise then rejects. */
@@ -2975,10 +2987,18 @@ interface ChangesHeadOptions {
2975
2987
  * the poll interval, and what each close code and each refused poll means a client does next.
2976
2988
  *
2977
2989
  * **One open, two ways in.** A subscription opens a WebSocket to the edge. Where it cannot — the
2978
- * runtime has no `WebSocket` (Node 18 and 20), constructing one throws, or the socket fails before it
2979
- * opens (a network that blocks sockets) — it polls the edge instead, from the same cursor, about
2980
- * every {@link VISITOR_POLL_INTERVAL_MS}, and tries a socket again about once a minute. Both carry
2981
- * one cursor space, so a switch either way loses nothing.
2990
+ * runtime has no `WebSocket` (Node 18 and 20), constructing one throws, the socket fails before it
2991
+ * opens (a network that blocks sockets), or it has not opened and been caught up within
2992
+ * {@link LIVE_SOCKET_OPEN_TIMEOUT_MS} (a network that holds it) — it polls the edge instead, from the
2993
+ * same cursor, about every {@link VISITOR_POLL_INTERVAL_MS}, and tries a socket again about once a
2994
+ * minute. Both carry one cursor space, so a switch either way loses nothing.
2995
+ *
2996
+ * **Where it starts.** Without `since`, the edge answers the dataset's current position before
2997
+ * anything else — the socket's `feed.opened`, or the first poll's answer — and the subscription hands
2998
+ * it to `reached`. That call is the position, with no request of its own for it: a read sent after it
2999
+ * is answered at or after the position, and every change after it is delivered here, so a publish the
3000
+ * read did not see is announced (REL-1513). The edge counts the subscription as one live connection,
3001
+ * whichever way in it took (`INV-LV-LIVE-IS-METERED`).
2982
3002
  *
2983
3003
  * **It ends only when its signal aborts, and throws every other end** — a socket closed by a refusal
2984
3004
  * or a deploy, a refused poll, a keepalive nobody answered — as a `LiveEdgeError` saying what to do
@@ -3005,11 +3025,51 @@ interface ChangesHeadOptions {
3005
3025
  * receives never learns otherwise that a network change dropped its connection.
3006
3026
  */
3007
3027
  declare const LIVE_KEEPALIVE_INTERVAL_MS = 30000;
3028
+ /**
3029
+ * How long a socket has to open and be caught up — the feed's `feed.opened` — before the subscription
3030
+ * stops waiting on it, closes it and polls instead, as it does for a socket that fails before it opens
3031
+ * (REL-1513).
3032
+ *
3033
+ * The poll interval, because that is what a socket is for: telling the page sooner than a poll would.
3034
+ * A poll is answered at once and polled again within this interval, so a socket that has not caught
3035
+ * up by then has already served the page worse than polling would have. It is well past a healthy
3036
+ * open — the door's checks and one ledger read at the edge — and half the keepalive's verdict on an
3037
+ * open socket that has gone quiet ({@link LIVE_KEEPALIVE_INTERVAL_MS}, twice). It bounds how long
3038
+ * `<RelyIOProvider live>`'s first reads wait for a position on a network that neither opens a socket
3039
+ * nor refuses one — a proxy that holds the upgrade — which without it they would wait on for as long
3040
+ * as the page is open.
3041
+ */
3042
+ declare const LIVE_SOCKET_OPEN_TIMEOUT_MS = 15000;
3008
3043
  interface LiveChangesOptions {
3009
3044
  /**
3010
3045
  * A change's cursor from an earlier subscription. Omitted, the edge answers the dataset's current
3011
- * position first and replays nothing; fetch what you show **after** that position arrives — with
3012
- * `followChanges()`, after `onState` reports `following` — so nothing lands in between unseen.
3046
+ * position first and replays nothing, and the subscription hands that position to `reached` before
3047
+ * anything after it. Read what you show **after** that first call — a read sent before it, from a
3048
+ * subscription opened afterwards without `since`, leaves a publish between the two that neither
3049
+ * sees (REL-1513). With `followChanges()`, which hands the source its own `reached`, call both —
3050
+ * and let the read go if the loop fails first, so content never waits on a feed that is down:
3051
+ *
3052
+ * ```ts
3053
+ * let positioned!: () => void
3054
+ * const position = new Promise<void>(resolve => (positioned = resolve))
3055
+ * const following = followChanges(
3056
+ * from =>
3057
+ * relyio.liveChanges({
3058
+ * ...from,
3059
+ * ids: [id],
3060
+ * reached: cursor => {
3061
+ * from.reached(cursor)
3062
+ * positioned()
3063
+ * },
3064
+ * }),
3065
+ * { signal, onChange, onResync, onState: state => state.kind !== 'following' && positioned() },
3066
+ * )
3067
+ * await position
3068
+ * const post = await relyio.content('post').findById(id).execute()
3069
+ * ```
3070
+ *
3071
+ * The wait is bounded: a socket that has not opened and been told its position within
3072
+ * {@link LIVE_SOCKET_OPEN_TIMEOUT_MS} is given up for a poll, answered at once.
3013
3073
  */
3014
3074
  since?: string;
3015
3075
  /** Content types to keep. Omitted keeps every type; an empty list is refused. At most 50. */
@@ -3036,7 +3096,8 @@ interface LiveChangesOptions {
3036
3096
  /**
3037
3097
  * Called with a position reached without a change to carry it. `followChanges()` passes it so a
3038
3098
  * connection dropped before its first change reconnects from there; see
3039
- * `ChangeSourceOptions.reached`.
3099
+ * `ChangeSourceOptions.reached`. Without `since`, its first call is the position the subscription
3100
+ * starts from (see `since`).
3040
3101
  */
3041
3102
  reached?: (cursor: string) => void;
3042
3103
  }
@@ -3292,9 +3353,14 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
3292
3353
  * (`rly_pub_…`): each change as ids, in order — the transport a browser follows changes with.
3293
3354
  *
3294
3355
  * A WebSocket to the edge, from `since` or the dataset's current position; where a socket cannot
3295
- * open — the runtime has none, or the network refuses it — it polls the edge instead, about every
3296
- * fifteen seconds, from the same cursor. The edge is `liveUrl`, or derived from the default
3297
- * `baseUrl` (see `RelyIOConfig.liveUrl`).
3356
+ * open — the runtime has none, the network refuses it, or it has not opened and been told its
3357
+ * position within `LIVE_SOCKET_OPEN_TIMEOUT_MS` — it polls the edge instead, about every fifteen
3358
+ * seconds, from the same cursor. The edge is `liveUrl`, or derived from the default `baseUrl`
3359
+ * (see `RelyIOConfig.liveUrl`).
3360
+ *
3361
+ * Without `since` it starts at the dataset's current position, which it hands `reached` before
3362
+ * anything after it: read what you show after that call, and a publish your read did not see is
3363
+ * one this subscription announces (see `LiveChangesOptions.since`).
3298
3364
  *
3299
3365
  * One subscription ends only when `signal` aborts, which ends the `for await` cleanly; every other
3300
3366
  * end — a socket a deploy dropped, a refusal, a refused poll — is thrown as a `LiveEdgeError`
@@ -3599,4 +3665,4 @@ declare function createClient<TSchema extends AnySchemaDefinition>(config: Typed
3599
3665
  */
3600
3666
  type ClientSchema<T extends TypedRelyIOClient<AnySchemaDefinition>> = T extends TypedRelyIOClient<infer TSchema> ? TSchema : never;
3601
3667
 
3602
- export { type BatchOperationResult as $, type ActiveSandbox as A, type SearchResultItem as B, type Change as C, type SearchHitMetadata as D, type ExtendedQueryResult as E, type FeedChange as F, type SearchResponse as G, HttpClient as H, type AutocompleteSuggestion as I, type AutocompleteResponse as J, type SimilarResult as K, LIVE_KEEPALIVE_INTERVAL_MS as L, type SimilarResponse as M, type SearchFilter as N, type SearchFields as O, type Project as P, type SearchSort as Q, type Register as R, type SandboxState as S, TypedRelyIOClient as T, type SearchTypeName as U, type SearchEntry as V, BatchClient as W, BatchBuilder as X, type BatchMethod as Y, type BatchOperation as Z, type BatchOptions as _, ChangesExpiredError as a, type BatchSummary as a0, type BatchResponse as a1, AdhocQueryClient as a2, AdhocQueryBuilder as a3, type FetchBlock as a4, type AggregateBlock as a5, type AggregateMetric as a6, type SearchBlock as a7, type FilterValue as a8, type FullTextConfig as a9, type MultipartPart as aA, type MultipartTarget as aB, type UploadProgress as aC, ResourceNotFoundError as aD, ResourceConflictError as aE, ResourceExpiredError as aF, isResourceNotFound as aG, type FileErrorCode as aH, type FileUploadErrorCode as aI, FileUploadError as aJ, FileValidationError as aK, type FileValidationConstraints as aL, validateFile as aM, type AdhocQueryDefinition as aa, type AdhocQueryOptions as ab, type QueryMetadata as ac, type AdhocQueryResult as ad, AssetClient as ae, AssetFileBuilder as af, AssetUploadBuilder as ag, isAssetEntry as ah, type AssetVisibility as ai, type FileStatus as aj, type FileBackend as ak, type AssetFileBlock as al, type AssetFileExtracted as am, type FileStatusResult as an, type AssetUrls as ao, type AssetEntryResponse as ap, type PopulatedAssetReference as aq, type PresignInput as ar, type PresignResult as as, type ConfirmInput as at, type ConfirmResult as au, type ResolveUrlInput as av, type ResolveUrlResult as aw, type CreateAssetOptions as ax, type WaitUntilReadyOptions as ay, type MultipartCreateResult as az, type ChangesExpiredReason as b, createClient as c, type TypedClientConfig as d, type ClientSchema as e, type RegisteredSchema as f, type SendOptions as g, entityTagOf as h, type ConditionalWriteOptions as i, type RetryableWriteOptions as j, type ChangesHeadOptions as k, type ChangesOptions as l, type LiveChangesOptions as m, ContentClient as n, SingletonClient as o, SettingsClient as p, ContentQueryBuilder as q, ContentByIdBuilder as r, type ChildrenOptions as s, type SingletonFetchOptions as t, type SettingsFetchOptions as u, SearchClient as v, SearchBuilder as w, AutocompleteBuilder as x, SimilarBuilder as y, type SearchMode as z };
3668
+ export { type BatchOptions as $, type ActiveSandbox as A, type SearchMode as B, type Change as C, type SearchResultItem as D, type ExtendedQueryResult as E, type FeedChange as F, type SearchHitMetadata as G, HttpClient as H, type SearchResponse as I, type AutocompleteSuggestion as J, type AutocompleteResponse as K, LIVE_KEEPALIVE_INTERVAL_MS as L, type SimilarResult as M, type SimilarResponse as N, type SearchFilter as O, type Project as P, type SearchFields as Q, type Register as R, type SandboxState as S, TypedRelyIOClient as T, type SearchSort as U, type SearchTypeName as V, type SearchEntry as W, BatchClient as X, BatchBuilder as Y, type BatchMethod as Z, type BatchOperation as _, ChangesExpiredError as a, type BatchOperationResult as a0, type BatchSummary as a1, type BatchResponse as a2, AdhocQueryClient as a3, AdhocQueryBuilder as a4, type FetchBlock as a5, type AggregateBlock as a6, type AggregateMetric as a7, type SearchBlock as a8, type FilterValue as a9, type MultipartCreateResult as aA, type MultipartPart as aB, type MultipartTarget as aC, type UploadProgress as aD, ResourceNotFoundError as aE, ResourceConflictError as aF, ResourceExpiredError as aG, isResourceNotFound as aH, type FileErrorCode as aI, type FileUploadErrorCode as aJ, FileUploadError as aK, FileValidationError as aL, type FileValidationConstraints as aM, validateFile as aN, type FullTextConfig as aa, type AdhocQueryDefinition as ab, type AdhocQueryOptions as ac, type QueryMetadata as ad, type AdhocQueryResult as ae, AssetClient as af, AssetFileBuilder as ag, AssetUploadBuilder as ah, isAssetEntry as ai, type AssetVisibility as aj, type FileStatus as ak, type FileBackend as al, type AssetFileBlock as am, type AssetFileExtracted as an, type FileStatusResult as ao, type AssetUrls as ap, type AssetEntryResponse as aq, type PopulatedAssetReference as ar, type PresignInput as as, type PresignResult as at, type ConfirmInput as au, type ConfirmResult as av, type ResolveUrlInput as aw, type ResolveUrlResult as ax, type CreateAssetOptions as ay, type WaitUntilReadyOptions as az, type ChangesExpiredReason as b, createClient as c, type TypedClientConfig as d, type ClientSchema as e, type RegisteredSchema as f, type SendOptions as g, entityTagOf as h, type ConditionalWriteOptions as i, type RetryableWriteOptions as j, type ChangesHeadOptions as k, type ChangesOptions as l, LIVE_SOCKET_OPEN_TIMEOUT_MS as m, type LiveChangesOptions as n, ContentClient as o, SingletonClient as p, SettingsClient as q, ContentQueryBuilder as r, ContentByIdBuilder as s, type ChildrenOptions as t, type SingletonFetchOptions as u, type SettingsFetchOptions as v, SearchClient as w, SearchBuilder as x, AutocompleteBuilder as y, SimilarBuilder as z };