@vercel/board 0.28.0 → 0.30.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 (139) hide show
  1. package/dist/{a2-B0_VlbtC.mjs → a2-D_28Pdip.mjs} +197 -259
  2. package/dist/access-CQ39gqEV.mjs +226 -0
  3. package/dist/access.d.mts +1 -1
  4. package/dist/access.mjs +3 -3
  5. package/dist/{actors-BLXVp4oZ.mjs → actors-xPiamLWk.mjs} +3 -3
  6. package/dist/{auth-lTkOgvcE.mjs → auth-BPinwfN0.mjs} +3 -226
  7. package/dist/backend-a2/blob-vercel.d.mts +1 -1
  8. package/dist/backend-a2/contract.d.mts +2 -2
  9. package/dist/backend-a2/contract.mjs +3 -3
  10. package/dist/backend-a2/scheduler-local.d.mts +1 -1
  11. package/dist/backend-a2/scheduler-local.mjs +1 -1
  12. package/dist/backend-a2/scheduler-qstash.d.mts +3 -3
  13. package/dist/backend-a2/scheduler-qstash.mjs +8 -8
  14. package/dist/backend-a2/scheduler-vercel.d.mts +3 -3
  15. package/dist/backend-a2/scheduler-vercel.mjs +6 -6
  16. package/dist/backend-a2/store-memory.d.mts +2 -2
  17. package/dist/backend-a2/store-memory.mjs +3 -3
  18. package/dist/backend-a2/store-postgres.d.mts +1 -1
  19. package/dist/backend-a2/store-postgres.mjs +34 -15
  20. package/dist/backend-a2/store-redis-http.d.mts +1 -1
  21. package/dist/backend-a2/store-redis-http.mjs +6 -6
  22. package/dist/backend-a2/store-redis.d.mts +2 -2
  23. package/dist/backend-a2/store-redis.mjs +5 -5
  24. package/dist/backend-a2/store-sqlite.d.mts +1 -1
  25. package/dist/backend-a2/store-sqlite.mjs +3 -3
  26. package/dist/backend-a2.d.mts +20 -7
  27. package/dist/backend-a2.mjs +2 -1
  28. package/dist/{backend-http-BvNFrvcY.mjs → backend-http-16SbvnAK.mjs} +2 -2
  29. package/dist/{backend-http-E7YU0qhn.d.mts → backend-http-3PoBYQoo.d.mts} +15 -3
  30. package/dist/{backend-http-CfLVYqmj.mjs → backend-http-BPaNYLWj.mjs} +4 -5
  31. package/dist/backend-http.d.mts +1 -1
  32. package/dist/backend-http.mjs +1 -1
  33. package/dist/backend-http.node.d.mts +1 -1
  34. package/dist/backend-http.node.mjs +1 -1
  35. package/dist/{backend-ZKYTe3xa.d.mts → backend-n3hajfrD.d.mts} +12 -6
  36. package/dist/{backend-vercel-D87pIp2k.mjs → backend-vercel-C4Kee2-K.mjs} +260 -30
  37. package/dist/{backend-vercel-DTrDiSk5.mjs → backend-vercel-Kd8nvW5A.mjs} +3 -3
  38. package/dist/{backend-vercel-CIRObA0t.d.mts → backend-vercel-qznuDxnN.d.mts} +20 -5
  39. package/dist/backend-vercel.d.mts +1 -1
  40. package/dist/backend-vercel.mjs +1 -1
  41. package/dist/backend-vercel.node.d.mts +1 -1
  42. package/dist/backend-vercel.node.mjs +1 -1
  43. package/dist/{blob-B-9AvYis.d.mts → blob-CqILvdmr.d.mts} +2 -2
  44. package/dist/blob-DQK5prXT.mjs +182 -0
  45. package/dist/{chat-provider-DnHibqnM.mjs → chat-provider-COtsU5jB.mjs} +2 -2
  46. package/dist/{chat-provider-DsNEBQiA.d.mts → chat-provider-D6jVT4wS.d.mts} +5 -3
  47. package/dist/cli-commands.d.mts +1 -1
  48. package/dist/cli-commands.mjs +1 -1
  49. package/dist/cli-embedded.d.mts +2 -2
  50. package/dist/cli-embedded.mjs +1 -1
  51. package/dist/cli.mjs +5 -5
  52. package/dist/{client-xLxeDz0f.d.mts → client-CjAatpV4.d.mts} +67 -10
  53. package/dist/{commands-BFookFtn.mjs → commands-B5DHjZKK.mjs} +54 -10
  54. package/dist/{commands-D6gvrOh3.d.mts → commands-BtH69yqt.d.mts} +17 -0
  55. package/dist/{conformance-DlnfuzEB.mjs → conformance-C7fwIvmN.mjs} +258 -18
  56. package/dist/conformance.d.mts +1 -1
  57. package/dist/conformance.mjs +1 -1
  58. package/dist/{engine-Bfe6pcXb.mjs → engine-DkdkXQEy.mjs} +21 -13
  59. package/dist/{errors-CB4tnZGz.d.mts → errors-87TVtXeb.d.mts} +1 -1
  60. package/dist/{client-D0Px7KzF.mjs → errors-C_5rB8Iz.mjs} +104 -4
  61. package/dist/{events-CewD4kw7.mjs → events-qf5XG5VQ.mjs} +2 -2
  62. package/dist/{exports-CCzw2Vdw.mjs → exports-CG0P8Qi4.mjs} +59 -33
  63. package/dist/exports-CrGA5_yN.d.mts +5 -0
  64. package/dist/{external-BV_cUncs.mjs → external-D3p5T57R.mjs} +4 -2
  65. package/dist/{folds-jS9wlh9_.d.mts → folds-8wRRXjAt.d.mts} +4 -0
  66. package/dist/{folds-Dyjput8M.mjs → folds-DGYkMW19.mjs} +3 -2
  67. package/dist/{index-C05it0mC.d.mts → index-BygAXP7t.d.mts} +2 -2
  68. package/dist/index.d.mts +6 -6
  69. package/dist/{index.default-DmKxH_E6.mjs → index.default-DhkgpfR2.mjs} +1 -1
  70. package/dist/index.mjs +5 -6
  71. package/dist/index.node.d.mts +6 -6
  72. package/dist/index.node.mjs +3 -4
  73. package/dist/inspect/app.js +29 -29
  74. package/dist/inspect/engine.js +5 -5
  75. package/dist/{internal-CvsrprnU-CRY89I-b.mjs → internal-CvsrprnU-zZMpDiRY.mjs} +1 -1
  76. package/dist/{local-DhkrAqPP.mjs → local-C76Fy5ad.mjs} +1 -1
  77. package/dist/{main-eci7w-aP.mjs → main-D2s-QBOK.mjs} +76 -26
  78. package/dist/{middleware-ChKM1zuu.mjs → middleware-DlJQYiwV.mjs} +2 -2
  79. package/dist/{node-Zd_C-gxP.mjs → node-D8Rtg1su.mjs} +1 -1
  80. package/dist/{platform-B4TnJtWu-CwcTyKg2.mjs → platform-B4TnJtWu-Do3agKr5.mjs} +1 -1
  81. package/dist/{project-DMDST9kl.mjs → project-C_2xs57L.mjs} +1 -1
  82. package/dist/{provider-poIkXapd.mjs → provider-BaVmi4Hi.mjs} +3 -1
  83. package/dist/{provider-Cdg1qadh.d.mts → provider-Bm46LAdp.d.mts} +9 -2
  84. package/dist/{redis-tables-DN9PfIDi.mjs → redis-tables-BWJZHUGg.mjs} +41 -25
  85. package/dist/{reducer-CjmvZSAb-D_OSISmj.mjs → reducer-Bswr11ar-P324o9vn.mjs} +2 -2
  86. package/dist/{reducer-CYPHsSmd-BQIfozGi.d.mts → reducer-CYPHsSmd-BXjGiptm.d.mts} +1 -1
  87. package/dist/{reducers-BcmSs4qf.mjs → reducers-8jqLewgw.mjs} +5 -5
  88. package/dist/{retryable-lazy-DZWmHpii-Bye-W8q7.mjs → retryable-lazy-DZWmHpii-DpTc5PIP.mjs} +1 -1
  89. package/dist/{scheduler-task-X1SToDjP-BVoWuInI.mjs → scheduler-task-X1SToDjP-D2Il2rln.mjs} +1 -1
  90. package/dist/{schemas-Be08nyfW.mjs → schemas-DBmUO6pr.mjs} +2 -1
  91. package/dist/{serve-B09an9DQ.mjs → serve-lPoBDEds.mjs} +7 -6
  92. package/dist/{server-qgez0Xny-D5mLfqFQ.d.mts → server-B9gu0qi1-DI1WvcVK.d.mts} +10 -4
  93. package/dist/{server-DTX0prGr.mjs → server-D82a4uMe.mjs} +4 -4
  94. package/dist/{server-DtFrWxi3-Boa6gdWO.mjs → server-DX7mM6nm-D7N_7bug.mjs} +32 -23
  95. package/dist/{serving-CvOWEym2.mjs → serving-DKny38LK.mjs} +1 -1
  96. package/dist/{session-clear-wHd5GCpZ-BnKSxReK.mjs → session-clear-XJYpmUpg-2q8l_FJR.mjs} +14 -2
  97. package/dist/{sql-U9WTxrwJ.mjs → sql-Bj0fk6dn.mjs} +2 -2
  98. package/dist/{sqlite-db-Ds4majtT.mjs → sqlite-db-Dc8G78XV.mjs} +1 -1
  99. package/dist/{store-D0MhBvg6-4Z2L0Kqd.d.mts → store-DEzcHZOA-B-5vhxef.d.mts} +12 -2
  100. package/dist/store-N8PXxDAS-DWWgv-Vz.mjs +5 -0
  101. package/dist/{store-codec-DwrWlgQx-CYxGW0aD.mjs → store-codec-pAG2oPgQ-SqDXlPBR.mjs} +4 -4
  102. package/dist/store-memory-4IBl0Ztu.mjs +2 -0
  103. package/dist/{store-memory-Bas9Uq5C.mjs → store-memory-B0PkVSuQ.mjs} +14 -7
  104. package/dist/{store-polling-BZt2Rf3D-BiEM6_HB.mjs → store-polling-BZt2Rf3D-Div-bJ_D.mjs} +2 -2
  105. package/dist/{store-presence-polling-JuAy2Ck2-CYpuK75X.mjs → store-presence-polling-JuAy2Ck2-Dh-g_KYM.mjs} +3 -3
  106. package/dist/{store-sqlite-CxxPCcCT.mjs → store-sqlite-D85t3tE7.mjs} +14 -7
  107. package/dist/store-sqlite-iBTYYKBj.mjs +2 -0
  108. package/dist/{stream-buffer-DrTyiIuo-BKy-vI14.mjs → stream-buffer-DrTyiIuo-Be10yOBR.mjs} +2 -2
  109. package/dist/sync-github.d.mts +4 -2
  110. package/dist/sync-github.mjs +4 -14
  111. package/dist/sync-kapso.d.mts +3 -2
  112. package/dist/sync-kapso.mjs +3 -3
  113. package/dist/sync-linear.d.mts +12 -2
  114. package/dist/sync-linear.mjs +191 -9
  115. package/dist/sync-slack.d.mts +41 -5
  116. package/dist/sync-slack.mjs +70 -11
  117. package/dist/sync.chat.d.mts +1 -1
  118. package/dist/sync.chat.mjs +1 -1
  119. package/dist/sync.d.mts +2 -2
  120. package/dist/sync.mjs +3 -3
  121. package/dist/tags-BpFo6q0_.mjs +14 -0
  122. package/dist/{targets-C-wdR5wP.mjs → targets-Cgjs29T0.mjs} +1 -1
  123. package/dist/{tokens-BuCU-61R.mjs → tokens-C5_yGRlL.mjs} +2 -2
  124. package/dist/{types-aCAf6lGU.d.mts → types-shZmGZ-q.d.mts} +2 -2
  125. package/dist/{watchers-hash-7DJU9b-n.mjs → watchers-hash-B_5b0-ZG.mjs} +50 -19
  126. package/docs/01-board/04-messages.md +93 -0
  127. package/docs/01-board/08-middleware.md +5 -2
  128. package/docs/02-sync/03-slack.md +6 -2
  129. package/docs/02-sync/07-linear.md +28 -6
  130. package/docs/04-reference/01-cli.md +27 -12
  131. package/docs/04-reference/02-board.md +20 -5
  132. package/docs/04-reference/03-http.md +17 -6
  133. package/docs/04-reference/05-conformance.md +14 -3
  134. package/package.json +2 -2
  135. package/dist/errors-CusN4x2l.mjs +0 -88
  136. package/dist/exports-D22M68rk.d.mts +0 -5
  137. package/dist/store-N8PXxDAS-BWBgzBHp.mjs +0 -5
  138. package/dist/store-memory-ZLiZbH3R.mjs +0 -2
  139. package/dist/store-sqlite-BmwL3pUR.mjs +0 -2
@@ -1,14 +1,14 @@
1
- import { n as CLEAR_EVENT_TYPE, o as sessionClearedError, s as supersededAttemptError, t as A2Error } from "../session-clear-wHd5GCpZ-BnKSxReK.mjs";
2
- import { m as nullProtoRecord, n as NOTIFY_TIMINGS } from "../internal-CvsrprnU-CRY89I-b.mjs";
3
- import { n as defaultSleep, r as pollingStream } from "../store-polling-BZt2Rf3D-BiEM6_HB.mjs";
4
- import { r as platformWaitUntil } from "../platform-B4TnJtWu-CwcTyKg2.mjs";
5
- import { t as retryableLazy } from "../retryable-lazy-DZWmHpii-Bye-W8q7.mjs";
6
- import { r as sqlTables } from "../sql-U9WTxrwJ.mjs";
7
- import { a as idleLogCursor, i as idempotentReplay, n as decodeCause, r as decodeReturnedEventIds, t as cursorKeyOf } from "../store-codec-DwrWlgQx-CYxGW0aD.mjs";
8
- import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "../store-N8PXxDAS-BWBgzBHp.mjs";
9
- import { t as pollPresence } from "../store-presence-polling-JuAy2Ck2-CYpuK75X.mjs";
1
+ import { a as duplicateBatchError, c as sessionClearedError, l as supersededAttemptError, n as CLEAR_EVENT_TYPE, s as lastIndexMismatchError, t as A2Error } from "../session-clear-XJYpmUpg-2q8l_FJR.mjs";
2
+ import { m as nullProtoRecord, n as NOTIFY_TIMINGS } from "../internal-CvsrprnU-zZMpDiRY.mjs";
3
+ import { n as defaultSleep, r as pollingStream } from "../store-polling-BZt2Rf3D-Div-bJ_D.mjs";
4
+ import { r as platformWaitUntil } from "../platform-B4TnJtWu-Do3agKr5.mjs";
5
+ import { t as retryableLazy } from "../retryable-lazy-DZWmHpii-DpTc5PIP.mjs";
6
+ import { r as sqlTables } from "../sql-Bj0fk6dn.mjs";
7
+ import { a as idleLogCursor, i as idempotentReplay, n as decodeCause, r as decodeReturnedEventIds, t as cursorKeyOf } from "../store-codec-pAG2oPgQ-SqDXlPBR.mjs";
8
+ import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "../store-N8PXxDAS-DWWgv-Vz.mjs";
9
+ import { t as pollPresence } from "../store-presence-polling-JuAy2Ck2-Dh-g_KYM.mjs";
10
10
  import { createHash } from "node:crypto";
11
- //#region ../../node_modules/.pnpm/experimental-a2@0.22.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__52060f00b21aecfab049c27fa3abd2f9/node_modules/experimental-a2/dist/store-postgres.js
11
+ //#region ../../node_modules/.pnpm/experimental-a2@0.24.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__b1e2c243a963f2620a5d202817417c26/node_modules/experimental-a2/dist/store-postgres.js
12
12
  const postgresNotificationChannel = ({ kind, sessionId }) => `a2_${kind}_${createHash("md5").update(sessionId).digest("hex")}`;
13
13
  function postgresNotifications(createConnection) {
14
14
  const channels = /* @__PURE__ */ new Map();
@@ -858,7 +858,8 @@ const INSERTED_AFTER = `(
858
858
  * every event's id belongs to this session already, the batch is a retry: it
859
859
  * stops with the committed rows. Some owned aborts, as does scheduled work
860
860
  * from at or below the clear marker (`origin`). Rows below the marker own no
861
- * id.
861
+ * id. Both id outcomes carry the head, which a conditional append's conflict
862
+ * reports when it moved.
862
863
  */
863
864
  const APPEND_CHECKS = `
864
865
  with boundary as materialized (
@@ -876,12 +877,12 @@ const APPEND_CHECKS = `
876
877
  )
877
878
  select case
878
879
  when (select count(*) from owned) = ${param.bigint("count")} then
879
- jsonb_build_object('stop', 'replay',
880
+ jsonb_build_object('stop', 'replay', 'head', boundary.base,
880
881
  'has_pending', boundary.has_pending,
881
882
  'events', (select jsonb_agg(to_jsonb(owned) order by owned.idx)
882
883
  from owned))
883
884
  when exists (select 1 from owned) then
884
- jsonb_build_object('abort', 'mixed', 'owned',
885
+ jsonb_build_object('abort', 'mixed', 'head', boundary.base, 'owned',
885
886
  (select count(*) from owned))
886
887
  when ${param.bigint("origin")} <= boundary.clear_index then
887
888
  jsonb_build_object('abort', 'cleared')
@@ -913,6 +914,15 @@ const FENCE = `
913
914
  from cause where cause.ord not in (select ord from held)
914
915
  order by cause.ord limit 1`;
915
916
  /**
917
+ * A conditional append's head check, under the session lock and after the
918
+ * fences: it aborts with the head unless the head is `ifLastIndex`.
919
+ */
920
+ const IF_LAST_INDEX = `
921
+ select jsonb_build_object('abort', 'moved', 'index', head.idx)
922
+ from (select coalesce(max(idx), 0) as idx from a2_events
923
+ where session_id = ${SESSION}) head
924
+ where head.idx <> ${param.bigint("ifLastIndex")}`;
925
+ /**
916
926
  * Frees the `ids` this session's rows below its clear marker hold, so the
917
927
  * batch can take them. It never waits on a row: a reclaim deleting one may
918
928
  * hold it, and one it skips aborts.
@@ -1876,12 +1886,19 @@ function postgres$1(options = {}) {
1876
1886
  const causes = [...new Map(events.flatMap((event) => event.cause ? [[jsonb(event.cause), event.cause]] : [])).values()];
1877
1887
  const work = enqueue(events, consumers);
1878
1888
  const originIndex = appendOptions?.originIndex;
1889
+ const ifLastIndex = appendOptions?.ifLastIndex;
1890
+ const conditionalAt = (head) => ifLastIndex === void 0 ? void 0 : {
1891
+ sessionId,
1892
+ ifLastIndex,
1893
+ head: asNumber(head)
1894
+ };
1879
1895
  const checked = (await run({
1880
1896
  sessionId,
1881
1897
  statements: [
1882
1898
  LOCK_SESSION,
1883
1899
  APPEND_CHECKS,
1884
1900
  causes.length > 0 && FENCE,
1901
+ ifLastIndex !== void 0 && IF_LAST_INDEX,
1885
1902
  suppliedIds.length > 0 && REUSE_IDS,
1886
1903
  INSERT_EVENTS,
1887
1904
  ...work.statements
@@ -1892,6 +1909,7 @@ function postgres$1(options = {}) {
1892
1909
  ids: suppliedIds,
1893
1910
  count: events.length,
1894
1911
  origin: originIndex ?? null,
1912
+ ifLastIndex: ifLastIndex ?? null,
1895
1913
  causes: causes.map((cause, offset) => ({
1896
1914
  ord: offset + 1,
1897
1915
  consumer: cause.consumer,
@@ -1906,17 +1924,18 @@ function postgres$1(options = {}) {
1906
1924
  switch (reason["abort"]) {
1907
1925
  case "mixed": {
1908
1926
  const owned = asNumber(reason["owned"]);
1909
- return new A2Error("PARTIAL_DUPLICATE_BATCH", `batch mixes ${owned} already-appended and ${events.length - owned} fresh events`);
1927
+ return duplicateBatchError(`batch mixes ${owned} already-appended and ${events.length - owned} fresh events`, conditionalAt(reason["head"]));
1910
1928
  }
1911
1929
  case "cleared": return sessionClearedError(`scheduled work from event ${originIndex} was cleared in session '${sessionId}'`);
1912
1930
  case "superseded": return supersededAttemptError(sessionId, causes[asNumber(reason["ord"]) - 1]);
1931
+ case "moved": return lastIndexMismatchError(sessionId, ifLastIndex, asNumber(reason["index"]));
1913
1932
  case "held": return new A2Error("STORE_UNAVAILABLE", `an event id being reused is still held by cleared work in session '${sessionId}'`);
1914
1933
  default: return new A2Error("STORE_UNAVAILABLE", "postgres store operation failed");
1915
1934
  }
1916
1935
  }
1917
1936
  })).find((row) => row["stop"] === "replay" || "base" in row);
1918
1937
  if (checked["stop"] === "replay") return {
1919
- events: idempotentReplay(events, checked["events"].map(toStored)),
1938
+ events: idempotentReplay(events, checked["events"].map(toStored), conditionalAt(checked["head"])),
1920
1939
  hasPending: checked["has_pending"] === true
1921
1940
  };
1922
1941
  return {
@@ -1,4 +1,4 @@
1
- import { t as BoardStore } from "../types-aCAf6lGU.mjs";
1
+ import { t as BoardStore } from "../types-shZmGZ-q.mjs";
2
2
  //#region src/store/redis-http.d.ts
3
3
  export type RedisHttpOptions = {
4
4
  /** The REST endpoint, e.g. `process.env.UPSTASH_REDIS_REST_URL`. */
@@ -1,9 +1,9 @@
1
- import { t as A2Error } from "../session-clear-wHd5GCpZ-BnKSxReK.mjs";
2
- import { n as NOTIFY_TIMINGS } from "../internal-CvsrprnU-CRY89I-b.mjs";
3
- import { n as defaultSleep } from "../store-polling-BZt2Rf3D-BiEM6_HB.mjs";
4
- import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "../store-N8PXxDAS-BWBgzBHp.mjs";
5
- import { n as createRedisNotifyStore, t as redisTables } from "../redis-tables-DN9PfIDi.mjs";
6
- //#region ../../node_modules/.pnpm/experimental-a2@0.22.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__52060f00b21aecfab049c27fa3abd2f9/node_modules/experimental-a2/dist/store-redis-http.js
1
+ import { t as A2Error } from "../session-clear-XJYpmUpg-2q8l_FJR.mjs";
2
+ import { n as NOTIFY_TIMINGS } from "../internal-CvsrprnU-zZMpDiRY.mjs";
3
+ import { n as defaultSleep } from "../store-polling-BZt2Rf3D-Div-bJ_D.mjs";
4
+ import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "../store-N8PXxDAS-DWWgv-Vz.mjs";
5
+ import { n as createRedisNotifyStore, t as redisTables } from "../redis-tables-BWJZHUGg.mjs";
6
+ //#region ../../node_modules/.pnpm/experimental-a2@0.24.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__b1e2c243a963f2620a5d202817417c26/node_modules/experimental-a2/dist/store-redis-http.js
7
7
  function redisHttpSubscriptions({ url, token, onReconnect, fallback }) {
8
8
  const subscriptions = /* @__PURE__ */ new Map();
9
9
  const listeners = /* @__PURE__ */ new Set();
@@ -1,5 +1,5 @@
1
- import { t as BoardStore } from "../types-aCAf6lGU.mjs";
2
- //#region ../../node_modules/.pnpm/experimental-a2@0.22.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__52060f00b21aecfab049c27fa3abd2f9/node_modules/experimental-a2/dist/store-redis.d.ts
1
+ import { t as BoardStore } from "../types-shZmGZ-q.mjs";
2
+ //#region ../../node_modules/.pnpm/experimental-a2@0.24.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__b1e2c243a963f2620a5d202817417c26/node_modules/experimental-a2/dist/store-redis.d.ts
3
3
  //#region src/store-redis-notify.d.ts
4
4
  type RedisConnection = {
5
5
  call(command: string, ...args: Array<string | number>): Promise<unknown>;
@@ -1,8 +1,8 @@
1
- import { t as A2Error } from "../session-clear-wHd5GCpZ-BnKSxReK.mjs";
2
- import { t as retryableLazy } from "../retryable-lazy-DZWmHpii-Bye-W8q7.mjs";
3
- import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "../store-N8PXxDAS-BWBgzBHp.mjs";
4
- import { n as createRedisNotifyStore, t as redisTables } from "../redis-tables-DN9PfIDi.mjs";
5
- //#region ../../node_modules/.pnpm/experimental-a2@0.22.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__52060f00b21aecfab049c27fa3abd2f9/node_modules/experimental-a2/dist/store-redis.js
1
+ import { t as A2Error } from "../session-clear-XJYpmUpg-2q8l_FJR.mjs";
2
+ import { t as retryableLazy } from "../retryable-lazy-DZWmHpii-DpTc5PIP.mjs";
3
+ import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "../store-N8PXxDAS-DWWgv-Vz.mjs";
4
+ import { n as createRedisNotifyStore, t as redisTables } from "../redis-tables-BWJZHUGg.mjs";
5
+ //#region ../../node_modules/.pnpm/experimental-a2@0.24.0_@upstash+qstash@2.12.0_@vercel+queue@0.7.0_ai@7.0.130_zod@4.6.5__b1e2c243a963f2620a5d202817417c26/node_modules/experimental-a2/dist/store-redis.js
6
6
  /**
7
7
  * experimental-a2/store-redis — the Redis-protocol store backend, on Redis
8
8
  * Streams. The storage semantics live in store-redis-core.ts (shared
@@ -1,4 +1,4 @@
1
- import { t as BoardStore } from "../types-aCAf6lGU.mjs";
1
+ import { t as BoardStore } from "../types-shZmGZ-q.mjs";
2
2
  //#region src/store/sqlite.d.ts
3
3
  /**
4
4
  * A board in one SQLite file, A2's log and board's tables side by side: `a2()`'s
@@ -1,6 +1,6 @@
1
- import { r as sqlTables } from "../sql-U9WTxrwJ.mjs";
2
- import { t as sqlite$1 } from "../store-sqlite-CxxPCcCT.mjs";
3
- import { t as sqliteDb } from "../sqlite-db-Ds4majtT.mjs";
1
+ import { r as sqlTables } from "../sql-Bj0fk6dn.mjs";
2
+ import { t as sqlite$1 } from "../store-sqlite-D85t3tE7.mjs";
3
+ import { t as sqliteDb } from "../sqlite-db-Dc8G78XV.mjs";
4
4
  //#region src/store/sqlite.ts
5
5
  /**
6
6
  * A board in one SQLite file, A2's log and board's tables side by side: `a2()`'s
@@ -1,10 +1,10 @@
1
- import { t as Actor, x as Attachment } from "./folds-jS9wlh9_.mjs";
2
- import { l as Reducer, r as ContractEvent } from "./reducer-CYPHsSmd-BQIfozGi.mjs";
3
- import { a as SessionAppend, c as SessionConsumeOptions, d as SessionSchedule, f as StateOptions, l as SessionConsumeResult, n as A2Server, o as SessionClearOptions, p as SessionCleared, r as Consumer, s as SessionClearResult, t as A2Scheduler, u as SessionDeadLetters } from "./server-qgez0Xny-D5mLfqFQ.mjs";
4
- import { A as InboxItem, B as Me, D as IdentityView, Ft as ThreadView, H as MessagesPage, Ht as UploadTicket, I as LinkedAccount, It as ThreadsPage, K as PersonView, Nt as SyncedView, R as MatchView, S as EventsPage, St as SyncCopiesView, Tt as SyncFindView, V as MessageView, b as Discovery, bt as SyncCodeView, dt as SourceJoin, et as RegistrationView, jt as SyncThreadView, k as InboxEntry, mt as SourceRead, ot as ScheduleView, v as ChannelView } from "./client-xLxeDz0f.mjs";
5
- import { i as Caller, n as BackendRoute, r as BoardBinding } from "./backend-ZKYTe3xa.mjs";
6
- import { n as fsBlob, r as memoryBlob, t as BlobStore } from "./blob-B-9AvYis.mjs";
7
- import { t as BoardStore } from "./types-aCAf6lGU.mjs";
1
+ import { t as Actor, x as Attachment } from "./folds-8wRRXjAt.mjs";
2
+ import { l as Reducer, r as ContractEvent } from "./reducer-CYPHsSmd-BXjGiptm.mjs";
3
+ import { a as SessionAppend, c as SessionConsumeOptions, d as SessionSchedule, f as StateOptions, l as SessionConsumeResult, n as A2Server, o as SessionClearOptions, p as SessionCleared, r as Consumer, s as SessionClearResult, t as A2Scheduler, u as SessionDeadLetters } from "./server-B9gu0qi1-DI1WvcVK.mjs";
4
+ import { A as InboxItem, Ct as SyncCopiesView, D as IdentityView, Et as SyncFindView, H as MessageView, It as ThreadView, L as LinkedAccount, Lt as ThreadsPage, Mt as SyncThreadView, Pt as SyncedView, S as EventsPage, U as MessagesPage, Ut as UploadTicket, V as Me, b as Discovery, ft as SourceJoin, ht as SourceRead, k as InboxEntry, q as PersonView, st as ScheduleView, tt as RegistrationView, v as ChannelView, xt as SyncCodeView, z as MatchView } from "./client-CjAatpV4.mjs";
5
+ import { i as Caller, n as BackendRoute, r as BoardBinding } from "./backend-n3hajfrD.mjs";
6
+ import { n as fsBlob, r as memoryBlob, t as BlobStore } from "./blob-CqILvdmr.mjs";
7
+ import { t as BoardStore } from "./types-shZmGZ-q.mjs";
8
8
  import { z } from "zod";
9
9
  //#region src/server/transport.d.ts
10
10
  /**
@@ -121,6 +121,7 @@ export declare function a2(options?: A2Options): {
121
121
  })[] | undefined;
122
122
  id?: string | undefined;
123
123
  attachments?: string[] | undefined;
124
+ after?: string | undefined;
124
125
  }, signal: AbortSignal) => Promise<{
125
126
  message: MessageView;
126
127
  unknownMentions?: string[];
@@ -134,12 +135,15 @@ export declare function a2(options?: A2Options): {
134
135
  id: string;
135
136
  } & {
136
137
  text: string;
138
+ revision?: number | undefined;
137
139
  }, signal: AbortSignal) => Promise<{
138
140
  ok: true;
139
141
  unknownMentions?: string[];
140
142
  }>;
141
143
  delete: (caller: Caller, input: {
142
144
  id: string;
145
+ } & {
146
+ revision?: number | undefined;
143
147
  }, signal: AbortSignal) => Promise<{
144
148
  ok: true;
145
149
  }>;
@@ -156,6 +160,7 @@ export declare function a2(options?: A2Options): {
156
160
  } & {
157
161
  set?: Record<string, string> | undefined;
158
162
  unset?: string[] | undefined;
163
+ if?: Record<string, string | null> | undefined;
159
164
  }, signal: AbortSignal) => Promise<{
160
165
  ok: true;
161
166
  }>;
@@ -207,6 +212,7 @@ export declare function a2(options?: A2Options): {
207
212
  name?: string | null | undefined;
208
213
  type?: string | null | undefined;
209
214
  size: number;
215
+ sha256?: string | undefined;
210
216
  }, signal: AbortSignal) => Promise<UploadTicket>;
211
217
  uploadFinish: (caller: Caller, input: {
212
218
  id: string;
@@ -284,6 +290,7 @@ export declare function a2(options?: A2Options): {
284
290
  } & {
285
291
  target: string;
286
292
  limit?: number | undefined;
293
+ after?: string | undefined;
287
294
  }, signal: AbortSignal) => Promise<SourceRead>;
288
295
  joinSource: (caller: Caller, input: {
289
296
  key: string;
@@ -339,6 +346,7 @@ export declare function a2(options?: A2Options): {
339
346
  message: string | null;
340
347
  }[] | undefined;
341
348
  id?: string | undefined;
349
+ after?: string | undefined;
342
350
  } | {
343
351
  author: {
344
352
  id: string;
@@ -360,6 +368,7 @@ export declare function a2(options?: A2Options): {
360
368
  channel: string;
361
369
  thread: string;
362
370
  } | undefined;
371
+ revision?: number | undefined;
363
372
  } | {
364
373
  author: {
365
374
  id: string;
@@ -375,6 +384,7 @@ export declare function a2(options?: A2Options): {
375
384
  } | undefined;
376
385
  message?: string | undefined;
377
386
  op: "delete";
387
+ revision?: number | undefined;
378
388
  } | {
379
389
  author: {
380
390
  id: string;
@@ -409,6 +419,7 @@ export declare function a2(options?: A2Options): {
409
419
  op: "labels";
410
420
  set?: Record<string, string> | undefined;
411
421
  unset?: string[] | undefined;
422
+ if?: Record<string, string | null> | undefined;
412
423
  } | {
413
424
  author: {
414
425
  id: string;
@@ -601,6 +612,7 @@ export declare function a2(options?: A2Options): {
601
612
  type: string;
602
613
  title: string;
603
614
  url: string | null;
615
+ body?: string | null | undefined;
604
616
  labels: Record<string, string>;
605
617
  unset: string[];
606
618
  owns?: string[] | undefined;
@@ -992,6 +1004,7 @@ export declare function a2(options?: A2Options): {
992
1004
  type: z.ZodString;
993
1005
  title: z.ZodString;
994
1006
  url: z.ZodNullable<z.ZodString>;
1007
+ body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
995
1008
  labels: z.ZodRecord<z.ZodString, z.ZodString>;
996
1009
  unset: z.ZodArray<z.ZodString>;
997
1010
  owns: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -1,2 +1,3 @@
1
- import { n as fsBlob, r as memoryBlob, t as a2 } from "./a2-B0_VlbtC.mjs";
1
+ import { t as a2 } from "./a2-D_28Pdip.mjs";
2
+ import { a as fsBlob, s as memoryBlob } from "./blob-DQK5prXT.mjs";
2
3
  export { a2, fsBlob, memoryBlob };
@@ -1,5 +1,5 @@
1
- import { r as createHttp } from "./backend-http-CfLVYqmj.mjs";
2
- import { i as environmentProfile, n as boardUrl, r as connect } from "./node-Zd_C-gxP.mjs";
1
+ import { r as createHttp } from "./backend-http-BPaNYLWj.mjs";
2
+ import { i as environmentProfile, n as boardUrl, r as connect } from "./node-D8Rtg1su.mjs";
3
3
  //#region src/backend-http/index.ts
4
4
  const environment = {
5
5
  url: boardUrl,
@@ -1,6 +1,6 @@
1
- import { t as Actor, x as Attachment } from "./folds-jS9wlh9_.mjs";
2
- import { A as InboxItem, B as Me, D as IdentityView, Ft as ThreadView, H as MessagesPage, Ht as UploadTicket, I as LinkedAccount, It as ThreadsPage, K as PersonView, Nt as SyncedView, R as MatchView, S as EventsPage, St as SyncCopiesView, Tt as SyncFindView, V as MessageView, b as Discovery, bt as SyncCodeView, dt as SourceJoin, et as RegistrationView, jt as SyncThreadView, k as InboxEntry, mt as SourceRead, o as ProfileOption, ot as ScheduleView, v as ChannelView } from "./client-xLxeDz0f.mjs";
3
- import { i as Caller, n as BackendRoute, r as BoardBinding } from "./backend-ZKYTe3xa.mjs";
1
+ import { t as Actor, x as Attachment } from "./folds-8wRRXjAt.mjs";
2
+ import { A as InboxItem, Ct as SyncCopiesView, D as IdentityView, Et as SyncFindView, H as MessageView, It as ThreadView, L as LinkedAccount, Lt as ThreadsPage, Mt as SyncThreadView, Pt as SyncedView, S as EventsPage, U as MessagesPage, Ut as UploadTicket, V as Me, b as Discovery, ft as SourceJoin, ht as SourceRead, k as InboxEntry, o as ProfileOption, q as PersonView, st as ScheduleView, tt as RegistrationView, v as ChannelView, xt as SyncCodeView, z as MatchView } from "./client-CjAatpV4.mjs";
3
+ import { i as Caller, n as BackendRoute, r as BoardBinding } from "./backend-n3hajfrD.mjs";
4
4
  //#region src/server/backend-http.d.ts
5
5
  type HttpOptions = {
6
6
  /**
@@ -95,6 +95,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
95
95
  })[] | undefined;
96
96
  id?: string | undefined;
97
97
  attachments?: string[] | undefined;
98
+ after?: string | undefined;
98
99
  }, signal: AbortSignal) => Promise<{
99
100
  message: MessageView;
100
101
  unknownMentions?: string[];
@@ -108,12 +109,15 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
108
109
  id: string;
109
110
  } & {
110
111
  text: string;
112
+ revision?: number | undefined;
111
113
  }, signal: AbortSignal) => Promise<{
112
114
  ok: true;
113
115
  unknownMentions?: string[];
114
116
  }>;
115
117
  delete: (caller: Caller, input: {
116
118
  id: string;
119
+ } & {
120
+ revision?: number | undefined;
117
121
  }, signal: AbortSignal) => Promise<{
118
122
  ok: true;
119
123
  }>;
@@ -130,6 +134,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
130
134
  } & {
131
135
  set?: Record<string, string> | undefined;
132
136
  unset?: string[] | undefined;
137
+ if?: Record<string, string | null> | undefined;
133
138
  }, signal: AbortSignal) => Promise<{
134
139
  ok: true;
135
140
  }>;
@@ -181,6 +186,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
181
186
  name?: string | null | undefined;
182
187
  type?: string | null | undefined;
183
188
  size: number;
189
+ sha256?: string | undefined;
184
190
  }, signal: AbortSignal) => Promise<UploadTicket>;
185
191
  uploadFinish: (caller: Caller, input: {
186
192
  id: string;
@@ -258,6 +264,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
258
264
  } & {
259
265
  target: string;
260
266
  limit?: number | undefined;
267
+ after?: string | undefined;
261
268
  }, signal: AbortSignal) => Promise<SourceRead>;
262
269
  joinSource: (caller: Caller, input: {
263
270
  key: string;
@@ -313,6 +320,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
313
320
  message: string | null;
314
321
  }[] | undefined;
315
322
  id?: string | undefined;
323
+ after?: string | undefined;
316
324
  } | {
317
325
  author: {
318
326
  id: string;
@@ -334,6 +342,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
334
342
  channel: string;
335
343
  thread: string;
336
344
  } | undefined;
345
+ revision?: number | undefined;
337
346
  } | {
338
347
  author: {
339
348
  id: string;
@@ -349,6 +358,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
349
358
  } | undefined;
350
359
  message?: string | undefined;
351
360
  op: "delete";
361
+ revision?: number | undefined;
352
362
  } | {
353
363
  author: {
354
364
  id: string;
@@ -383,6 +393,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
383
393
  op: "labels";
384
394
  set?: Record<string, string> | undefined;
385
395
  unset?: string[] | undefined;
396
+ if?: Record<string, string | null> | undefined;
386
397
  } | {
387
398
  author: {
388
399
  id: string;
@@ -575,6 +586,7 @@ declare function createHttp(url: string | undefined, options: HttpOptions, envir
575
586
  type: string;
576
587
  title: string;
577
588
  url: string | null;
589
+ body?: string | null | undefined;
578
590
  labels: Record<string, string>;
579
591
  unset: string[];
580
592
  owns?: string[] | undefined;
@@ -1,9 +1,8 @@
1
1
  import "./files-SniSmeEr.mjs";
2
- import "./schemas-Be08nyfW.mjs";
3
- import { K as routes, O as RegisterBody, a as METHODS, n as compileWatcher, t as canonicalWatchers } from "./watchers-hash-7DJU9b-n.mjs";
4
- import { n as createBoardClient, t as BoardError } from "./client-D0Px7KzF.mjs";
2
+ import "./schemas-DBmUO6pr.mjs";
3
+ import { a as METHODS, k as RegisterBody, n as compileWatcher, q as routes, t as canonicalWatchers } from "./watchers-hash-B_5b0-ZG.mjs";
4
+ import { a as forbidden, d as createBoardClient, o as json, t as HttpError, u as BoardError } from "./errors-C_5rB8Iz.mjs";
5
5
  import { a as keyId, n as DERIVED_ID, o as sha256, r as derivedId, t as waitUntil } from "./wait-until-Dw4XrIDQ.mjs";
6
- import { a as forbidden, o as json, t as HttpError } from "./errors-CusN4x2l.mjs";
7
6
  //#region src/server/registrant.ts
8
7
  /** Registering again this soon after the same registration only repeats it. */
9
8
  const REGISTER_EVERY_MS = 1e4;
@@ -479,7 +478,7 @@ function createHttp(url, options, environment) {
479
478
  return discovery();
480
479
  },
481
480
  async readSource(caller, input, signal) {
482
- if ("self" in caller && bound().sync.some((entry) => entry.key === input.key)) return bound().readSource(input.key, input.target, input.limit ?? 50);
481
+ if ("self" in caller && bound().sync.some((entry) => entry.key === input.key)) return bound().readSource(input.key, input.target, input.limit ?? 50, input.after ?? null);
483
482
  return remoteCall("readSource", caller, input, signal);
484
483
  },
485
484
  async joinSource(caller, input, signal) {
@@ -1,4 +1,4 @@
1
- import { n as HttpOptions, t as HttpBackend } from "./backend-http-E7YU0qhn.mjs";
1
+ import { n as HttpOptions, t as HttpBackend } from "./backend-http-3PoBYQoo.mjs";
2
2
  //#region src/backend-http/index.default.d.ts
3
3
  /**
4
4
  * The board at `url`, which keeps the log. Outside Node there's no environment to find it or a
@@ -1,2 +1,2 @@
1
- import { t as http } from "./index.default-DmKxH_E6.mjs";
1
+ import { t as http } from "./index.default-DhkgpfR2.mjs";
2
2
  export { http };
@@ -1,4 +1,4 @@
1
- import { n as HttpOptions, t as HttpBackend } from "./backend-http-E7YU0qhn.mjs";
1
+ import { n as HttpOptions, t as HttpBackend } from "./backend-http-3PoBYQoo.mjs";
2
2
  //#region src/backend-http/index.d.ts
3
3
  /**
4
4
  * The board at `url`, which keeps the log: this board uses it as this deployment. Without a
@@ -1,2 +1,2 @@
1
- import { t as http } from "./backend-http-BvNFrvcY.mjs";
1
+ import { t as http } from "./backend-http-16SbvnAK.mjs";
2
2
  export { http };
@@ -1,9 +1,9 @@
1
1
  import { t as Access } from "./access-CV96SYgr.mjs";
2
2
  import { m as RuleFunction, n as AccessRule, r as Authenticate, s as Granted, t as AccessFunction, u as Known } from "./auth-CU56Q2Xh.mjs";
3
- import { A as Labels, C as Author, t as Actor, u as ExternalEvent, x as Attachment } from "./folds-jS9wlh9_.mjs";
4
- import { A as InboxItem, At as SyncRootsQuery, B as Me, C as EventsQuery, D as IdentityView, Et as SyncImportBody, Ft as ThreadView, H as MessagesPage, Ht as UploadTicket, I as LinkedAccount, It as ThreadsPage, K as PersonView, L as LinkedQuery, Lt as ThreadsQuery, M as InboxPushBody, Mt as SyncUnlinkBody, N as InboxQuery, Nt as SyncedView, O as InboxAckBody, Ot as SyncReceiptBody, P as LabelBody, Q as RegisterBody, R as MatchView, S as EventsPage, St as SyncCopiesView, Tt as SyncFindView, U as MessagesQuery, V as MessageView, Vt as UploadStartBody, X as ReactBody, _ as BoardEventView, b as Discovery, bt as SyncCodeView, dt as SourceJoin, et as RegistrationView, ft as SourceJoinBody, gt as SyncAccountBody, ht as SourceReadQuery, j as InboxNextQuery, jt as SyncThreadView, k as InboxEntry, m as AckBody, mt as SourceRead, o as ProfileOption, ot as ScheduleView, q as PostBody, rt as ScheduleBody, st as SchedulesQuery, t as BoardClient, v as ChannelView, wt as SyncFindQuery, x as EditBody, xt as SyncCopiesQuery, yt as SyncCodeBody, z as MatchesQuery, zt as TypingBody } from "./client-xLxeDz0f.mjs";
5
- import { t as HttpError } from "./errors-CB4tnZGz.mjs";
6
- import { p as SyncProvider } from "./provider-Cdg1qadh.mjs";
3
+ import { A as Labels, C as Author, t as Actor, u as ExternalEvent, x as Attachment } from "./folds-8wRRXjAt.mjs";
4
+ import { $ as RegisterBody, A as InboxItem, B as MatchesQuery, Bt as TypingBody, C as EventsQuery, Ct as SyncCopiesView, D as IdentityView, Dt as SyncImportBody, Et as SyncFindView, F as LabelBody, H as MessageView, Ht as UploadStartBody, It as ThreadView, J as PostBody, L as LinkedAccount, Lt as ThreadsPage, M as InboxPushBody, Mt as SyncThreadView, N as InboxQuery, Nt as SyncUnlinkBody, O as InboxAckBody, Pt as SyncedView, R as LinkedQuery, Rt as ThreadsQuery, S as EventsPage, St as SyncCopiesQuery, Tt as SyncFindQuery, U as MessagesPage, Ut as UploadTicket, V as Me, W as MessagesQuery, Z as ReactBody, _ as BoardEventView, _t as SyncAccountBody, b as Discovery, bt as SyncCodeBody, ct as SchedulesQuery, ft as SourceJoin, gt as SourceReadQuery, ht as SourceRead, it as ScheduleBody, j as InboxNextQuery, jt as SyncRootsQuery, k as InboxEntry, kt as SyncReceiptBody, m as AckBody, o as ProfileOption, pt as SourceJoinBody, q as PersonView, st as ScheduleView, t as BoardClient, tt as RegistrationView, v as ChannelView, x as EditBody, xt as SyncCodeView, y as DeleteBody, z as MatchView } from "./client-CjAatpV4.mjs";
5
+ import { t as HttpError } from "./errors-87TVtXeb.mjs";
6
+ import { p as SyncProvider } from "./provider-Bm46LAdp.mjs";
7
7
  import { z } from "zod";
8
8
  //#region src/api/protocol.d.ts
9
9
  type Input<S extends z.ZodType> = NonNullable<z.output<S>>;
@@ -82,7 +82,7 @@ type Protocol = {
82
82
  };
83
83
  };
84
84
  delete: {
85
- input: Id;
85
+ input: Id & Input<typeof DeleteBody>;
86
86
  output: {
87
87
  ok: true;
88
88
  };
@@ -616,7 +616,7 @@ type BoardBinding = {
616
616
  * Reads a platform channel or thread with sync entry `key`'s app, which only board() has: what
617
617
  * `readSource` answers. 404 `not_synced_here` for an entry it doesn't run.
618
618
  */
619
- readSource(key: string, target: string, limit: number): Promise<SourceRead>;
619
+ readSource(key: string, target: string, limit: number, after: string | null): Promise<SourceRead>;
620
620
  /** Adds sync entry `key`'s app to a channel, where it opted in: what `joinSource` answers. 404 `not_synced_here` likewise. */
621
621
  joinSource(key: string, target: string): Promise<SourceJoin>;
622
622
  /**
@@ -671,6 +671,12 @@ interface Backend extends ProtocolMethods {
671
671
  * project.
672
672
  */
673
673
  readonly keeps: boolean;
674
+ /**
675
+ * Whether a schedule's sends come back through board(), as a2()'s do, so its middleware screens
676
+ * each. A backend whose sends post elsewhere, as vercel()'s do from Vercel's API, says false, and
677
+ * board() screens a schedule's message once, when it's made. True when left out.
678
+ */
679
+ readonly sendsSchedulesHere?: boolean;
674
680
  /**
675
681
  * board() calls it once, when it's created, before any request: what background work needs
676
682
  * from the board (its subscriptions, its sync, its policy, a handle through it). It does no I/O.