@rocicorp/zero 1.4.0-canary.5 → 1.5.0-canary.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 (200) hide show
  1. package/out/analyze-query/src/analyze-cli.js +2 -2
  2. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  3. package/out/zero/package.js +1 -1
  4. package/out/zero/package.js.map +1 -1
  5. package/out/zero-cache/src/auth/auth.d.ts +1 -1
  6. package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
  7. package/out/zero-cache/src/auth/auth.js +1 -1
  8. package/out/zero-cache/src/auth/auth.js.map +1 -1
  9. package/out/zero-cache/src/auth/write-authorizer.d.ts +1 -1
  10. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  11. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  12. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  13. package/out/zero-cache/src/config/normalize.js +8 -0
  14. package/out/zero-cache/src/config/normalize.js.map +1 -1
  15. package/out/zero-cache/src/config/zero-config.d.ts +8 -4
  16. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  17. package/out/zero-cache/src/config/zero-config.js +28 -6
  18. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  19. package/out/zero-cache/src/custom/fetch.d.ts +1 -1
  20. package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
  21. package/out/zero-cache/src/custom/fetch.js +2 -2
  22. package/out/zero-cache/src/custom/fetch.js.map +1 -1
  23. package/out/zero-cache/src/custom-queries/transform-query.d.ts +21 -7
  24. package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
  25. package/out/zero-cache/src/custom-queries/transform-query.js +26 -9
  26. package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
  27. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  28. package/out/zero-cache/src/server/change-streamer.js +2 -1
  29. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  30. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  31. package/out/zero-cache/src/server/runner/run-worker.js +5 -2
  32. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  33. package/out/zero-cache/src/server/syncer.js +3 -3
  34. package/out/zero-cache/src/server/syncer.js.map +1 -1
  35. package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
  36. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  37. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  38. package/out/zero-cache/src/services/change-source/pg/change-source.js +24 -20
  39. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  40. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +258 -45
  41. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  42. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +119 -83
  43. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  44. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  45. package/out/zero-cache/src/services/change-source/pg/schema/init.js +1 -1
  46. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  47. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
  48. package/out/zero-cache/src/services/change-source/pg/schema/shard.js +11 -2
  49. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
  50. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +1 -0
  51. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  52. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +3 -3
  53. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  54. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  55. package/out/zero-cache/src/services/change-streamer/storer.js +3 -3
  56. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  57. package/out/zero-cache/src/services/http-service.d.ts +1 -0
  58. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  59. package/out/zero-cache/src/services/http-service.js +5 -4
  60. package/out/zero-cache/src/services/http-service.js.map +1 -1
  61. package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
  62. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  63. package/out/zero-cache/src/services/life-cycle.js +1 -2
  64. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  65. package/out/zero-cache/src/services/mutagen/mutagen.d.ts +1 -1
  66. package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
  67. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
  68. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  69. package/out/zero-cache/src/services/mutagen/pusher.d.ts +4 -3
  70. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  71. package/out/zero-cache/src/services/mutagen/pusher.js +57 -38
  72. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  73. package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
  74. package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
  75. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js +2 -1
  76. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
  77. package/out/zero-cache/src/services/view-syncer/client-handler.js +1 -1
  78. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  79. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +39 -27
  80. package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +1 -1
  81. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +138 -102
  82. package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
  83. package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
  84. package/out/zero-cache/src/services/view-syncer/cvr-store.js +22 -2
  85. package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
  86. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +6 -0
  87. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  88. package/out/zero-cache/src/services/view-syncer/cvr.js +8 -0
  89. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  90. package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
  91. package/out/zero-cache/src/services/view-syncer/row-record-cache.js +27 -3
  92. package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
  93. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +3 -3
  94. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  95. package/out/zero-cache/src/services/view-syncer/view-syncer.js +115 -86
  96. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  97. package/out/zero-cache/src/workers/connection.js +2 -2
  98. package/out/zero-cache/src/workers/connection.js.map +1 -1
  99. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +1 -1
  100. package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
  101. package/out/zero-cache/src/workers/syncer-ws-message-handler.js +7 -7
  102. package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
  103. package/out/zero-cache/src/workers/syncer.d.ts +1 -1
  104. package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
  105. package/out/zero-cache/src/workers/syncer.js +11 -10
  106. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  107. package/out/zero-client/src/client/connection.d.ts +15 -7
  108. package/out/zero-client/src/client/connection.d.ts.map +1 -1
  109. package/out/zero-client/src/client/connection.js.map +1 -1
  110. package/out/zero-client/src/client/crud-impl.d.ts +1 -1
  111. package/out/zero-client/src/client/crud-impl.d.ts.map +1 -1
  112. package/out/zero-client/src/client/crud-impl.js +1 -1
  113. package/out/zero-client/src/client/crud-impl.js.map +1 -1
  114. package/out/zero-client/src/client/crud.d.ts +1 -1
  115. package/out/zero-client/src/client/crud.d.ts.map +1 -1
  116. package/out/zero-client/src/client/crud.js +1 -1
  117. package/out/zero-client/src/client/crud.js.map +1 -1
  118. package/out/zero-client/src/client/keys.d.ts +1 -1
  119. package/out/zero-client/src/client/keys.d.ts.map +1 -1
  120. package/out/zero-client/src/client/keys.js.map +1 -1
  121. package/out/zero-client/src/client/make-replicache-mutators.js +1 -1
  122. package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
  123. package/out/zero-client/src/client/mutation-tracker.d.ts +2 -1
  124. package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
  125. package/out/zero-client/src/client/mutation-tracker.js +3 -3
  126. package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
  127. package/out/zero-client/src/client/version.js +1 -1
  128. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  129. package/out/zero-client/src/client/zero.js +2 -2
  130. package/out/zero-client/src/client/zero.js.map +1 -1
  131. package/out/zero-client/src/types/client-state.d.ts +1 -1
  132. package/out/zero-client/src/types/client-state.d.ts.map +1 -1
  133. package/out/zero-protocol/src/custom-queries.js +1 -1
  134. package/out/zero-protocol/src/down.js +1 -1
  135. package/out/zero-protocol/src/error-kind-enum.d.ts +1 -2
  136. package/out/zero-protocol/src/error-kind-enum.d.ts.map +1 -1
  137. package/out/zero-protocol/src/error-kind-enum.js.map +1 -1
  138. package/out/zero-protocol/src/mutate-server.d.ts +165 -0
  139. package/out/zero-protocol/src/mutate-server.d.ts.map +1 -0
  140. package/out/zero-protocol/src/mutate-server.js +24 -0
  141. package/out/zero-protocol/src/mutate-server.js.map +1 -0
  142. package/out/zero-protocol/src/mutation.d.ts +229 -0
  143. package/out/zero-protocol/src/mutation.d.ts.map +1 -0
  144. package/out/zero-protocol/src/mutation.js +112 -0
  145. package/out/zero-protocol/src/mutation.js.map +1 -0
  146. package/out/zero-protocol/src/mutations-patch.js +1 -1
  147. package/out/zero-protocol/src/mutations-patch.js.map +1 -1
  148. package/out/zero-protocol/src/push.d.ts +3 -234
  149. package/out/zero-protocol/src/push.d.ts.map +1 -1
  150. package/out/zero-protocol/src/push.js +3 -114
  151. package/out/zero-protocol/src/push.js.map +1 -1
  152. package/out/zero-protocol/src/query-server.d.ts +150 -0
  153. package/out/zero-protocol/src/query-server.d.ts.map +1 -0
  154. package/out/zero-protocol/src/query-server.js +16 -0
  155. package/out/zero-protocol/src/query-server.js.map +1 -0
  156. package/out/zero-protocol/src/up.js +1 -1
  157. package/out/zero-server/src/mod.d.ts +4 -2
  158. package/out/zero-server/src/mod.d.ts.map +1 -1
  159. package/out/zero-server/src/process-mutations.d.ts +41 -4
  160. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  161. package/out/zero-server/src/process-mutations.js +52 -35
  162. package/out/zero-server/src/process-mutations.js.map +1 -1
  163. package/out/zero-server/src/push-processor.d.ts +3 -3
  164. package/out/zero-server/src/push-processor.d.ts.map +1 -1
  165. package/out/zero-server/src/push-processor.js.map +1 -1
  166. package/out/zero-server/src/queries/process-queries.d.ts +22 -52
  167. package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
  168. package/out/zero-server/src/queries/process-queries.js +50 -49
  169. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  170. package/out/zero-server/src/zql-database.js.map +1 -1
  171. package/out/zero-types/src/default-types.d.ts +1 -0
  172. package/out/zero-types/src/default-types.d.ts.map +1 -1
  173. package/out/zql/src/builder/builder.d.ts.map +1 -1
  174. package/out/zql/src/builder/builder.js +17 -7
  175. package/out/zql/src/builder/builder.js.map +1 -1
  176. package/out/zql/src/ivm/cap.d.ts +32 -0
  177. package/out/zql/src/ivm/cap.d.ts.map +1 -0
  178. package/out/zql/src/ivm/cap.js +205 -0
  179. package/out/zql/src/ivm/cap.js.map +1 -0
  180. package/out/zql/src/ivm/constraint.js +1 -1
  181. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  182. package/out/zql/src/ivm/flipped-join.js +61 -15
  183. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  184. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  185. package/out/zql/src/ivm/memory-source.js +3 -4
  186. package/out/zql/src/ivm/memory-source.js.map +1 -1
  187. package/out/zql/src/ivm/schema.d.ts +8 -0
  188. package/out/zql/src/ivm/schema.d.ts.map +1 -1
  189. package/out/zql/src/ivm/take.js +2 -2
  190. package/out/zql/src/mutate/mutator-registry.js.map +1 -1
  191. package/out/zql/src/mutate/mutator.d.ts +11 -2
  192. package/out/zql/src/mutate/mutator.d.ts.map +1 -1
  193. package/out/zql/src/mutate/mutator.js.map +1 -1
  194. package/out/zql/src/query/query-registry.d.ts +9 -2
  195. package/out/zql/src/query/query-registry.d.ts.map +1 -1
  196. package/out/zql/src/query/query-registry.js.map +1 -1
  197. package/out/zqlite/src/table-source.d.ts.map +1 -1
  198. package/out/zqlite/src/table-source.js +4 -1
  199. package/out/zqlite/src/table-source.js.map +1 -1
  200. package/package.json +1 -1
@@ -9,20 +9,17 @@ import { authEquals, resolveAuth } from "../../auth/auth.js";
9
9
  *
10
10
  * Connections are registered as `provisional`, optionally backfilled with
11
11
  * `initConnection` metadata, and then promoted to `validated` once their
12
- * stored `userID` is confirmed as valid. The manager also tracks which
12
+ * effective `userID` is confirmed as valid. The manager also tracks which
13
13
  * validated connection currently serves as the group's background connection.
14
- *
15
- * This is intentionally side-effect free.
16
14
  */
17
15
  var ConnectionContextManagerImpl = class {
18
16
  #lc;
19
17
  #connections = /* @__PURE__ */ new Map();
20
18
  #group = {
21
- userID: void 0,
19
+ pinnedUser: void 0,
22
20
  backgroundConnection: void 0,
23
21
  retransformAt: void 0,
24
- maintenanceNotBeforeAt: void 0,
25
- validated: false
22
+ maintenanceNotBeforeAt: void 0
26
23
  };
27
24
  #validateLegacyJWT;
28
25
  #now;
@@ -48,49 +45,39 @@ var ConnectionContextManagerImpl = class {
48
45
  */
49
46
  registerConnection(selector, connectParams, auth) {
50
47
  this.#removeConnection(selector);
51
- const sharedHeaders = {
52
- customHeaders: void 0,
53
- token: auth?.raw,
54
- origin: connectParams.origin,
55
- userID: connectParams.userID
48
+ const getContext = (type) => {
49
+ const config = type === "query" ? this.#queryConfig : this.#pushConfig;
50
+ return {
51
+ url: config?.url?.[0],
52
+ allowedUrlPatterns: config?.url?.map(compileUrlPattern),
53
+ headerOptions: {
54
+ customHeaders: void 0,
55
+ origin: connectParams.origin,
56
+ apiKey: config?.apiKey,
57
+ allowedClientHeaders: cloneAllowedClientHeaders(config?.allowedClientHeaders),
58
+ cookie: config?.forwardCookies ? connectParams.httpCookie : void 0
59
+ }
60
+ };
56
61
  };
57
62
  const connection = {
58
63
  state: "provisional",
59
64
  clientID: connectParams.clientID,
60
65
  wsID: connectParams.wsID,
61
66
  revision: 0,
62
- userID: connectParams.userID,
67
+ user: { id: connectParams.userID ?? null },
63
68
  auth,
64
69
  profileID: connectParams.profileID,
65
70
  baseCookie: connectParams.baseCookie,
66
71
  protocolVersion: connectParams.protocolVersion,
67
72
  revalidateAt: void 0,
68
- queryContext: {
69
- url: this.#queryConfig?.url?.[0],
70
- allowedUrlPatterns: this.#queryConfig?.url?.map(compileUrlPattern),
71
- headerOptions: {
72
- ...sharedHeaders,
73
- apiKey: this.#queryConfig?.apiKey,
74
- allowedClientHeaders: this.#queryConfig?.allowedClientHeaders,
75
- cookie: this.#queryConfig?.forwardCookies ? connectParams.httpCookie : void 0
76
- }
77
- },
78
- pushContext: {
79
- url: this.#pushConfig?.url?.[0],
80
- allowedUrlPatterns: this.#pushConfig?.url?.map(compileUrlPattern),
81
- headerOptions: {
82
- ...sharedHeaders,
83
- apiKey: this.#pushConfig?.apiKey,
84
- allowedClientHeaders: this.#pushConfig?.allowedClientHeaders,
85
- cookie: this.#pushConfig?.forwardCookies ? connectParams.httpCookie : void 0
86
- }
87
- },
73
+ queryContext: getContext("query"),
74
+ mutateContext: getContext("mutate"),
88
75
  insertionOrder: ++this.#nextInsertionOrder
89
76
  };
90
- this.#connections.set(connection.clientID, connection);
77
+ this.#storeConnection(connection);
91
78
  this.#refreshBackgroundConnectionContext();
92
79
  this.#updateBackgroundRetransformDeadline(false);
93
- return snapshotConnection(connection);
80
+ return connection;
94
81
  }
95
82
  /**
96
83
  * Backfills `initConnection` data for sockets that were registered before the
@@ -100,13 +87,36 @@ var ConnectionContextManagerImpl = class {
100
87
  */
101
88
  initConnection(selector, body) {
102
89
  const connection = this.#mustGetConnectionContext(selector);
103
- if (body.userQueryURL) connection.queryContext.url = body.userQueryURL;
104
- if (body.userQueryHeaders) connection.queryContext.headerOptions.customHeaders = body.userQueryHeaders;
105
- if (body.userPushURL) connection.pushContext.url = body.userPushURL;
106
- if (body.userPushHeaders) connection.pushContext.headerOptions.customHeaders = body.userPushHeaders;
107
- connection.revision++;
108
- this.#demoteConnection(connection);
109
- return snapshotConnection(connection);
90
+ let queryContext = connection.queryContext;
91
+ let mutateContext = connection.mutateContext;
92
+ if (body.userQueryURL) queryContext = {
93
+ ...queryContext,
94
+ url: body.userQueryURL
95
+ };
96
+ if (body.userQueryHeaders) queryContext = {
97
+ ...queryContext,
98
+ headerOptions: {
99
+ ...queryContext.headerOptions,
100
+ customHeaders: cloneCustomHeaders(body.userQueryHeaders)
101
+ }
102
+ };
103
+ if (body.userPushURL) mutateContext = {
104
+ ...mutateContext,
105
+ url: body.userPushURL
106
+ };
107
+ if (body.userPushHeaders) mutateContext = {
108
+ ...mutateContext,
109
+ headerOptions: {
110
+ ...mutateContext.headerOptions,
111
+ customHeaders: cloneCustomHeaders(body.userPushHeaders)
112
+ }
113
+ };
114
+ return this.#demoteConnection({
115
+ ...connection,
116
+ revision: connection.revision + 1,
117
+ queryContext,
118
+ mutateContext
119
+ });
110
120
  }
111
121
  /**
112
122
  * A material auth change demotes the connection back to provisional until it
@@ -114,14 +124,17 @@ var ConnectionContextManagerImpl = class {
114
124
  */
115
125
  async updateAuth(selector, body) {
116
126
  const connection = this.#mustGetConnectionContext(selector);
117
- const nextAuth = await resolveAuth(this.#lc, connection.auth, connection.userID, body.auth, this.#validateLegacyJWT);
118
- const authChanged = !authEquals(connection.auth, nextAuth);
119
- connection.auth = nextAuth;
120
- if (authChanged) {
121
- connection.revision++;
122
- this.#demoteConnection(connection);
123
- }
124
- return snapshotConnection(connection);
127
+ const nextAuth = await resolveAuth(this.#lc, connection.auth, connection.user.id, body.auth, this.#validateLegacyJWT);
128
+ if (!authEquals(connection.auth, nextAuth)) return this.#demoteConnection({
129
+ ...connection,
130
+ auth: nextAuth,
131
+ revision: connection.revision + 1
132
+ });
133
+ if (nextAuth === connection.auth) return connection;
134
+ return this.#storeConnection({
135
+ ...connection,
136
+ auth: nextAuth
137
+ });
125
138
  }
126
139
  /**
127
140
  * Validates one connection against the group's pinned `userID`.
@@ -132,7 +145,7 @@ var ConnectionContextManagerImpl = class {
132
145
  * background connection if none is currently available. If the websocket is
133
146
  * gone by the time async validation finishes, this becomes a no-op.
134
147
  */
135
- validateConnection(selector, revision) {
148
+ validateConnection(selector, revision, validation) {
136
149
  const connection = this.#getConnectionContext(selector);
137
150
  if (!connection) return;
138
151
  if (connection.revision !== revision) {
@@ -143,21 +156,34 @@ var ConnectionContextManagerImpl = class {
143
156
  });
144
157
  return;
145
158
  }
146
- if (this.#group.validated && this.#group.userID !== connection.userID) throw new ProtocolErrorWithLevel({
159
+ let validatedUserState;
160
+ if (validation.kind === "server-validated") {
161
+ validatedUserState = { id: validation.validatedUserID };
162
+ if (connection.user.id !== validatedUserState.id) throw new ProtocolErrorWithLevel({
163
+ kind: Unauthorized,
164
+ message: "Connection userID does not match validated server userID.",
165
+ origin: ZeroCache
166
+ }, "warn");
167
+ }
168
+ const incomingUserState = validatedUserState ?? connection.user;
169
+ if (this.#group.pinnedUser !== void 0 && this.#group.pinnedUser.id !== incomingUserState.id) throw new ProtocolErrorWithLevel({
147
170
  kind: Unauthorized,
148
171
  message: "Client groups are pinned to a single userID. Connection userID does not match existing client group userID.",
149
172
  origin: ZeroCache
150
173
  }, "warn");
151
- if (!this.#group.validated) {
152
- this.#group.validated = true;
153
- this.#group.userID = connection.userID;
154
- }
155
- connection.state = "validated";
156
- connection.revalidateAt = this.#nextRevalidateAt();
157
- this.#refreshBackgroundConnectionContext(connection);
174
+ if (this.#group.pinnedUser === void 0) this.#setGroup({
175
+ ...this.#group,
176
+ pinnedUser: incomingUserState
177
+ });
178
+ const validatedConnection = this.#storeConnection({
179
+ ...connection,
180
+ state: "validated",
181
+ revalidateAt: this.#nextRevalidateAt()
182
+ });
183
+ this.#refreshBackgroundConnectionContext(validatedConnection);
158
184
  this.#updateBackgroundRetransformDeadline(false);
159
185
  return {
160
- connection: snapshotConnection(connection),
186
+ connection: validatedConnection,
161
187
  group: this.getGroupState()
162
188
  };
163
189
  }
@@ -177,25 +203,28 @@ var ConnectionContextManagerImpl = class {
177
203
  markBackgroundRetransformSuccess(selector, revision) {
178
204
  const backgroundConnection = this.#getBackgroundConnectionContext();
179
205
  if (!backgroundConnection) return;
180
- if (selector !== void 0 && (backgroundConnection.clientID !== selector.clientID || backgroundConnection.wsID !== selector.wsID || backgroundConnection.revision !== revision)) return;
206
+ if (backgroundConnection.clientID !== selector.clientID || backgroundConnection.wsID !== selector.wsID || backgroundConnection.revision !== revision) return;
181
207
  this.#updateBackgroundRetransformDeadline(true);
182
208
  }
183
209
  deferMaintenance(kind) {
184
210
  const intervalMs = kind === "revalidate" ? this.#revalidateIntervalMs : this.#retransformIntervalMs;
185
211
  if (intervalMs === void 0) return;
186
- this.#group.maintenanceNotBeforeAt = Math.max(this.#group.maintenanceNotBeforeAt ?? 0, this.#now() + intervalMs);
212
+ this.#setGroup({
213
+ ...this.#group,
214
+ maintenanceNotBeforeAt: Math.max(this.#group.maintenanceNotBeforeAt ?? 0, this.#now() + intervalMs)
215
+ });
187
216
  }
188
217
  /** Returns the current live record for a client slot, if any. */
189
218
  getConnectionContext(selector) {
190
- return snapshotConnection(this.#getConnectionContext(selector));
219
+ return this.#getConnectionContext(selector);
191
220
  }
192
221
  /** Returns the live record for one websocket or throws if it is unavailable. */
193
222
  mustGetConnectionContext(selector) {
194
- return snapshotConnection(this.#mustGetConnectionContext(selector));
223
+ return this.#mustGetConnectionContext(selector);
195
224
  }
196
225
  /** Returns the current background connection, if one exists. */
197
226
  getBackgroundConnectionContext() {
198
- return snapshotConnection(this.#getBackgroundConnectionContext());
227
+ return this.#getBackgroundConnectionContext();
199
228
  }
200
229
  mustGetBackgroundConnectionContext() {
201
230
  const backgroundConnection = this.#getBackgroundConnectionContext();
@@ -208,7 +237,7 @@ var ConnectionContextManagerImpl = class {
208
237
  }
209
238
  /** Returns the shared group auth state. */
210
239
  getGroupState() {
211
- return snapshotGroup(this.#group);
240
+ return this.#group;
212
241
  }
213
242
  /**
214
243
  * Reports which maintenance work is currently due.
@@ -224,7 +253,7 @@ var ConnectionContextManagerImpl = class {
224
253
  let earliestDeadlineAt = this.#group.retransformAt;
225
254
  for (const connection of this.#connections.values()) {
226
255
  if (connection.state !== "validated" || connection.revalidateAt === void 0) continue;
227
- if (connection.revalidateAt <= now) dueRevalidations.push(snapshotConnection(connection));
256
+ if (connection.revalidateAt <= now) dueRevalidations.push(connection);
228
257
  earliestDeadlineAt = minDefined(earliestDeadlineAt, connection.revalidateAt);
229
258
  }
230
259
  const dueRetransform = this.#group.retransformAt !== void 0 && this.#group.retransformAt <= now;
@@ -252,17 +281,20 @@ var ConnectionContextManagerImpl = class {
252
281
  });
253
282
  return;
254
283
  }
255
- const snapshot = snapshotConnection(connection);
256
284
  this.#connections.delete(connection.clientID);
257
285
  this.#refreshBackgroundConnectionContext();
258
286
  this.#updateBackgroundRetransformDeadline(false);
259
- return snapshot;
287
+ return connection;
260
288
  }
261
289
  #demoteConnection(connection) {
262
- connection.state = "provisional";
263
- connection.revalidateAt = void 0;
290
+ const demotedConnection = this.#storeConnection({
291
+ ...connection,
292
+ state: "provisional",
293
+ revalidateAt: void 0
294
+ });
264
295
  this.#refreshBackgroundConnectionContext();
265
296
  this.#updateBackgroundRetransformDeadline(false);
297
+ return demotedConnection;
266
298
  }
267
299
  /**
268
300
  * Keeps the background connection sticky while it remains validated.
@@ -277,10 +309,10 @@ var ConnectionContextManagerImpl = class {
277
309
  const currentBackgroundConnection = this.#getBackgroundConnectionContext();
278
310
  if (currentBackgroundConnection?.clientID === preferred.clientID && currentBackgroundConnection.wsID === preferred.wsID) return;
279
311
  if (currentBackgroundConnection !== void 0) return;
280
- this.#group.backgroundConnection = {
312
+ this.#setBackgroundConnection({
281
313
  clientID: preferred.clientID,
282
314
  wsID: preferred.wsID
283
- };
315
+ });
284
316
  this.#lc.debug?.("Selected background connection for shared auth work", {
285
317
  clientID: preferred.clientID,
286
318
  wsID: preferred.wsID,
@@ -291,10 +323,10 @@ var ConnectionContextManagerImpl = class {
291
323
  }
292
324
  if (this.#getBackgroundConnectionContext()?.state === "validated") return;
293
325
  const nextBackgroundConnection = [...this.#connections.values()].filter((connection) => connection.state === "validated").sort(comparePreferredValidatedConnection).at(0);
294
- this.#group.backgroundConnection = nextBackgroundConnection ? {
326
+ this.#setBackgroundConnection(nextBackgroundConnection ? {
295
327
  clientID: nextBackgroundConnection.clientID,
296
328
  wsID: nextBackgroundConnection.wsID
297
- } : void 0;
329
+ } : void 0);
298
330
  if (nextBackgroundConnection) this.#lc.debug?.("Selected background connection for shared auth work", {
299
331
  clientID: nextBackgroundConnection.clientID,
300
332
  wsID: nextBackgroundConnection.wsID,
@@ -322,6 +354,21 @@ var ConnectionContextManagerImpl = class {
322
354
  }, "warn");
323
355
  return connection;
324
356
  }
357
+ #storeConnection(connection) {
358
+ this.#connections.set(connection.clientID, connection);
359
+ return connection;
360
+ }
361
+ #setGroup(group) {
362
+ this.#group = group;
363
+ return group;
364
+ }
365
+ #setBackgroundConnection(backgroundConnection) {
366
+ if (sameConnectionSelector(this.#group.backgroundConnection, backgroundConnection)) return;
367
+ this.#setGroup({
368
+ ...this.#group,
369
+ backgroundConnection: backgroundConnection ? { ...backgroundConnection } : void 0
370
+ });
371
+ }
325
372
  /**
326
373
  * Keeps the group background retransform deadline coherent with current
327
374
  * schedulability.
@@ -333,41 +380,21 @@ var ConnectionContextManagerImpl = class {
333
380
  */
334
381
  #updateBackgroundRetransformDeadline(reset) {
335
382
  if (!this.#getBackgroundConnectionContext() || this.#retransformIntervalMs === void 0) {
336
- this.#group.retransformAt = void 0;
383
+ if (this.#group.retransformAt !== void 0) this.#setGroup({
384
+ ...this.#group,
385
+ retransformAt: void 0
386
+ });
337
387
  return;
338
388
  }
339
- if (reset || this.#group.retransformAt === void 0) this.#group.retransformAt = this.#now() + this.#retransformIntervalMs;
389
+ if (reset || this.#group.retransformAt === void 0) this.#setGroup({
390
+ ...this.#group,
391
+ retransformAt: this.#now() + this.#retransformIntervalMs
392
+ });
340
393
  }
341
394
  #nextRevalidateAt() {
342
395
  return this.#revalidateIntervalMs === void 0 ? void 0 : this.#now() + this.#revalidateIntervalMs;
343
396
  }
344
397
  };
345
- function snapshotConnection(connection) {
346
- if (!connection) return;
347
- return {
348
- ...connection,
349
- queryContext: {
350
- ...connection.queryContext,
351
- headerOptions: {
352
- ...connection.queryContext.headerOptions,
353
- customHeaders: connection.queryContext.headerOptions.customHeaders ? { ...connection.queryContext.headerOptions.customHeaders } : void 0
354
- }
355
- },
356
- pushContext: {
357
- ...connection.pushContext,
358
- headerOptions: {
359
- ...connection.pushContext.headerOptions,
360
- customHeaders: connection.pushContext.headerOptions.customHeaders ? { ...connection.pushContext.headerOptions.customHeaders } : void 0
361
- }
362
- }
363
- };
364
- }
365
- function snapshotGroup(group) {
366
- return {
367
- ...group,
368
- backgroundConnection: group.backgroundConnection ? { ...group.backgroundConnection } : void 0
369
- };
370
- }
371
398
  function compareByInsertionOrder(a, b) {
372
399
  return a.insertionOrder - b.insertionOrder || a.wsID.localeCompare(b.wsID);
373
400
  }
@@ -379,6 +406,15 @@ function minDefined(a, b) {
379
406
  if (b === void 0) return a;
380
407
  return Math.min(a, b);
381
408
  }
409
+ function sameConnectionSelector(a, b) {
410
+ return a?.clientID === b?.clientID && a?.wsID === b?.wsID;
411
+ }
412
+ function cloneCustomHeaders(headers) {
413
+ return headers ? { ...headers } : void 0;
414
+ }
415
+ function cloneAllowedClientHeaders(headers) {
416
+ return headers ? [...headers] : void 0;
417
+ }
382
418
  //#endregion
383
419
  export { ConnectionContextManagerImpl };
384
420
 
@@ -1 +1 @@
1
- {"version":3,"file":"connection-context-manager.js","names":["#lc","#connections","#group","#validateLegacyJWT","#now","#revalidateIntervalMs","#retransformIntervalMs","#queryConfig","#pushConfig","#removeConnection","#nextInsertionOrder","#refreshBackgroundConnectionContext","#updateBackgroundRetransformDeadline","#mustGetConnectionContext","#demoteConnection","#getConnectionContext","#nextRevalidateAt","#getBackgroundConnectionContext"],"sources":["../../../../../../zero-cache/src/services/view-syncer/connection-context-manager.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {InitConnectionBody} from '../../../../zero-protocol/src/connect.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport type {UpdateAuthBody} from '../../../../zero-protocol/src/update-auth.ts';\nimport {\n authEquals,\n resolveAuth,\n type Auth,\n type ValidateLegacyJWT,\n} from '../../auth/auth.ts';\nimport type {ZeroConfig} from '../../config/zero-config.ts';\nimport {compileUrlPattern} from '../../custom/fetch.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {ConnectParams} from '../../workers/connect-params.ts';\n\nexport type ConnectionState = 'provisional' | 'validated';\n\n/**\n * Identifies one live websocket for a client slot.\n */\nexport type ConnectionSelector = {\n readonly clientID: string;\n readonly wsID: string;\n};\n\ntype FetchConfig = ZeroConfig['query'];\n\nexport type HeaderOptions = {\n apiKey?: string | undefined;\n customHeaders?: Record<string, string> | undefined;\n allowedClientHeaders?: readonly string[] | undefined;\n cookie?: string | undefined;\n origin?: string | undefined;\n};\n\nexport type ConnectionFetchContext = {\n url: string | undefined;\n allowedUrlPatterns: URLPattern[] | undefined;\n headerOptions: HeaderOptions;\n};\n\n/**\n * A snapshot of one live connection tracked by the manager.\n *\n * `revalidateAt` is only populated while the connection is `validated`.\n */\nexport type ConnectionContext = {\n state: ConnectionState;\n\n readonly clientID: string;\n readonly wsID: string;\n readonly userID: string | undefined;\n\n auth: Auth | undefined;\n\n readonly profileID: string | null;\n readonly baseCookie: string | null;\n readonly protocolVersion: number;\n\n revision: number;\n\n revalidateAt: number | undefined;\n\n readonly insertionOrder: number;\n\n readonly queryContext: ConnectionFetchContext;\n readonly pushContext: ConnectionFetchContext;\n};\n\n/**\n * Group-scoped auth state shared across the live connections.\n *\n * The background connection is the validated connection currently used for\n * shared background work. Retransform happens on a group level, and uses\n * the background connection's credential to refetch the latest queries.\n *\n * Since auth can be pinned to logged-out users, `userID` can be undefined\n * even after validation.\n */\nexport type GroupAuthState = {\n userID: string | undefined;\n validated: boolean;\n\n backgroundConnection: ConnectionSelector | undefined;\n retransformAt: number | undefined;\n // Defer all maintenance in case a transient failure occurs.\n maintenanceNotBeforeAt: number | undefined;\n};\n\nexport type ConnectionContextManager = {\n registerConnection(\n selector: ConnectionSelector,\n connectParams: ConnectParams,\n auth?: Auth,\n ): Readonly<ConnectionContext>;\n\n initConnection(\n selector: ConnectionSelector,\n body: InitConnectionBody,\n ): Readonly<ConnectionContext>;\n\n updateAuth(\n selector: ConnectionSelector,\n body: UpdateAuthBody,\n ): Promise<Readonly<ConnectionContext>>;\n\n validateConnection(\n selector: ConnectionSelector,\n revision: number,\n ):\n | Readonly<{\n connection: ConnectionContext;\n group: GroupAuthState;\n }>\n | undefined;\n\n failConnection(\n selector: ConnectionSelector,\n revision: number,\n ): Readonly<ConnectionContext> | undefined;\n closeConnection(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined;\n\n markBackgroundRetransformSuccess(\n selector: ConnectionSelector,\n revision: number,\n ): void;\n\n deferMaintenance(kind: 'revalidate' | 'retransform'): void;\n\n getConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined;\n mustGetConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext>;\n\n getBackgroundConnectionContext(): Readonly<ConnectionContext> | undefined;\n mustGetBackgroundConnectionContext(): Readonly<ConnectionContext>;\n\n getGroupState(): Readonly<GroupAuthState>;\n\n planMaintenance(): {\n dueRevalidations: Readonly<ConnectionContext>[];\n dueRetransform: boolean;\n earliestDeadlineAt: number | undefined;\n };\n};\n\n/**\n * State machine for the auth state of a single `ViewSyncerService`.\n *\n * Connections are registered as `provisional`, optionally backfilled with\n * `initConnection` metadata, and then promoted to `validated` once their\n * stored `userID` is confirmed as valid. The manager also tracks which\n * validated connection currently serves as the group's background connection.\n *\n * This is intentionally side-effect free.\n */\nexport class ConnectionContextManagerImpl implements ConnectionContextManager {\n readonly #lc: LogContext;\n\n // The live connection records, keyed by clientID\n readonly #connections = new Map<string, ConnectionContext>();\n readonly #group: GroupAuthState = {\n userID: undefined,\n backgroundConnection: undefined,\n retransformAt: undefined,\n maintenanceNotBeforeAt: undefined,\n validated: false,\n };\n\n readonly #validateLegacyJWT: ValidateLegacyJWT | undefined;\n\n readonly #now: () => number;\n readonly #revalidateIntervalMs: number | undefined;\n readonly #retransformIntervalMs: number | undefined;\n readonly #queryConfig: FetchConfig | undefined;\n readonly #pushConfig: FetchConfig | undefined;\n #nextInsertionOrder = 0;\n\n constructor(\n lc: LogContext,\n revalidateIntervalSeconds?: number,\n retransformIntervalSeconds?: number,\n queryConfig?: FetchConfig,\n pushConfig?: FetchConfig,\n validateLegacyJWT?: ValidateLegacyJWT,\n now?: () => number,\n ) {\n this.#lc = lc;\n this.#now = now ?? Date.now;\n this.#revalidateIntervalMs =\n revalidateIntervalSeconds === undefined\n ? undefined\n : revalidateIntervalSeconds * 1000;\n this.#retransformIntervalMs =\n retransformIntervalSeconds === undefined\n ? undefined\n : retransformIntervalSeconds * 1000;\n this.#queryConfig = queryConfig;\n this.#pushConfig = pushConfig;\n this.#validateLegacyJWT = validateLegacyJWT;\n }\n\n /**\n * Creates or replaces the live record for a websocket connection.\n *\n * Re-registering the same `clientID` drops the old socket record and starts\n * the replacement back in `provisional` state.\n */\n registerConnection(\n selector: ConnectionSelector,\n connectParams: ConnectParams,\n auth?: Auth,\n ): Readonly<ConnectionContext> {\n this.#removeConnection(selector);\n\n const sharedHeaders = {\n customHeaders: undefined,\n token: auth?.raw,\n origin: connectParams.origin,\n userID: connectParams.userID,\n };\n\n const connection: ConnectionContext = {\n state: 'provisional',\n\n clientID: connectParams.clientID,\n wsID: connectParams.wsID,\n revision: 0,\n userID: connectParams.userID,\n auth,\n\n profileID: connectParams.profileID,\n baseCookie: connectParams.baseCookie,\n protocolVersion: connectParams.protocolVersion,\n\n revalidateAt: undefined,\n\n queryContext: {\n url: this.#queryConfig?.url?.[0],\n allowedUrlPatterns: this.#queryConfig?.url?.map(compileUrlPattern),\n headerOptions: {\n ...sharedHeaders,\n apiKey: this.#queryConfig?.apiKey,\n allowedClientHeaders: this.#queryConfig?.allowedClientHeaders,\n cookie: this.#queryConfig?.forwardCookies\n ? connectParams.httpCookie\n : undefined,\n },\n },\n pushContext: {\n url: this.#pushConfig?.url?.[0],\n allowedUrlPatterns: this.#pushConfig?.url?.map(compileUrlPattern),\n headerOptions: {\n ...sharedHeaders,\n apiKey: this.#pushConfig?.apiKey,\n allowedClientHeaders: this.#pushConfig?.allowedClientHeaders,\n cookie: this.#pushConfig?.forwardCookies\n ? connectParams.httpCookie\n : undefined,\n },\n },\n\n insertionOrder: ++this.#nextInsertionOrder,\n };\n this.#connections.set(connection.clientID, connection);\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n return snapshotConnection(connection);\n }\n\n /**\n * Backfills `initConnection` data for sockets that were registered before the\n * client could send its full init payload.\n *\n * This updates metadata only; it does not validate the connection.\n */\n initConnection(\n selector: ConnectionSelector,\n body: InitConnectionBody,\n ): Readonly<ConnectionContext> {\n const connection = this.#mustGetConnectionContext(selector);\n\n if (body.userQueryURL) {\n connection.queryContext.url = body.userQueryURL;\n }\n if (body.userQueryHeaders) {\n connection.queryContext.headerOptions.customHeaders =\n body.userQueryHeaders;\n }\n if (body.userPushURL) {\n connection.pushContext.url = body.userPushURL;\n }\n if (body.userPushHeaders) {\n connection.pushContext.headerOptions.customHeaders = body.userPushHeaders;\n }\n\n connection.revision++;\n this.#demoteConnection(connection);\n\n return snapshotConnection(connection);\n }\n\n /**\n * A material auth change demotes the connection back to provisional until it\n * is validated again.\n */\n async updateAuth(\n selector: ConnectionSelector,\n body: UpdateAuthBody,\n ): Promise<Readonly<ConnectionContext>> {\n const connection = this.#mustGetConnectionContext(selector);\n\n const nextAuth = await resolveAuth(\n this.#lc,\n connection.auth,\n connection.userID,\n body.auth,\n this.#validateLegacyJWT,\n );\n\n const authChanged = !authEquals(connection.auth, nextAuth);\n connection.auth = nextAuth;\n if (authChanged) {\n connection.revision++;\n this.#demoteConnection(connection);\n }\n\n return snapshotConnection(connection);\n }\n\n /**\n * Validates one connection against the group's pinned `userID`.\n *\n * The first successful validation binds the group `userID`. Later\n * validations must match it. Validation also refreshes the connection's\n * revalidation deadline and may pick the connection as the group\n * background connection if none is currently available. If the websocket is\n * gone by the time async validation finishes, this becomes a no-op.\n */\n validateConnection(\n selector: ConnectionSelector,\n revision: number,\n ):\n | Readonly<{\n connection: ConnectionContext;\n group: GroupAuthState;\n }>\n | undefined {\n const connection = this.#getConnectionContext(selector);\n if (!connection) {\n return undefined;\n }\n\n if (connection.revision !== revision) {\n this.#lc.debug?.('Skipping validateConnection for stale revision', {\n clientID: selector.clientID,\n attemptedRevision: revision,\n currentRevision: connection.revision,\n });\n return undefined;\n }\n\n if (this.#group.validated && this.#group.userID !== connection.userID) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Unauthorized,\n message:\n 'Client groups are pinned to a single userID. Connection userID does not match existing client group userID.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n\n if (!this.#group.validated) {\n this.#group.validated = true;\n this.#group.userID = connection.userID;\n }\n\n connection.state = 'validated';\n connection.revalidateAt = this.#nextRevalidateAt();\n this.#refreshBackgroundConnectionContext(connection);\n this.#updateBackgroundRetransformDeadline(false);\n\n return {\n connection: snapshotConnection(connection),\n group: this.getGroupState(),\n };\n }\n\n /** Removes one connection due to failed auth and updates all derived background/deadline state. */\n failConnection(\n selector: ConnectionSelector,\n revision: number,\n ): ConnectionContext | undefined {\n return this.#removeConnection(selector, revision);\n }\n\n /** Removes one disconnected connection and updates all derived background/deadline state. */\n closeConnection(selector: ConnectionSelector): ConnectionContext | undefined {\n return this.#removeConnection(selector);\n }\n\n /**\n * Records a successful background retransform. This starts a fresh interval\n * from the manager clock when shared retransform is schedulable, or\n * clears the deadline if it is not.\n */\n markBackgroundRetransformSuccess(\n selector: ConnectionSelector,\n revision: number,\n ): void {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection) {\n return;\n }\n if (\n selector !== undefined &&\n (backgroundConnection.clientID !== selector.clientID ||\n backgroundConnection.wsID !== selector.wsID ||\n backgroundConnection.revision !== revision)\n ) {\n return;\n }\n this.#updateBackgroundRetransformDeadline(true);\n }\n\n deferMaintenance(kind: 'revalidate' | 'retransform'): void {\n const intervalMs =\n kind === 'revalidate'\n ? this.#revalidateIntervalMs\n : this.#retransformIntervalMs;\n if (intervalMs === undefined) {\n return;\n }\n this.#group.maintenanceNotBeforeAt = Math.max(\n this.#group.maintenanceNotBeforeAt ?? 0,\n this.#now() + intervalMs,\n );\n }\n\n /** Returns the current live record for a client slot, if any. */\n getConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined {\n return snapshotConnection(this.#getConnectionContext(selector));\n }\n\n /** Returns the live record for one websocket or throws if it is unavailable. */\n mustGetConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> {\n return snapshotConnection(this.#mustGetConnectionContext(selector));\n }\n\n /** Returns the current background connection, if one exists. */\n getBackgroundConnectionContext(): Readonly<ConnectionContext> | undefined {\n return snapshotConnection(this.#getBackgroundConnectionContext());\n }\n\n mustGetBackgroundConnectionContext(): Readonly<ConnectionContext> {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.InvalidConnectionRequest,\n message:\n 'No validated connection is available for shared query work.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n return backgroundConnection;\n }\n\n /** Returns the shared group auth state. */\n getGroupState(): Readonly<GroupAuthState> {\n return snapshotGroup(this.#group);\n }\n\n /**\n * Reports which maintenance work is currently due.\n *\n * The result is a pure snapshot: callers decide which actions to run and\n * when to wake up next. `earliestDeadlineAt` is the earliest outstanding\n * maintenance deadline, including overdue work, unless a transient failure\n * has deferred all scheduled maintenance until `maintenanceNotBeforeAt`.\n */\n planMaintenance(): {\n dueRevalidations: Readonly<ConnectionContext>[];\n dueRetransform: boolean;\n earliestDeadlineAt: number | undefined;\n } {\n const dueRevalidations: Readonly<ConnectionContext>[] = [];\n const now = this.#now();\n let earliestDeadlineAt = this.#group.retransformAt;\n\n for (const connection of this.#connections.values()) {\n if (\n connection.state !== 'validated' ||\n connection.revalidateAt === undefined\n ) {\n continue;\n }\n if (connection.revalidateAt <= now) {\n dueRevalidations.push(snapshotConnection(connection));\n }\n earliestDeadlineAt = minDefined(\n earliestDeadlineAt,\n connection.revalidateAt,\n );\n }\n\n const dueRetransform =\n this.#group.retransformAt !== undefined &&\n this.#group.retransformAt <= now;\n const maintenanceNotBeforeAt = this.#group.maintenanceNotBeforeAt;\n\n if (\n maintenanceNotBeforeAt !== undefined &&\n maintenanceNotBeforeAt > now &&\n earliestDeadlineAt !== undefined\n ) {\n return {\n dueRevalidations: [],\n dueRetransform: false,\n earliestDeadlineAt: Math.max(\n earliestDeadlineAt,\n maintenanceNotBeforeAt,\n ),\n };\n }\n\n return {\n dueRevalidations: dueRevalidations.sort(compareByInsertionOrder),\n dueRetransform,\n earliestDeadlineAt,\n };\n }\n\n #removeConnection(\n selector: ConnectionSelector,\n revision?: number,\n ): Readonly<ConnectionContext> | undefined {\n const connection = this.#getConnectionContext(selector);\n\n if (!connection) {\n return undefined;\n }\n\n // If the revision has changed, we should not remove the connection\n if (revision !== undefined && connection.revision !== revision) {\n this.#lc.debug?.('Ignoring failConnection for stale revision', {\n clientID: selector.clientID,\n wsID: selector.wsID,\n attemptedRevision: revision,\n currentRevision: connection.revision,\n });\n return undefined;\n }\n\n const snapshot = snapshotConnection(connection);\n\n this.#connections.delete(connection.clientID);\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n\n return snapshot;\n }\n\n #demoteConnection(connection: ConnectionContext): void {\n connection.state = 'provisional';\n connection.revalidateAt = undefined;\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n }\n\n /**\n * Keeps the background connection sticky while it remains validated.\n *\n * When a newly validated `preferred` connection is provided, it is promoted\n * only if there is no current validated background connection. Otherwise the\n * existing background connection stays in place until it disappears or is\n * demoted, at which point the newest validated connection is selected.\n */\n #refreshBackgroundConnectionContext(preferred?: ConnectionContext): void {\n if (preferred?.state === 'validated') {\n const currentBackgroundConnection =\n this.#getBackgroundConnectionContext();\n if (\n currentBackgroundConnection?.clientID === preferred.clientID &&\n currentBackgroundConnection.wsID === preferred.wsID\n ) {\n return;\n }\n if (currentBackgroundConnection !== undefined) {\n return;\n }\n this.#group.backgroundConnection = {\n clientID: preferred.clientID,\n wsID: preferred.wsID,\n };\n this.#lc.debug?.('Selected background connection for shared auth work', {\n clientID: preferred.clientID,\n wsID: preferred.wsID,\n revision: preferred.revision,\n reason: 'preferred-validated',\n });\n return;\n }\n\n const currentBackgroundConnection = this.#getBackgroundConnectionContext();\n if (currentBackgroundConnection?.state === 'validated') {\n return;\n }\n\n const nextBackgroundConnection = [...this.#connections.values()]\n .filter(connection => connection.state === 'validated')\n .sort(comparePreferredValidatedConnection)\n .at(0);\n this.#group.backgroundConnection = nextBackgroundConnection\n ? {\n clientID: nextBackgroundConnection.clientID,\n wsID: nextBackgroundConnection.wsID,\n }\n : undefined;\n if (nextBackgroundConnection) {\n this.#lc.debug?.('Selected background connection for shared auth work', {\n clientID: nextBackgroundConnection.clientID,\n wsID: nextBackgroundConnection.wsID,\n revision: nextBackgroundConnection.revision,\n reason: 'fallback-validated',\n });\n }\n }\n\n #getBackgroundConnectionContext(): ConnectionContext | undefined {\n const backgroundConnection = this.#group.backgroundConnection;\n if (!backgroundConnection) {\n return undefined;\n }\n return this.#getConnectionContext(backgroundConnection);\n }\n\n #getConnectionContext(\n selector: ConnectionSelector,\n ): ConnectionContext | undefined {\n const connection = this.#connections.get(selector.clientID);\n if (!connection) {\n return undefined;\n }\n if (connection.wsID !== selector.wsID) {\n return undefined;\n }\n return connection;\n }\n\n #mustGetConnectionContext(selector: ConnectionSelector): ConnectionContext {\n const connection = this.#getConnectionContext(selector);\n\n if (!connection) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.InvalidConnectionRequest,\n message:\n 'Connection auth state was not available for this websocket.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n\n return connection;\n }\n\n /**\n * Keeps the group background retransform deadline coherent with current\n * schedulability.\n *\n * When `reset` is false, this seeds a deadline only when shared retransform\n * is now possible and no deadline exists yet, preserving any existing\n * cadence. When `reset` is true, it starts a fresh interval from `#now()` if\n * retransform is schedulable, or clears the deadline if it is not.\n */\n #updateBackgroundRetransformDeadline(reset: boolean) {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection || this.#retransformIntervalMs === undefined) {\n this.#group.retransformAt = undefined;\n return;\n }\n\n if (reset || this.#group.retransformAt === undefined) {\n this.#group.retransformAt = this.#now() + this.#retransformIntervalMs;\n }\n }\n\n #nextRevalidateAt() {\n return this.#revalidateIntervalMs === undefined\n ? undefined\n : this.#now() + this.#revalidateIntervalMs;\n }\n}\n\nfunction snapshotConnection<T extends ConnectionContext | undefined>(\n connection: T,\n): T extends undefined ? T | undefined : Readonly<T> {\n if (!connection) {\n return undefined as T extends undefined ? T | undefined : Readonly<T>;\n }\n return {\n ...connection,\n queryContext: {\n ...connection.queryContext,\n headerOptions: {\n ...connection.queryContext.headerOptions,\n customHeaders: connection.queryContext.headerOptions.customHeaders\n ? {...connection.queryContext.headerOptions.customHeaders}\n : undefined,\n },\n },\n pushContext: {\n ...connection.pushContext,\n headerOptions: {\n ...connection.pushContext.headerOptions,\n customHeaders: connection.pushContext.headerOptions.customHeaders\n ? {...connection.pushContext.headerOptions.customHeaders}\n : undefined,\n },\n },\n } as T extends undefined ? T | undefined : Readonly<T>;\n}\n\nfunction snapshotGroup(group: GroupAuthState): Readonly<GroupAuthState> {\n return {\n ...group,\n backgroundConnection: group.backgroundConnection\n ? {...group.backgroundConnection}\n : undefined,\n };\n}\n\nfunction compareByInsertionOrder(\n a: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n b: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n) {\n return a.insertionOrder - b.insertionOrder || a.wsID.localeCompare(b.wsID);\n}\n\nfunction comparePreferredValidatedConnection(\n a: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n b: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n) {\n return b.insertionOrder - a.insertionOrder || b.wsID.localeCompare(a.wsID);\n}\n\nfunction minDefined(a: number | undefined, b: number | undefined) {\n if (a === undefined) {\n return b;\n }\n if (b === undefined) {\n return a;\n }\n return Math.min(a, b);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"connection-context-manager.js","names":["#lc","#connections","#validateLegacyJWT","#now","#revalidateIntervalMs","#retransformIntervalMs","#queryConfig","#pushConfig","#removeConnection","#nextInsertionOrder","#storeConnection","#refreshBackgroundConnectionContext","#updateBackgroundRetransformDeadline","#mustGetConnectionContext","#demoteConnection","#getConnectionContext","#group","#setGroup","#nextRevalidateAt","#getBackgroundConnectionContext","#setBackgroundConnection"],"sources":["../../../../../../zero-cache/src/services/view-syncer/connection-context-manager.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {InitConnectionBody} from '../../../../zero-protocol/src/connect.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport type {UpdateAuthBody} from '../../../../zero-protocol/src/update-auth.ts';\nimport {\n authEquals,\n resolveAuth,\n type Auth,\n type ValidateLegacyJWT,\n} from '../../auth/auth.ts';\nimport type {ZeroConfig} from '../../config/zero-config.ts';\nimport {compileUrlPattern} from '../../custom/fetch.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {ConnectParams} from '../../workers/connect-params.ts';\n\nexport type ConnectionState = 'provisional' | 'validated';\n\n/**\n * Normalized user identity shared by live connection state and group auth state.\n * `id: null` means logged out.\n */\nexport type UserState = {readonly id: string | null};\n\n/**\n * Delineates the two paths for validating a connection: either server can validate\n * the user's identity and return a definitive userID to trust, or we fall back to\n * trusting the one provided by the client in the incoming query params.\n */\nexport type ConnectionValidation =\n | {kind: 'client-fallback'}\n | {kind: 'server-validated'; validatedUserID: string | null};\n\n/**\n * Identifies one live websocket for a client slot.\n */\nexport type ConnectionSelector = {\n readonly clientID: string;\n readonly wsID: string;\n};\n\ntype FetchConfig = ZeroConfig['query'];\n\nexport type HeaderOptions = {\n readonly apiKey?: string | undefined;\n readonly customHeaders?: Readonly<Record<string, string>> | undefined;\n readonly allowedClientHeaders?: readonly string[] | undefined;\n readonly cookie?: string | undefined;\n readonly origin?: string | undefined;\n};\n\nexport type ConnectionFetchContext = {\n readonly url: string | undefined;\n readonly allowedUrlPatterns: readonly URLPattern[] | undefined;\n readonly headerOptions: HeaderOptions;\n};\n\n/**\n * A snapshot of one live connection tracked by the manager.\n *\n * `revalidateAt` is only populated while the connection is `validated`.\n */\nexport type ConnectionContext = {\n readonly state: ConnectionState;\n\n readonly clientID: string;\n readonly wsID: string;\n readonly user: UserState;\n\n readonly auth: Auth | undefined;\n\n readonly profileID: string | null;\n readonly baseCookie: string | null;\n readonly protocolVersion: number;\n\n readonly revision: number;\n\n readonly revalidateAt: number | undefined;\n\n readonly insertionOrder: number;\n\n readonly queryContext: ConnectionFetchContext;\n readonly mutateContext: ConnectionFetchContext;\n};\n\n/**\n * Group-scoped auth state shared across the live connections.\n *\n * The background connection is the validated connection currently used for\n * shared background work. Retransform happens on a group level, and uses\n * the background connection's credential to refetch the latest queries.\n */\nexport type GroupAuthState = {\n readonly pinnedUser: UserState | undefined;\n\n readonly backgroundConnection: ConnectionSelector | undefined;\n readonly retransformAt: number | undefined;\n // Defer all maintenance in case a transient failure occurs.\n readonly maintenanceNotBeforeAt: number | undefined;\n};\n\nexport type ConnectionContextManager = {\n registerConnection(\n selector: ConnectionSelector,\n connectParams: ConnectParams,\n auth?: Auth,\n ): Readonly<ConnectionContext>;\n\n initConnection(\n selector: ConnectionSelector,\n body: InitConnectionBody,\n ): Readonly<ConnectionContext>;\n\n updateAuth(\n selector: ConnectionSelector,\n body: UpdateAuthBody,\n ): Promise<Readonly<ConnectionContext>>;\n\n validateConnection(\n selector: ConnectionSelector,\n revision: number,\n validation: ConnectionValidation,\n ):\n | Readonly<{\n connection: ConnectionContext;\n group: GroupAuthState;\n }>\n | undefined;\n\n failConnection(\n selector: ConnectionSelector,\n revision: number,\n ): Readonly<ConnectionContext> | undefined;\n closeConnection(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined;\n\n markBackgroundRetransformSuccess(\n selector: ConnectionSelector,\n revision: number,\n ): void;\n\n deferMaintenance(kind: 'revalidate' | 'retransform'): void;\n\n getConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined;\n mustGetConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext>;\n\n getBackgroundConnectionContext(): Readonly<ConnectionContext> | undefined;\n mustGetBackgroundConnectionContext(): Readonly<ConnectionContext>;\n\n getGroupState(): Readonly<GroupAuthState>;\n\n planMaintenance(): {\n dueRevalidations: Readonly<ConnectionContext>[];\n dueRetransform: boolean;\n earliestDeadlineAt: number | undefined;\n };\n};\n\n/**\n * State machine for the auth state of a single `ViewSyncerService`.\n *\n * Connections are registered as `provisional`, optionally backfilled with\n * `initConnection` metadata, and then promoted to `validated` once their\n * effective `userID` is confirmed as valid. The manager also tracks which\n * validated connection currently serves as the group's background connection.\n */\nexport class ConnectionContextManagerImpl implements ConnectionContextManager {\n readonly #lc: LogContext;\n\n // The live connection records, keyed by clientID\n readonly #connections = new Map<string, ConnectionContext>();\n #group: GroupAuthState = {\n pinnedUser: undefined,\n backgroundConnection: undefined,\n retransformAt: undefined,\n maintenanceNotBeforeAt: undefined,\n };\n\n readonly #validateLegacyJWT: ValidateLegacyJWT | undefined;\n\n readonly #now: () => number;\n readonly #revalidateIntervalMs: number | undefined;\n readonly #retransformIntervalMs: number | undefined;\n readonly #queryConfig: FetchConfig | undefined;\n readonly #pushConfig: FetchConfig | undefined;\n #nextInsertionOrder = 0;\n\n constructor(\n lc: LogContext,\n revalidateIntervalSeconds?: number,\n retransformIntervalSeconds?: number,\n queryConfig?: FetchConfig,\n pushConfig?: FetchConfig,\n validateLegacyJWT?: ValidateLegacyJWT,\n now?: () => number,\n ) {\n this.#lc = lc;\n this.#now = now ?? Date.now;\n this.#revalidateIntervalMs =\n revalidateIntervalSeconds === undefined\n ? undefined\n : revalidateIntervalSeconds * 1000;\n this.#retransformIntervalMs =\n retransformIntervalSeconds === undefined\n ? undefined\n : retransformIntervalSeconds * 1000;\n this.#queryConfig = queryConfig;\n this.#pushConfig = pushConfig;\n this.#validateLegacyJWT = validateLegacyJWT;\n }\n\n /**\n * Creates or replaces the live record for a websocket connection.\n *\n * Re-registering the same `clientID` drops the old socket record and starts\n * the replacement back in `provisional` state.\n */\n registerConnection(\n selector: ConnectionSelector,\n connectParams: ConnectParams,\n auth?: Auth,\n ): Readonly<ConnectionContext> {\n this.#removeConnection(selector);\n\n const getContext = (type: 'query' | 'mutate'): ConnectionFetchContext => {\n const config = type === 'query' ? this.#queryConfig : this.#pushConfig;\n\n return {\n url: config?.url?.[0],\n allowedUrlPatterns: config?.url?.map(compileUrlPattern),\n headerOptions: {\n customHeaders: undefined,\n origin: connectParams.origin,\n apiKey: config?.apiKey,\n allowedClientHeaders: cloneAllowedClientHeaders(\n config?.allowedClientHeaders,\n ),\n cookie: config?.forwardCookies ? connectParams.httpCookie : undefined,\n },\n };\n };\n\n const connection: ConnectionContext = {\n state: 'provisional',\n\n clientID: connectParams.clientID,\n wsID: connectParams.wsID,\n revision: 0,\n user: {id: connectParams.userID ?? null},\n auth,\n\n profileID: connectParams.profileID,\n baseCookie: connectParams.baseCookie,\n protocolVersion: connectParams.protocolVersion,\n\n revalidateAt: undefined,\n\n queryContext: getContext('query'),\n mutateContext: getContext('mutate'),\n\n insertionOrder: ++this.#nextInsertionOrder,\n };\n this.#storeConnection(connection);\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n return connection;\n }\n\n /**\n * Backfills `initConnection` data for sockets that were registered before the\n * client could send its full init payload.\n *\n * This updates metadata only; it does not validate the connection.\n */\n initConnection(\n selector: ConnectionSelector,\n body: InitConnectionBody,\n ): Readonly<ConnectionContext> {\n const connection = this.#mustGetConnectionContext(selector);\n\n let queryContext = connection.queryContext;\n let mutateContext = connection.mutateContext;\n\n if (body.userQueryURL) {\n queryContext = {\n ...queryContext,\n url: body.userQueryURL,\n };\n }\n if (body.userQueryHeaders) {\n queryContext = {\n ...queryContext,\n headerOptions: {\n ...queryContext.headerOptions,\n customHeaders: cloneCustomHeaders(body.userQueryHeaders),\n },\n };\n }\n if (body.userPushURL) {\n mutateContext = {\n ...mutateContext,\n url: body.userPushURL,\n };\n }\n if (body.userPushHeaders) {\n mutateContext = {\n ...mutateContext,\n headerOptions: {\n ...mutateContext.headerOptions,\n customHeaders: cloneCustomHeaders(body.userPushHeaders),\n },\n };\n }\n\n return this.#demoteConnection({\n ...connection,\n revision: connection.revision + 1,\n queryContext,\n mutateContext,\n });\n }\n\n /**\n * A material auth change demotes the connection back to provisional until it\n * is validated again.\n */\n async updateAuth(\n selector: ConnectionSelector,\n body: UpdateAuthBody,\n ): Promise<Readonly<ConnectionContext>> {\n const connection = this.#mustGetConnectionContext(selector);\n\n const nextAuth = await resolveAuth(\n this.#lc,\n connection.auth,\n connection.user.id,\n body.auth,\n this.#validateLegacyJWT,\n );\n\n const authChanged = !authEquals(connection.auth, nextAuth);\n if (authChanged) {\n return this.#demoteConnection({\n ...connection,\n auth: nextAuth,\n revision: connection.revision + 1,\n });\n }\n\n if (nextAuth === connection.auth) {\n return connection;\n }\n\n return this.#storeConnection({\n ...connection,\n auth: nextAuth,\n });\n }\n\n /**\n * Validates one connection against the group's pinned `userID`.\n *\n * The first successful validation binds the group `userID`. Later\n * validations must match it. Validation also refreshes the connection's\n * revalidation deadline and may pick the connection as the group\n * background connection if none is currently available. If the websocket is\n * gone by the time async validation finishes, this becomes a no-op.\n */\n validateConnection(\n selector: ConnectionSelector,\n revision: number,\n validation: ConnectionValidation,\n ):\n | Readonly<{\n connection: ConnectionContext;\n group: GroupAuthState;\n }>\n | undefined {\n const connection = this.#getConnectionContext(selector);\n if (!connection) {\n return undefined;\n }\n\n if (connection.revision !== revision) {\n this.#lc.debug?.('Skipping validateConnection for stale revision', {\n clientID: selector.clientID,\n attemptedRevision: revision,\n currentRevision: connection.revision,\n });\n return undefined;\n }\n\n let validatedUserState: UserState | undefined;\n\n // If the API server has validated the user's identity, we ensure that\n // the connection's claimed userID matches it.\n if (validation.kind === 'server-validated') {\n validatedUserState = {id: validation.validatedUserID};\n\n // Check that the ws connection userID provided by the client\n // matches the validated userID from the API server.\n if (connection.user.id !== validatedUserState.id) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Unauthorized,\n message:\n 'Connection userID does not match validated server userID.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n }\n\n // The incoming user state is either the validated user state from the server\n // or the WS client's claimed user state if no server validation occurred.\n const incomingUserState = validatedUserState ?? connection.user;\n\n // Once a client group is validated, every later validated connection must\n // agree with that pinned identity.\n if (\n this.#group.pinnedUser !== undefined &&\n this.#group.pinnedUser.id !== incomingUserState.id\n ) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.Unauthorized,\n message:\n 'Client groups are pinned to a single userID. Connection userID does not match existing client group userID.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n\n if (this.#group.pinnedUser === undefined) {\n this.#setGroup({\n ...this.#group,\n pinnedUser: incomingUserState,\n });\n }\n\n const validatedConnection = this.#storeConnection({\n ...connection,\n state: 'validated',\n revalidateAt: this.#nextRevalidateAt(),\n });\n this.#refreshBackgroundConnectionContext(validatedConnection);\n this.#updateBackgroundRetransformDeadline(false);\n\n return {\n connection: validatedConnection,\n group: this.getGroupState(),\n };\n }\n\n /** Removes one connection due to failed auth and updates all derived background/deadline state. */\n failConnection(\n selector: ConnectionSelector,\n revision: number,\n ): ConnectionContext | undefined {\n return this.#removeConnection(selector, revision);\n }\n\n /** Removes one disconnected connection and updates all derived background/deadline state. */\n closeConnection(selector: ConnectionSelector): ConnectionContext | undefined {\n return this.#removeConnection(selector);\n }\n\n /**\n * Records a successful background retransform. This starts a fresh interval\n * from the manager clock when shared retransform is schedulable, or\n * clears the deadline if it is not.\n */\n markBackgroundRetransformSuccess(\n selector: ConnectionSelector,\n revision: number,\n ): void {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection) {\n return;\n }\n if (\n backgroundConnection.clientID !== selector.clientID ||\n backgroundConnection.wsID !== selector.wsID ||\n backgroundConnection.revision !== revision\n ) {\n return;\n }\n this.#updateBackgroundRetransformDeadline(true);\n }\n\n deferMaintenance(kind: 'revalidate' | 'retransform'): void {\n const intervalMs =\n kind === 'revalidate'\n ? this.#revalidateIntervalMs\n : this.#retransformIntervalMs;\n if (intervalMs === undefined) {\n return;\n }\n this.#setGroup({\n ...this.#group,\n maintenanceNotBeforeAt: Math.max(\n this.#group.maintenanceNotBeforeAt ?? 0,\n this.#now() + intervalMs,\n ),\n });\n }\n\n /** Returns the current live record for a client slot, if any. */\n getConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> | undefined {\n return this.#getConnectionContext(selector);\n }\n\n /** Returns the live record for one websocket or throws if it is unavailable. */\n mustGetConnectionContext(\n selector: ConnectionSelector,\n ): Readonly<ConnectionContext> {\n return this.#mustGetConnectionContext(selector);\n }\n\n /** Returns the current background connection, if one exists. */\n getBackgroundConnectionContext(): Readonly<ConnectionContext> | undefined {\n return this.#getBackgroundConnectionContext();\n }\n\n mustGetBackgroundConnectionContext(): Readonly<ConnectionContext> {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.InvalidConnectionRequest,\n message:\n 'No validated connection is available for shared query work.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n return backgroundConnection;\n }\n\n /** Returns the shared group auth state. */\n getGroupState(): Readonly<GroupAuthState> {\n return this.#group;\n }\n\n /**\n * Reports which maintenance work is currently due.\n *\n * The result is a pure snapshot: callers decide which actions to run and\n * when to wake up next. `earliestDeadlineAt` is the earliest outstanding\n * maintenance deadline, including overdue work, unless a transient failure\n * has deferred all scheduled maintenance until `maintenanceNotBeforeAt`.\n */\n planMaintenance(): {\n dueRevalidations: Readonly<ConnectionContext>[];\n dueRetransform: boolean;\n earliestDeadlineAt: number | undefined;\n } {\n const dueRevalidations: Readonly<ConnectionContext>[] = [];\n const now = this.#now();\n let earliestDeadlineAt = this.#group.retransformAt;\n\n for (const connection of this.#connections.values()) {\n if (\n connection.state !== 'validated' ||\n connection.revalidateAt === undefined\n ) {\n continue;\n }\n if (connection.revalidateAt <= now) {\n dueRevalidations.push(connection);\n }\n earliestDeadlineAt = minDefined(\n earliestDeadlineAt,\n connection.revalidateAt,\n );\n }\n\n const dueRetransform =\n this.#group.retransformAt !== undefined &&\n this.#group.retransformAt <= now;\n const maintenanceNotBeforeAt = this.#group.maintenanceNotBeforeAt;\n\n if (\n maintenanceNotBeforeAt !== undefined &&\n maintenanceNotBeforeAt > now &&\n earliestDeadlineAt !== undefined\n ) {\n return {\n dueRevalidations: [],\n dueRetransform: false,\n earliestDeadlineAt: Math.max(\n earliestDeadlineAt,\n maintenanceNotBeforeAt,\n ),\n };\n }\n\n return {\n dueRevalidations: dueRevalidations.sort(compareByInsertionOrder),\n dueRetransform,\n earliestDeadlineAt,\n };\n }\n\n #removeConnection(\n selector: ConnectionSelector,\n revision?: number,\n ): Readonly<ConnectionContext> | undefined {\n const connection = this.#getConnectionContext(selector);\n\n if (!connection) {\n return undefined;\n }\n\n // If the revision has changed, we should not remove the connection\n if (revision !== undefined && connection.revision !== revision) {\n this.#lc.debug?.('Ignoring failConnection for stale revision', {\n clientID: selector.clientID,\n wsID: selector.wsID,\n attemptedRevision: revision,\n currentRevision: connection.revision,\n });\n return undefined;\n }\n\n this.#connections.delete(connection.clientID);\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n\n return connection;\n }\n\n #demoteConnection(connection: ConnectionContext): ConnectionContext {\n const demotedConnection = this.#storeConnection({\n ...connection,\n state: 'provisional',\n revalidateAt: undefined,\n });\n this.#refreshBackgroundConnectionContext();\n this.#updateBackgroundRetransformDeadline(false);\n return demotedConnection;\n }\n\n /**\n * Keeps the background connection sticky while it remains validated.\n *\n * When a newly validated `preferred` connection is provided, it is promoted\n * only if there is no current validated background connection. Otherwise the\n * existing background connection stays in place until it disappears or is\n * demoted, at which point the newest validated connection is selected.\n */\n #refreshBackgroundConnectionContext(preferred?: ConnectionContext): void {\n if (preferred?.state === 'validated') {\n const currentBackgroundConnection =\n this.#getBackgroundConnectionContext();\n if (\n currentBackgroundConnection?.clientID === preferred.clientID &&\n currentBackgroundConnection.wsID === preferred.wsID\n ) {\n return;\n }\n if (currentBackgroundConnection !== undefined) {\n return;\n }\n this.#setBackgroundConnection({\n clientID: preferred.clientID,\n wsID: preferred.wsID,\n });\n this.#lc.debug?.('Selected background connection for shared auth work', {\n clientID: preferred.clientID,\n wsID: preferred.wsID,\n revision: preferred.revision,\n reason: 'preferred-validated',\n });\n return;\n }\n\n const currentBackgroundConnection = this.#getBackgroundConnectionContext();\n if (currentBackgroundConnection?.state === 'validated') {\n return;\n }\n\n const nextBackgroundConnection = [...this.#connections.values()]\n .filter(connection => connection.state === 'validated')\n .sort(comparePreferredValidatedConnection)\n .at(0);\n this.#setBackgroundConnection(\n nextBackgroundConnection\n ? {\n clientID: nextBackgroundConnection.clientID,\n wsID: nextBackgroundConnection.wsID,\n }\n : undefined,\n );\n if (nextBackgroundConnection) {\n this.#lc.debug?.('Selected background connection for shared auth work', {\n clientID: nextBackgroundConnection.clientID,\n wsID: nextBackgroundConnection.wsID,\n revision: nextBackgroundConnection.revision,\n reason: 'fallback-validated',\n });\n }\n }\n\n #getBackgroundConnectionContext(): ConnectionContext | undefined {\n const backgroundConnection = this.#group.backgroundConnection;\n if (!backgroundConnection) {\n return undefined;\n }\n return this.#getConnectionContext(backgroundConnection);\n }\n\n #getConnectionContext(\n selector: ConnectionSelector,\n ): ConnectionContext | undefined {\n const connection = this.#connections.get(selector.clientID);\n if (!connection) {\n return undefined;\n }\n if (connection.wsID !== selector.wsID) {\n return undefined;\n }\n return connection;\n }\n\n #mustGetConnectionContext(selector: ConnectionSelector): ConnectionContext {\n const connection = this.#getConnectionContext(selector);\n\n if (!connection) {\n throw new ProtocolErrorWithLevel(\n {\n kind: ErrorKind.InvalidConnectionRequest,\n message:\n 'Connection auth state was not available for this websocket.',\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n\n return connection;\n }\n\n #storeConnection(connection: ConnectionContext): ConnectionContext {\n this.#connections.set(connection.clientID, connection);\n return connection;\n }\n\n #setGroup(group: GroupAuthState): GroupAuthState {\n this.#group = group;\n return group;\n }\n\n #setBackgroundConnection(\n backgroundConnection: ConnectionSelector | undefined,\n ) {\n if (\n sameConnectionSelector(\n this.#group.backgroundConnection,\n backgroundConnection,\n )\n ) {\n return;\n }\n this.#setGroup({\n ...this.#group,\n backgroundConnection: backgroundConnection\n ? {...backgroundConnection}\n : undefined,\n });\n }\n\n /**\n * Keeps the group background retransform deadline coherent with current\n * schedulability.\n *\n * When `reset` is false, this seeds a deadline only when shared retransform\n * is now possible and no deadline exists yet, preserving any existing\n * cadence. When `reset` is true, it starts a fresh interval from `#now()` if\n * retransform is schedulable, or clears the deadline if it is not.\n */\n #updateBackgroundRetransformDeadline(reset: boolean) {\n const backgroundConnection = this.#getBackgroundConnectionContext();\n if (!backgroundConnection || this.#retransformIntervalMs === undefined) {\n if (this.#group.retransformAt !== undefined) {\n this.#setGroup({\n ...this.#group,\n retransformAt: undefined,\n });\n }\n return;\n }\n\n if (reset || this.#group.retransformAt === undefined) {\n this.#setGroup({\n ...this.#group,\n retransformAt: this.#now() + this.#retransformIntervalMs,\n });\n }\n }\n\n #nextRevalidateAt() {\n return this.#revalidateIntervalMs === undefined\n ? undefined\n : this.#now() + this.#revalidateIntervalMs;\n }\n}\n\nfunction compareByInsertionOrder(\n a: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n b: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n) {\n return a.insertionOrder - b.insertionOrder || a.wsID.localeCompare(b.wsID);\n}\n\nfunction comparePreferredValidatedConnection(\n a: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n b: Pick<ConnectionContext, 'insertionOrder' | 'wsID'>,\n) {\n return b.insertionOrder - a.insertionOrder || b.wsID.localeCompare(a.wsID);\n}\n\nfunction minDefined(a: number | undefined, b: number | undefined) {\n if (a === undefined) {\n return b;\n }\n if (b === undefined) {\n return a;\n }\n return Math.min(a, b);\n}\n\nfunction sameConnectionSelector(\n a: ConnectionSelector | undefined,\n b: ConnectionSelector | undefined,\n) {\n return a?.clientID === b?.clientID && a?.wsID === b?.wsID;\n}\n\nfunction cloneCustomHeaders(\n headers: Readonly<Record<string, string>> | undefined,\n) {\n return headers ? {...headers} : undefined;\n}\n\nfunction cloneAllowedClientHeaders(headers: readonly string[] | undefined) {\n return headers ? [...headers] : undefined;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"cvr-store.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cvr-store.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"names":[],"mappings":"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"}
@@ -164,7 +164,19 @@ var CVRStore = class {
164
164
  WHERE cvr."clientGroupID" = ${id}`,
165
165
  tx`SELECT "clientID" FROM ${this.#cvr("clients")}
166
166
  WHERE "clientGroupID" = ${id}`,
167
- tx`SELECT * FROM ${this.#cvr("queries")}
167
+ tx`SELECT
168
+ "clientGroupID",
169
+ "queryHash",
170
+ "clientAST",
171
+ "queryName",
172
+ "queryArgs",
173
+ "patchVersion",
174
+ "transformationHash",
175
+ "transformationVersion",
176
+ "internal",
177
+ "deleted",
178
+ "rowSetSignature"
179
+ FROM ${this.#cvr("queries")}
168
180
  WHERE "clientGroupID" = ${id} AND deleted IS DISTINCT FROM true`,
169
181
  tx`SELECT
170
182
  "clientGroupID",
@@ -378,7 +390,15 @@ var CVRStore = class {
378
390
  try {
379
391
  await reader.processReadTask((tx) => checkVersion(tx, this.#schema, this.#id, current));
380
392
  const [allDesires, queryRows] = await reader.processReadTask((tx) => Promise.all([tx`
381
- SELECT * FROM ${this.#cvr("desires")}
393
+ SELECT
394
+ "clientGroupID",
395
+ "clientID",
396
+ "queryHash",
397
+ "patchVersion",
398
+ "deleted",
399
+ "ttl",
400
+ "inactivatedAt"
401
+ FROM ${this.#cvr("desires")}
382
402
  WHERE "clientGroupID" = ${this.#id}
383
403
  AND "patchVersion" > ${start}
384
404
  AND "patchVersion" <= ${end}`, tx`