@segmentstream/ontology 0.0.0-stage → 0.92.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 (483) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +2 -0
  3. package/README.md +1655 -2
  4. package/dist/action.d.ts +193 -0
  5. package/dist/action.js +41 -0
  6. package/dist/agent-chat.d.ts +44 -0
  7. package/dist/agent-chat.js +91 -0
  8. package/dist/agent-task-contract.d.ts +64 -0
  9. package/dist/agent-task-contract.js +15 -0
  10. package/dist/agent-task.d.ts +39 -0
  11. package/dist/agent-task.js +112 -0
  12. package/dist/analyze.d.ts +215 -0
  13. package/dist/analyze.js +2438 -0
  14. package/dist/app-feedback.d.ts +167 -0
  15. package/dist/app-feedback.js +176 -0
  16. package/dist/authoring-input.d.ts +3 -0
  17. package/dist/authoring-input.js +107 -0
  18. package/dist/authoring-names.d.ts +4 -0
  19. package/dist/authoring-names.js +13 -0
  20. package/dist/authoring-records.d.ts +35 -0
  21. package/dist/authoring-records.js +264 -0
  22. package/dist/authoring.d.ts +15 -0
  23. package/dist/authoring.js +331 -0
  24. package/dist/bin/check.d.ts +30 -0
  25. package/dist/bin/check.js +99 -0
  26. package/dist/bin/load.d.ts +48 -0
  27. package/dist/bin/load.js +139 -0
  28. package/dist/bin/main.d.ts +31 -0
  29. package/dist/bin/main.js +121 -0
  30. package/dist/bin/migrate.d.ts +57 -0
  31. package/dist/bin/migrate.js +170 -0
  32. package/dist/bin/output.d.ts +31 -0
  33. package/dist/bin/output.js +84 -0
  34. package/dist/bin.d.ts +2 -0
  35. package/dist/bin.js +31 -0
  36. package/dist/blob.d.ts +52 -0
  37. package/dist/blob.js +87 -0
  38. package/dist/channel-session.d.ts +16 -0
  39. package/dist/channel-session.js +16 -0
  40. package/dist/chat.d.ts +43 -0
  41. package/dist/chat.js +34 -0
  42. package/dist/confirmation.d.ts +46 -0
  43. package/dist/confirmation.js +41 -0
  44. package/dist/connection.d.ts +213 -0
  45. package/dist/connection.js +289 -0
  46. package/dist/deployment.d.ts +35 -0
  47. package/dist/deployment.js +76 -0
  48. package/dist/diagnostics.d.ts +27 -0
  49. package/dist/diagnostics.js +106 -0
  50. package/dist/emails.d.ts +70 -0
  51. package/dist/emails.js +221 -0
  52. package/dist/entity.d.ts +331 -0
  53. package/dist/entity.js +153 -0
  54. package/dist/errors.d.ts +154 -0
  55. package/dist/errors.js +109 -0
  56. package/dist/feedback-config.d.ts +24 -0
  57. package/dist/feedback-config.js +126 -0
  58. package/dist/files.d.ts +39 -0
  59. package/dist/files.js +4 -0
  60. package/dist/groups.d.ts +95 -0
  61. package/dist/groups.js +280 -0
  62. package/dist/index.d.ts +109 -0
  63. package/dist/index.js +70 -0
  64. package/dist/internal/diagnostics.js +594 -0
  65. package/dist/legacy.d.ts +160 -0
  66. package/dist/legacy.js +270 -0
  67. package/dist/manifest-compatibility.d.ts +8 -0
  68. package/dist/manifest-compatibility.js +87 -0
  69. package/dist/manifest.d.ts +3329 -0
  70. package/dist/manifest.js +757 -0
  71. package/dist/me.d.ts +46 -0
  72. package/dist/me.js +109 -0
  73. package/dist/metric-filters.d.ts +48 -0
  74. package/dist/metric-filters.js +252 -0
  75. package/dist/metric-routes.d.ts +132 -0
  76. package/dist/metric-routes.js +498 -0
  77. package/dist/metric.d.ts +172 -0
  78. package/dist/metric.js +132 -0
  79. package/dist/migrate/apply.d.ts +94 -0
  80. package/dist/migrate/apply.js +526 -0
  81. package/dist/migrate/errors.d.ts +46 -0
  82. package/dist/migrate/errors.js +38 -0
  83. package/dist/migrate/index.d.ts +10 -0
  84. package/dist/migrate/index.js +7 -0
  85. package/dist/migrate/model.d.ts +2311 -0
  86. package/dist/migrate/model.js +148 -0
  87. package/dist/migrate/plan.d.ts +51 -0
  88. package/dist/migrate/plan.js +1856 -0
  89. package/dist/migrate/preview.d.ts +13 -0
  90. package/dist/migrate/preview.js +65 -0
  91. package/dist/migrate/storage.d.ts +226 -0
  92. package/dist/migrate/storage.js +774 -0
  93. package/dist/model-metrics.d.ts +22 -0
  94. package/dist/model-metrics.js +545 -0
  95. package/dist/names.d.ts +49 -0
  96. package/dist/names.js +110 -0
  97. package/dist/navigation-artifact.d.ts +13 -0
  98. package/dist/navigation-artifact.js +11 -0
  99. package/dist/navigation-catalog.d.ts +55 -0
  100. package/dist/navigation-catalog.js +297 -0
  101. package/dist/nitro-navigation.d.ts +3 -0
  102. package/dist/nitro-navigation.js +64 -0
  103. package/dist/nitro-workflows.d.ts +108 -0
  104. package/dist/nitro-workflows.js +286 -0
  105. package/dist/nitro.d.ts +40 -0
  106. package/dist/nitro.js +50 -0
  107. package/dist/ontology.d.ts +41 -0
  108. package/dist/ontology.js +46 -0
  109. package/dist/permissions.d.ts +198 -0
  110. package/dist/permissions.js +272 -0
  111. package/dist/property.d.ts +188 -0
  112. package/dist/property.js +301 -0
  113. package/dist/query.d.ts +245 -0
  114. package/dist/query.js +615 -0
  115. package/dist/relationship.d.ts +99 -0
  116. package/dist/relationship.js +33 -0
  117. package/dist/render.d.ts +81 -0
  118. package/dist/render.js +512 -0
  119. package/dist/replication/baseline.d.ts +51 -0
  120. package/dist/replication/baseline.js +215 -0
  121. package/dist/replication/bigquery.d.ts +37 -0
  122. package/dist/replication/bigquery.js +211 -0
  123. package/dist/replication/coverage.d.ts +14 -0
  124. package/dist/replication/coverage.js +53 -0
  125. package/dist/replication/evolution.d.ts +25 -0
  126. package/dist/replication/evolution.js +184 -0
  127. package/dist/replication/identities.d.ts +6 -0
  128. package/dist/replication/identities.js +47 -0
  129. package/dist/replication/legacy-baseline.d.ts +27 -0
  130. package/dist/replication/legacy-baseline.js +109 -0
  131. package/dist/replication/legacy-store.d.ts +19 -0
  132. package/dist/replication/legacy-store.js +63 -0
  133. package/dist/replication/lineage.d.ts +36 -0
  134. package/dist/replication/lineage.js +72 -0
  135. package/dist/replication/migrate.d.ts +21 -0
  136. package/dist/replication/migrate.js +84 -0
  137. package/dist/replication/model.d.ts +52 -0
  138. package/dist/replication/model.js +99 -0
  139. package/dist/replication/scans.d.ts +34 -0
  140. package/dist/replication/scans.js +158 -0
  141. package/dist/replication/schema.d.ts +11 -0
  142. package/dist/replication/schema.js +226 -0
  143. package/dist/replication/shadow-schema.d.ts +4 -0
  144. package/dist/replication/shadow-schema.js +61 -0
  145. package/dist/replication/shadow.d.ts +127 -0
  146. package/dist/replication/shadow.js +614 -0
  147. package/dist/replication/source-replacement.d.ts +33 -0
  148. package/dist/replication/source-replacement.js +76 -0
  149. package/dist/replication/store.d.ts +36 -0
  150. package/dist/replication/store.js +382 -0
  151. package/dist/replication/transaction.d.ts +23 -0
  152. package/dist/replication/transaction.js +88 -0
  153. package/dist/role.d.ts +61 -0
  154. package/dist/role.js +76 -0
  155. package/dist/runtime/action-deadlocks.d.ts +21 -0
  156. package/dist/runtime/action-deadlocks.js +130 -0
  157. package/dist/runtime/action-transactions.d.ts +35 -0
  158. package/dist/runtime/action-transactions.js +54 -0
  159. package/dist/runtime/agent-counters.d.ts +26 -0
  160. package/dist/runtime/agent-counters.js +98 -0
  161. package/dist/runtime/agent-tasks.d.ts +63 -0
  162. package/dist/runtime/agent-tasks.js +120 -0
  163. package/dist/runtime/agents.d.ts +15 -0
  164. package/dist/runtime/agents.js +457 -0
  165. package/dist/runtime/batch-diagnostics.d.ts +22 -0
  166. package/dist/runtime/batch-diagnostics.js +89 -0
  167. package/dist/runtime/batch.d.ts +52 -0
  168. package/dist/runtime/batch.js +534 -0
  169. package/dist/runtime/channel-session-revocation.d.ts +3 -0
  170. package/dist/runtime/channel-session-revocation.js +5 -0
  171. package/dist/runtime/channel-sessions.d.ts +4 -0
  172. package/dist/runtime/channel-sessions.js +61 -0
  173. package/dist/runtime/confirmations.d.ts +29 -0
  174. package/dist/runtime/confirmations.js +57 -0
  175. package/dist/runtime/cursor.d.ts +23 -0
  176. package/dist/runtime/cursor.js +100 -0
  177. package/dist/runtime/deployment.d.ts +7 -0
  178. package/dist/runtime/deployment.js +4 -0
  179. package/dist/runtime/errors.d.ts +118 -0
  180. package/dist/runtime/errors.js +109 -0
  181. package/dist/runtime/federation-tables.d.ts +2 -0
  182. package/dist/runtime/federation-tables.js +20 -0
  183. package/dist/runtime/federation.d.ts +42 -0
  184. package/dist/runtime/federation.js +222 -0
  185. package/dist/runtime/files.d.ts +39 -0
  186. package/dist/runtime/files.js +44 -0
  187. package/dist/runtime/generated-actions.d.ts +37 -0
  188. package/dist/runtime/generated-actions.js +307 -0
  189. package/dist/runtime/history.d.ts +91 -0
  190. package/dist/runtime/history.js +77 -0
  191. package/dist/runtime/ids.d.ts +6 -0
  192. package/dist/runtime/ids.js +39 -0
  193. package/dist/runtime/member-tables.d.ts +8 -0
  194. package/dist/runtime/member-tables.js +33 -0
  195. package/dist/runtime/member-writes.d.ts +78 -0
  196. package/dist/runtime/member-writes.js +202 -0
  197. package/dist/runtime/metric-query.d.ts +19 -0
  198. package/dist/runtime/metric-query.js +411 -0
  199. package/dist/runtime/model.d.ts +67 -0
  200. package/dist/runtime/model.js +150 -0
  201. package/dist/runtime/new-user-hook.d.ts +6 -0
  202. package/dist/runtime/new-user-hook.js +37 -0
  203. package/dist/runtime/oauth.d.ts +9 -0
  204. package/dist/runtime/oauth.js +299 -0
  205. package/dist/runtime/pipeline.d.ts +155 -0
  206. package/dist/runtime/pipeline.js +597 -0
  207. package/dist/runtime/postgres-tls.d.ts +10 -0
  208. package/dist/runtime/postgres-tls.js +14 -0
  209. package/dist/runtime/principals.d.ts +302 -0
  210. package/dist/runtime/principals.js +1307 -0
  211. package/dist/runtime/reads.d.ts +55 -0
  212. package/dist/runtime/reads.js +313 -0
  213. package/dist/runtime/records.d.ts +42 -0
  214. package/dist/runtime/records.js +245 -0
  215. package/dist/runtime/resolve-agent-identity.d.ts +6 -0
  216. package/dist/runtime/resolve-agent-identity.js +181 -0
  217. package/dist/runtime/service-binding.d.ts +18 -0
  218. package/dist/runtime/service-binding.js +266 -0
  219. package/dist/runtime/sign-in-links.d.ts +68 -0
  220. package/dist/runtime/sign-in-links.js +147 -0
  221. package/dist/runtime/sql-runtime.d.ts +131 -0
  222. package/dist/runtime/sql-runtime.js +362 -0
  223. package/dist/runtime/statement.d.ts +18 -0
  224. package/dist/runtime/statement.js +31 -0
  225. package/dist/runtime/user-identities.d.ts +66 -0
  226. package/dist/runtime/user-identities.js +106 -0
  227. package/dist/runtime/user-identity-sql.d.ts +86 -0
  228. package/dist/runtime/user-identity-sql.js +297 -0
  229. package/dist/runtime/user-roles.d.ts +16 -0
  230. package/dist/runtime/user-roles.js +32 -0
  231. package/dist/runtime/validation.d.ts +16 -0
  232. package/dist/runtime/validation.js +26 -0
  233. package/dist/runtime/where.d.ts +57 -0
  234. package/dist/runtime/where.js +404 -0
  235. package/dist/runtime/workflow-admission.d.ts +49 -0
  236. package/dist/runtime/workflow-admission.js +92 -0
  237. package/dist/runtime/workflow-argument-codec.d.ts +10 -0
  238. package/dist/runtime/workflow-argument-codec.js +120 -0
  239. package/dist/runtime/workflow-arguments.d.ts +17 -0
  240. package/dist/runtime/workflow-arguments.js +99 -0
  241. package/dist/runtime/workflow-starts.d.ts +203 -0
  242. package/dist/runtime/workflow-starts.js +493 -0
  243. package/dist/runtime/workflow-users.d.ts +9 -0
  244. package/dist/runtime/workflow-users.js +17 -0
  245. package/dist/runtime/workload.d.ts +25 -0
  246. package/dist/runtime/workload.js +24 -0
  247. package/dist/runtime/writes.d.ts +108 -0
  248. package/dist/runtime/writes.js +491 -0
  249. package/dist/runtime-source.d.ts +22 -0
  250. package/dist/runtime-source.js +28 -0
  251. package/dist/runtime.d.ts +310 -0
  252. package/dist/runtime.js +31 -0
  253. package/dist/server.d.ts +23 -0
  254. package/dist/server.js +107 -0
  255. package/dist/service/agent/attachments.d.ts +33 -0
  256. package/dist/service/agent/attachments.js +228 -0
  257. package/dist/service/agent/authentication.d.ts +22 -0
  258. package/dist/service/agent/authentication.js +58 -0
  259. package/dist/service/agent/confirmations.d.ts +5 -0
  260. package/dist/service/agent/confirmations.js +73 -0
  261. package/dist/service/agent/conversation-routes.d.ts +14 -0
  262. package/dist/service/agent/conversation-routes.js +45 -0
  263. package/dist/service/agent/conversations.d.ts +40 -0
  264. package/dist/service/agent/conversations.js +69 -0
  265. package/dist/service/agent/files.d.ts +12 -0
  266. package/dist/service/agent/files.js +69 -0
  267. package/dist/service/agent/protocol.d.ts +90 -0
  268. package/dist/service/agent/protocol.js +114 -0
  269. package/dist/service/agent/server.d.ts +28 -0
  270. package/dist/service/agent/server.js +374 -0
  271. package/dist/service/agent/task-caller.d.ts +21 -0
  272. package/dist/service/agent/task-caller.js +35 -0
  273. package/dist/service/agent/task-start.d.ts +53 -0
  274. package/dist/service/agent/task-start.js +161 -0
  275. package/dist/service/agent/tasks.d.ts +40 -0
  276. package/dist/service/agent/tasks.js +155 -0
  277. package/dist/service/api.d.ts +50 -0
  278. package/dist/service/api.js +288 -0
  279. package/dist/service/authentication.d.ts +227 -0
  280. package/dist/service/authentication.js +767 -0
  281. package/dist/service/caller-context.d.ts +24 -0
  282. package/dist/service/caller-context.js +6 -0
  283. package/dist/service/catalog.d.ts +42 -0
  284. package/dist/service/catalog.js +66 -0
  285. package/dist/service/channel/provider.d.ts +10 -0
  286. package/dist/service/channel/provider.js +1 -0
  287. package/dist/service/channel/providers/telegram.d.ts +18 -0
  288. package/dist/service/channel/providers/telegram.js +108 -0
  289. package/dist/service/channel/sessions.d.ts +5 -0
  290. package/dist/service/channel/sessions.js +53 -0
  291. package/dist/service/channel/sign-in.d.ts +7 -0
  292. package/dist/service/channel/sign-in.js +78 -0
  293. package/dist/service/chat/archive.d.ts +64 -0
  294. package/dist/service/chat/archive.js +62 -0
  295. package/dist/service/chat/attribution.d.ts +26 -0
  296. package/dist/service/chat/attribution.js +28 -0
  297. package/dist/service/chat/delivery.d.ts +18 -0
  298. package/dist/service/chat/delivery.js +251 -0
  299. package/dist/service/chat/diagnostics.d.ts +2 -0
  300. package/dist/service/chat/diagnostics.js +35 -0
  301. package/dist/service/chat/envelope.d.ts +96 -0
  302. package/dist/service/chat/envelope.js +39 -0
  303. package/dist/service/chat/idempotency.d.ts +19 -0
  304. package/dist/service/chat/idempotency.js +37 -0
  305. package/dist/service/chat/providers/telegram.d.ts +36 -0
  306. package/dist/service/chat/providers/telegram.js +133 -0
  307. package/dist/service/chat/reads.d.ts +25 -0
  308. package/dist/service/chat/reads.js +75 -0
  309. package/dist/service/chat/resolve.d.ts +34 -0
  310. package/dist/service/chat/resolve.js +150 -0
  311. package/dist/service/chat/routes.d.ts +23 -0
  312. package/dist/service/chat/routes.js +75 -0
  313. package/dist/service/chat/schemas.d.ts +43 -0
  314. package/dist/service/chat/schemas.js +31 -0
  315. package/dist/service/config.d.ts +218 -0
  316. package/dist/service/config.js +265 -0
  317. package/dist/service/connection-stream.d.ts +10 -0
  318. package/dist/service/connection-stream.js +191 -0
  319. package/dist/service/connections.d.ts +60 -0
  320. package/dist/service/connections.js +271 -0
  321. package/dist/service/decisions.d.ts +35 -0
  322. package/dist/service/decisions.js +63 -0
  323. package/dist/service/descriptions.d.ts +8 -0
  324. package/dist/service/descriptions.js +20 -0
  325. package/dist/service/discovery-schemas.d.ts +92 -0
  326. package/dist/service/discovery-schemas.js +59 -0
  327. package/dist/service/discovery-search.d.ts +30 -0
  328. package/dist/service/discovery-search.js +95 -0
  329. package/dist/service/discovery.d.ts +37 -0
  330. package/dist/service/discovery.js +436 -0
  331. package/dist/service/docs.d.ts +9 -0
  332. package/dist/service/docs.js +197 -0
  333. package/dist/service/errors.d.ts +145 -0
  334. package/dist/service/errors.js +704 -0
  335. package/dist/service/federation-provider.d.ts +36 -0
  336. package/dist/service/federation-provider.js +110 -0
  337. package/dist/service/federation-server.d.ts +20 -0
  338. package/dist/service/federation-server.js +249 -0
  339. package/dist/service/federation-status.d.ts +40 -0
  340. package/dist/service/federation-status.js +151 -0
  341. package/dist/service/handlers.d.ts +18 -0
  342. package/dist/service/handlers.js +287 -0
  343. package/dist/service/mcp/confirmation.d.ts +68 -0
  344. package/dist/service/mcp/confirmation.js +178 -0
  345. package/dist/service/mcp/find-input.d.ts +12 -0
  346. package/dist/service/mcp/find-input.js +122 -0
  347. package/dist/service/mcp/input-schema.d.ts +6 -0
  348. package/dist/service/mcp/input-schema.js +126 -0
  349. package/dist/service/mcp/listing.d.ts +26 -0
  350. package/dist/service/mcp/listing.js +92 -0
  351. package/dist/service/mcp/metric-tools.d.ts +85 -0
  352. package/dist/service/mcp/metric-tools.js +258 -0
  353. package/dist/service/mcp/request-log.d.ts +5 -0
  354. package/dist/service/mcp/request-log.js +53 -0
  355. package/dist/service/mcp/runtime-policy.d.ts +27 -0
  356. package/dist/service/mcp/runtime-policy.js +62 -0
  357. package/dist/service/mcp/server.d.ts +52 -0
  358. package/dist/service/mcp/server.js +861 -0
  359. package/dist/service/mcp/tools.d.ts +99 -0
  360. package/dist/service/mcp/tools.js +938 -0
  361. package/dist/service/member-file-routes.d.ts +22 -0
  362. package/dist/service/member-file-routes.js +52 -0
  363. package/dist/service/member-files.d.ts +245 -0
  364. package/dist/service/member-files.js +258 -0
  365. package/dist/service/metric-query-platform.d.ts +77 -0
  366. package/dist/service/metric-query-platform.js +198 -0
  367. package/dist/service/metric-query-scopes.d.ts +43 -0
  368. package/dist/service/metric-query-scopes.js +147 -0
  369. package/dist/service/metric-query.d.ts +48 -0
  370. package/dist/service/metric-query.js +200 -0
  371. package/dist/service/name-suggestions.d.ts +3 -0
  372. package/dist/service/name-suggestions.js +38 -0
  373. package/dist/service/navigation-schemas.d.ts +80 -0
  374. package/dist/service/navigation-schemas.js +49 -0
  375. package/dist/service/navigation.d.ts +20 -0
  376. package/dist/service/navigation.js +165 -0
  377. package/dist/service/oauth/protocol.d.ts +70 -0
  378. package/dist/service/oauth/protocol.js +157 -0
  379. package/dist/service/oauth/refresh-replay.d.ts +2 -0
  380. package/dist/service/oauth/refresh-replay.js +20 -0
  381. package/dist/service/oauth/server.d.ts +28 -0
  382. package/dist/service/oauth/server.js +769 -0
  383. package/dist/service/operations.d.ts +170 -0
  384. package/dist/service/operations.js +392 -0
  385. package/dist/service/plan.d.ts +57 -0
  386. package/dist/service/plan.js +96 -0
  387. package/dist/service/rate-limit.d.ts +22 -0
  388. package/dist/service/rate-limit.js +52 -0
  389. package/dist/service/record-reads.d.ts +21 -0
  390. package/dist/service/record-reads.js +155 -0
  391. package/dist/service/replication.d.ts +5 -0
  392. package/dist/service/replication.js +39 -0
  393. package/dist/service/runtime-contract.d.ts +508 -0
  394. package/dist/service/runtime-contract.js +18 -0
  395. package/dist/service/runtime-identity.d.ts +71 -0
  396. package/dist/service/runtime-identity.js +122 -0
  397. package/dist/service/schemas.d.ts +961 -0
  398. package/dist/service/schemas.js +639 -0
  399. package/dist/service/service.d.ts +21 -0
  400. package/dist/service/service.js +526 -0
  401. package/dist/service/warehouse-platform.d.ts +17 -0
  402. package/dist/service/warehouse-platform.js +122 -0
  403. package/dist/service/warehouse-query.d.ts +24 -0
  404. package/dist/service/warehouse-query.js +280 -0
  405. package/dist/service/webhooks.d.ts +106 -0
  406. package/dist/service/webhooks.js +233 -0
  407. package/dist/service/workflow-admission-provider.d.ts +31 -0
  408. package/dist/service/workflow-admission-provider.js +205 -0
  409. package/dist/service/workflow-argument-serialization.d.ts +2 -0
  410. package/dist/service/workflow-argument-serialization.js +14 -0
  411. package/dist/service/workflow-callback.d.ts +22 -0
  412. package/dist/service/workflow-callback.js +75 -0
  413. package/dist/service/workflow-deployment.d.ts +8 -0
  414. package/dist/service/workflow-deployment.js +131 -0
  415. package/dist/service/workflow-diagnostics.d.ts +23 -0
  416. package/dist/service/workflow-diagnostics.js +263 -0
  417. package/dist/service/workflow-errors.d.ts +26 -0
  418. package/dist/service/workflow-errors.js +181 -0
  419. package/dist/service/workflow-logging.d.ts +2 -0
  420. package/dist/service/workflow-logging.js +50 -0
  421. package/dist/service/workflow-queue-fence.d.ts +6 -0
  422. package/dist/service/workflow-queue-fence.js +66 -0
  423. package/dist/service/workflows.d.ts +200 -0
  424. package/dist/service/workflows.js +1549 -0
  425. package/dist/sign-in.d.ts +58 -0
  426. package/dist/sign-in.js +57 -0
  427. package/dist/source.d.ts +30 -0
  428. package/dist/source.js +107 -0
  429. package/dist/start-recovery-contract.d.ts +49 -0
  430. package/dist/start-recovery-contract.js +26 -0
  431. package/dist/start-recovery.d.ts +27 -0
  432. package/dist/start-recovery.js +81 -0
  433. package/dist/storage/api.d.ts +4 -0
  434. package/dist/storage/api.js +40 -0
  435. package/dist/storage/attachments.d.ts +146 -0
  436. package/dist/storage/attachments.js +733 -0
  437. package/dist/storage/authorization.d.ts +38 -0
  438. package/dist/storage/authorization.js +83 -0
  439. package/dist/storage/file-access.d.ts +17 -0
  440. package/dist/storage/file-access.js +8 -0
  441. package/dist/storage/limits.d.ts +12 -0
  442. package/dist/storage/limits.js +17 -0
  443. package/dist/storage/maintenance-auth.d.ts +20 -0
  444. package/dist/storage/maintenance-auth.js +24 -0
  445. package/dist/storage/maintenance.d.ts +11 -0
  446. package/dist/storage/maintenance.js +67 -0
  447. package/dist/storage/neon.d.ts +4 -0
  448. package/dist/storage/neon.js +318 -0
  449. package/dist/storage/operator.d.ts +11 -0
  450. package/dist/storage/operator.js +30 -0
  451. package/dist/storage/provider.d.ts +93 -0
  452. package/dist/storage/provider.js +36 -0
  453. package/dist/storage/sessions.d.ts +184 -0
  454. package/dist/storage/sessions.js +688 -0
  455. package/dist/storage/tables.d.ts +54 -0
  456. package/dist/storage/tables.js +205 -0
  457. package/dist/storage/transfers.d.ts +16 -0
  458. package/dist/storage/transfers.js +153 -0
  459. package/dist/storage/writes.d.ts +7 -0
  460. package/dist/storage/writes.js +88 -0
  461. package/dist/telegram.d.ts +35 -0
  462. package/dist/telegram.js +173 -0
  463. package/dist/user-identity.d.ts +28 -0
  464. package/dist/user-identity.js +106 -0
  465. package/dist/user.d.ts +75 -0
  466. package/dist/user.js +111 -0
  467. package/dist/warehouse-backed.d.ts +6 -0
  468. package/dist/warehouse-backed.js +495 -0
  469. package/dist/webhook-token.d.ts +11 -0
  470. package/dist/webhook-token.js +18 -0
  471. package/dist/webhooks.d.ts +40 -0
  472. package/dist/webhooks.js +55 -0
  473. package/dist/wire.d.ts +10 -0
  474. package/dist/wire.js +35 -0
  475. package/dist/workflow-runtime.d.ts +116 -0
  476. package/dist/workflow-runtime.js +109 -0
  477. package/dist/workflow-topics.d.ts +28 -0
  478. package/dist/workflow-topics.js +28 -0
  479. package/dist/workflow.d.ts +284 -0
  480. package/dist/workflow.js +259 -0
  481. package/dist/workflows.d.ts +24 -0
  482. package/dist/workflows.js +18 -0
  483. package/package.json +127 -4
@@ -0,0 +1,31 @@
1
+ import { quoteIdentifier } from "../migrate/storage.js";
2
+ /**
3
+ * Collects the parameters of one statement. Values are always bound as parameters, cast to the
4
+ * column's type; only identifiers from the definition are written into the SQL text.
5
+ */
6
+ export class Params {
7
+ values = [];
8
+ /** Binds a value and returns its placeholder, cast when a type is given: `$3::bigint`. */
9
+ add(value, cast) {
10
+ this.values.push(value);
11
+ const placeholder = `$${this.values.length}`;
12
+ return cast === undefined ? placeholder : `${placeholder}::${cast}`;
13
+ }
14
+ }
15
+ /** `"t0"."owner_id"`. */
16
+ export function columnOf(alias, column) {
17
+ return `${quoteIdentifier(alias)}.${quoteIdentifier(column)}`;
18
+ }
19
+ /** Hands out table aliases, `t0`, `t1`, …, unique within one statement. */
20
+ export class Aliases {
21
+ next = 0;
22
+ take(prefix = "t") {
23
+ const alias = `${prefix}${this.next}`;
24
+ this.next += 1;
25
+ return alias;
26
+ }
27
+ }
28
+ /** `%` and `_` match literally in LIKE patterns built from caller text; `\` is the escape. */
29
+ export function escapeLike(text) {
30
+ return text.replace(/[\\%_]/g, (character) => `\\${character}`);
31
+ }
@@ -0,0 +1,66 @@
1
+ import { Effect } from "effect";
2
+ import type { SqlClient } from "effect/unstable/sql";
3
+ import { type SqlError } from "effect/unstable/sql/SqlError";
4
+ import type { Conflict, NotFound } from "../errors.js";
5
+ import type { Ontology } from "../ontology.js";
6
+ import type { StoredRecord } from "../runtime.js";
7
+ import type { UserIdentityOrigin } from "../user-identity.js";
8
+ import { type IdentityAccount } from "./user-identity-sql.js";
9
+ export * from "./user-identity-sql.js";
10
+ /**
11
+ * Whether the deployed ontology keeps `user_identity`: its table exists and the catalog declares
12
+ * it. The platform reads databases an earlier SDK deployed too, which have no such table, or keep
13
+ * one no runtime writes once an earlier SDK was deployed again; those read the legacy stores.
14
+ */
15
+ export declare function userIdentitiesAvailable(sql: SqlClient.SqlClient): Effect.Effect<boolean, SqlError>;
16
+ export interface IdentityCreate extends IdentityAccount {
17
+ /** Keeps an id issued before the record, such as a channel account's `_agent_identities` id. */
18
+ readonly id?: string;
19
+ readonly userId: string;
20
+ readonly origin: UserIdentityOrigin;
21
+ readonly username?: string | null;
22
+ readonly display?: string | null;
23
+ }
24
+ /**
25
+ * The platform's writes of `user_identity`: each runs in its own savepoint of the caller's
26
+ * transaction and records history under `scope`, without a principal. Only these writes change the
27
+ * entity; the general runtime refuses to. They change `user_identity` alone: callers write the
28
+ * legacy stores beside them.
29
+ */
30
+ export declare function makeIdentityWriter(ontology: Ontology, sql: SqlClient.SqlClient, scope: {
31
+ readonly action: string;
32
+ readonly actionId: string;
33
+ }): {
34
+ /** Creates a live identity; Conflict when its account or member key is held. */
35
+ create: (input: IdentityCreate) => Effect.Effect<StoredRecord, Conflict | NotFound>;
36
+ /** Revokes a live identity at `at`, freeing its keys; a revoked one changes nothing. */
37
+ revoke: (id: string, at: string) => Effect.Effect<StoredRecord, Conflict | NotFound>;
38
+ /** Records the account's current username and display; unchanged values write nothing. */
39
+ describe: (id: string, values: {
40
+ readonly username?: string | null;
41
+ readonly display?: string | null;
42
+ }) => Effect.Effect<StoredRecord, Conflict | NotFound>;
43
+ };
44
+ export type IdentityWriter = ReturnType<typeof makeIdentityWriter>;
45
+ /** A sign-in identity as the runtime reads it. */
46
+ export interface SignInIdentityRow {
47
+ readonly id: string;
48
+ readonly provider: string;
49
+ readonly issuer: string | null;
50
+ readonly subject: string;
51
+ }
52
+ /** The member's live sign-in identities: email, SegmentStream and app-token accounts. */
53
+ export declare function liveSignInIdentities(sql: SqlClient.SqlClient, userId: string): Effect.Effect<ReadonlyArray<SignInIdentityRow>, SqlError>;
54
+ /** The user the live account belongs to, or undefined; an account no key can name has none. */
55
+ export declare function userOfAccount(sql: SqlClient.SqlClient, account: IdentityAccount): Effect.Effect<string | undefined, SqlError>;
56
+ /**
57
+ * Records a live sign-in identity of the member unless the account is held already, by them or by
58
+ * another member: the caller decides what the latter means. An account no key can name is not
59
+ * recorded, and so never signs in.
60
+ */
61
+ export declare function ensureSignInIdentity(writer: IdentityWriter, sql: SqlClient.SqlClient, input: IdentityAccount & {
62
+ readonly userId: string;
63
+ readonly origin: UserIdentityOrigin;
64
+ }): Effect.Effect<void, Conflict | NotFound | SqlError>;
65
+ /** Runs {@link USER_IDENTITY_SYNC_SQL} in the caller's transaction. */
66
+ export declare function syncUserIdentities(sql: SqlClient.SqlClient): Effect.Effect<void, SqlError>;
@@ -0,0 +1,106 @@
1
+ import { Effect } from "effect";
2
+ import { isSqlError } from "effect/unstable/sql/SqlError";
3
+ import { entityModel, ontologyModel } from "./model.js";
4
+ import { uniqueConflict } from "./sql-runtime.js";
5
+ import { accountKey, isRecordableAccount, memberKey, SIGN_IN_ORIGIN_SQL, USER_IDENTITY_ENTITY_ID, USER_IDENTITY_SYNC_SQL, USER_IDENTITY_TABLE, } from "./user-identity-sql.js";
6
+ import { createRecord, updateRecord } from "./writes.js";
7
+ export * from "./user-identity-sql.js";
8
+ /**
9
+ * Whether the deployed ontology keeps `user_identity`: its table exists and the catalog declares
10
+ * it. The platform reads databases an earlier SDK deployed too, which have no such table, or keep
11
+ * one no runtime writes once an earlier SDK was deployed again; those read the legacy stores.
12
+ */
13
+ export function userIdentitiesAvailable(sql) {
14
+ return Effect.gen(function* () {
15
+ const [tables] = yield* sql.unsafe(`SELECT to_regclass($1) IS NOT NULL AS "identities", ` +
16
+ `to_regclass('"_ontology"') IS NOT NULL AS "catalog"`, [`"${USER_IDENTITY_TABLE}"`]);
17
+ if (tables?.identities !== true || tables.catalog !== true) {
18
+ return false;
19
+ }
20
+ const [catalog] = yield* sql.unsafe(`SELECT EXISTS (SELECT 1 FROM "_ontology" WHERE "id" ` +
21
+ `AND "manifest"->'entities' @> $1::jsonb) AS "declared"`, [JSON.stringify([{ id: USER_IDENTITY_ENTITY_ID }])]);
22
+ return catalog?.declared === true;
23
+ });
24
+ }
25
+ /**
26
+ * The platform's writes of `user_identity`: each runs in its own savepoint of the caller's
27
+ * transaction and records history under `scope`, without a principal. Only these writes change the
28
+ * entity; the general runtime refuses to. They change `user_identity` alone: callers write the
29
+ * legacy stores beside them.
30
+ */
31
+ export function makeIdentityWriter(ontology, sql, scope) {
32
+ const model = ontologyModel(ontology);
33
+ const entity = entityModel(model, USER_IDENTITY_TABLE);
34
+ const client = sql.withoutTransforms();
35
+ const context = () => ({
36
+ model,
37
+ scope: { action: scope.action, actionId: scope.actionId, principalId: null },
38
+ edits: [],
39
+ run: (text, params) => client.unsafe(text, params.values),
40
+ });
41
+ // A unique violation is a held key; any other database failure is a defect, as in the runtime.
42
+ const write = (operation) => sql.withTransaction(operation()).pipe(Effect.catchTag("ScopeViolated", (error) => Effect.die(error)), Effect.catchIf(isSqlError, (error) => uniqueConflict(entity, error)));
43
+ return {
44
+ /** Creates a live identity; Conflict when its account or member key is held. */
45
+ create: (input) => Effect.suspend(() => {
46
+ const values = {
47
+ provider: input.provider,
48
+ issuer: input.issuer,
49
+ subject: input.subject,
50
+ username: input.username ?? null,
51
+ display: input.display ?? null,
52
+ origin: input.origin,
53
+ revoked_at: null,
54
+ account_key: accountKey(input),
55
+ member_key: memberKey(input.userId, input.provider),
56
+ user: input.userId,
57
+ };
58
+ return write(() => createRecord(context(), entity, values, undefined, input.id));
59
+ }),
60
+ /** Revokes a live identity at `at`, freeing its keys; a revoked one changes nothing. */
61
+ revoke: (id, at) => write(() => updateRecord(context(), entity, id, {
62
+ revoked_at: at,
63
+ account_key: null,
64
+ member_key: null,
65
+ })),
66
+ /** Records the account's current username and display; unchanged values write nothing. */
67
+ describe: (id, values) => write(() => updateRecord(context(), entity, id, {
68
+ ...(values.username === undefined ? {} : { username: values.username }),
69
+ ...(values.display === undefined ? {} : { display: values.display }),
70
+ })),
71
+ };
72
+ }
73
+ /** The member's live sign-in identities: email, SegmentStream and app-token accounts. */
74
+ export function liveSignInIdentities(sql, userId) {
75
+ return sql.unsafe(`SELECT "i"."id"::text AS "id", "i"."provider", "i"."issuer", "i"."subject" ` +
76
+ `FROM "${USER_IDENTITY_TABLE}" AS "i" WHERE "i"."user_id" = $1::uuid ` +
77
+ `AND "i"."origin"::text IN ${SIGN_IN_ORIGIN_SQL} AND "i"."revoked_at" IS NULL ` +
78
+ `ORDER BY "i"."created_at", "i"."id"`, [userId]);
79
+ }
80
+ /** The user the live account belongs to, or undefined; an account no key can name has none. */
81
+ export function userOfAccount(sql, account) {
82
+ if (!isRecordableAccount(account)) {
83
+ return Effect.succeed(undefined);
84
+ }
85
+ return sql
86
+ .unsafe(`SELECT "user_id"::text AS "user_id" FROM "${USER_IDENTITY_TABLE}" WHERE "account_key" = $1`, [accountKey(account)])
87
+ .pipe(Effect.map(([row]) => row?.user_id));
88
+ }
89
+ /**
90
+ * Records a live sign-in identity of the member unless the account is held already, by them or by
91
+ * another member: the caller decides what the latter means. An account no key can name is not
92
+ * recorded, and so never signs in.
93
+ */
94
+ export function ensureSignInIdentity(writer, sql, input) {
95
+ return Effect.gen(function* () {
96
+ if (!isRecordableAccount(input) || (yield* userOfAccount(sql, input)) !== undefined) {
97
+ return;
98
+ }
99
+ yield* writer.create(input);
100
+ });
101
+ }
102
+ // @legacy identities.legacy-stores-dual-write
103
+ /** Runs {@link USER_IDENTITY_SYNC_SQL} in the caller's transaction. */
104
+ export function syncUserIdentities(sql) {
105
+ return sql.unsafe(USER_IDENTITY_SYNC_SQL).unprepared.pipe(Effect.asVoid);
106
+ }
@@ -0,0 +1,86 @@
1
+ import type { UserIdentityOrigin } from "../user-identity.js";
2
+ /**
3
+ * Members' external accounts live in the built-in `user_identity` entity. Until the contract step
4
+ * removes them, the stores earlier SDKs read stay written beside it in the same transaction: the
5
+ * member's `user.identity_provider` and `identity_subject`, `_user_identities` for SegmentStream
6
+ * (OIDC) bindings and `_agent_identities` for channel accounts. See
7
+ * docs/workspace-user-identities.md. This module holds SQL only, so that the planner can use it.
8
+ */
9
+ export declare const USER_IDENTITY_TABLE = "user_identity";
10
+ /** The built-in entity's stable id, by which a manifest includes it. */
11
+ export declare const USER_IDENTITY_ENTITY_ID = "ent_user_identity";
12
+ /** The provider of email sign-in: the workspace's Neon Auth. */
13
+ export declare const NEON_AUTH_PROVIDER = "neon-auth";
14
+ /** The provider of SegmentStream (OIDC) sign-in; the issuer tells the issuing deployment apart. */
15
+ export declare const OIDC_PROVIDER = "oidc";
16
+ /** The legacy `user.identity_provider` of an OIDC binding: `oidc:<issuer>`. */
17
+ export declare const LEGACY_OIDC_PREFIX = "oidc:";
18
+ /** Origins of the identities a member signs in with, which the member's user columns mirror. */
19
+ export declare const SIGN_IN_ORIGINS: ReadonlyArray<UserIdentityOrigin>;
20
+ /** Origins of channel accounts, which `_agent_identities` mirrors with the same ids. */
21
+ export declare const CHANNEL_ORIGINS: ReadonlyArray<UserIdentityOrigin>;
22
+ /** `origin IN (…)` of sign-in identities, for SQL on the alias `i`. */
23
+ export declare const SIGN_IN_ORIGIN_SQL: string;
24
+ /** `origin IN (…)` of channel accounts, for SQL on the alias `i`. */
25
+ export declare const CHANNEL_ORIGIN_SQL: string;
26
+ /**
27
+ * Channel accounts as the runtime reads them: the identity `i`, beside its `_agent_identities` row
28
+ * `a`, which the dual write keeps with the same id. While earlier SDKs or platforms may still
29
+ * serve requests, a revocation one of them recorded only in `_agent_identities`, or a row it
30
+ * deleted there (a preview copy is cleared), ends the identity too; the next migration copies it.
31
+ */
32
+ export declare const CHANNEL_IDENTITIES_FROM: string;
33
+ /** The `user_identity` record `i` is a live channel account, whatever the legacy store holds. */
34
+ export declare const LIVE_CHANNEL_RECORD: string;
35
+ /** The channel identity `i` (with `a`, see {@link CHANNEL_IDENTITIES_FROM}) is live. */
36
+ export declare const LIVE_CHANNEL_IDENTITY: string;
37
+ /**
38
+ * When the channel identity `i` (with `a`) stopped working: its own revocation, else the legacy
39
+ * store's, else, when the legacy row is gone, its last change.
40
+ */
41
+ export declare const CHANNEL_REVOKED_AT: string;
42
+ /** An external account: the provider, the OIDC issuer for `oidc`, and the id at the provider. */
43
+ export interface IdentityAccount {
44
+ readonly provider: string;
45
+ readonly issuer: string | null;
46
+ readonly subject: string;
47
+ }
48
+ /** The account a legacy `identity_provider` and `identity_subject` name. */
49
+ export declare function accountOfLegacy(identityProvider: string, subject: string): IdentityAccount;
50
+ /** The legacy `identity_provider` of an account: `oidc:<issuer>`, or the provider itself. */
51
+ export declare function legacyProviderOf(account: IdentityAccount): string;
52
+ /** Whether the account can be recorded: a key part never holds whitespace, a subject is set. */
53
+ export declare function isRecordableAccount(account: IdentityAccount): boolean;
54
+ /**
55
+ * The live account key: `<provider> <subject>`, or `<provider> <issuer> <subject>` for an issuer.
56
+ * The provider decides whether an issuer is present, and neither holds whitespace, so two accounts
57
+ * never share a key. {@link accountKeySql} computes the same key in SQL.
58
+ */
59
+ export declare function accountKey(account: IdentityAccount): string;
60
+ /** The live member key, `<user id> <provider>`, or none for `oidc`, of which a member has several. */
61
+ export declare function memberKey(userId: string, provider: string): string | null;
62
+ /** {@link accountKey} over the columns `provider`, `issuer` and `subject` of the alias given. */
63
+ export declare function accountKeySql(alias: string): string;
64
+ /** {@link memberKey} over the columns `user_id` and `provider` of the alias given. */
65
+ export declare function memberKeySql(alias: string): string;
66
+ /**
67
+ * Refuses a deploy that drops email sign-in while an active member who signs in by email has no
68
+ * SegmentStream (OIDC) identity: they would lose access.
69
+ */
70
+ export declare const SEGMENTSTREAM_LINK_FENCE_SQL: string;
71
+ /**
72
+ * Refuses a deploy that drops SegmentStream sign-in while an active member with a SegmentStream
73
+ * identity has no email sign-in: they would lose access.
74
+ */
75
+ export declare const EMAIL_LINK_FENCE_SQL: string;
76
+ /**
77
+ * Copies what the legacy stores hold and `user_identity` lacks, idempotently, so that a database
78
+ * served or migrated by an earlier SDK in between is in step again. Each migration runs it, a no-op
79
+ * one included, after the entity's table exists. It deletes channel identities whose
80
+ * `_agent_identities` row is gone (a preview copy clears them), revokes those revoked there, keeps
81
+ * their username and display current, adds missing channel accounts with their ids, members'
82
+ * `identity_provider`/`identity_subject` sign-ins and `_user_identities` bindings, and copies
83
+ * first-contact notices. A row whose key another live identity holds is skipped rather than failing
84
+ * the deploy. Every change is recorded in history under `user_identity.sync`.
85
+ */
86
+ export declare const USER_IDENTITY_SYNC_SQL: string;
@@ -0,0 +1,297 @@
1
+ import { AGENT_IDENTITIES_TABLE, IDENTITY_NOTICES_TABLE, quoteIdentifier, } from "../migrate/storage.js";
2
+ /**
3
+ * Members' external accounts live in the built-in `user_identity` entity. Until the contract step
4
+ * removes them, the stores earlier SDKs read stay written beside it in the same transaction: the
5
+ * member's `user.identity_provider` and `identity_subject`, `_user_identities` for SegmentStream
6
+ * (OIDC) bindings and `_agent_identities` for channel accounts. See
7
+ * docs/workspace-user-identities.md. This module holds SQL only, so that the planner can use it.
8
+ */
9
+ export const USER_IDENTITY_TABLE = "user_identity";
10
+ /** The built-in entity's stable id, by which a manifest includes it. */
11
+ export const USER_IDENTITY_ENTITY_ID = "ent_user_identity";
12
+ /** The provider of email sign-in: the workspace's Neon Auth. */
13
+ export const NEON_AUTH_PROVIDER = "neon-auth";
14
+ /** The provider of SegmentStream (OIDC) sign-in; the issuer tells the issuing deployment apart. */
15
+ export const OIDC_PROVIDER = "oidc";
16
+ /** The legacy `user.identity_provider` of an OIDC binding: `oidc:<issuer>`. */
17
+ export const LEGACY_OIDC_PREFIX = "oidc:";
18
+ /** Origins of the identities a member signs in with, which the member's user columns mirror. */
19
+ export const SIGN_IN_ORIGINS = ["invite", "sign_in", "link"];
20
+ /** Origins of channel accounts, which `_agent_identities` mirrors with the same ids. */
21
+ export const CHANNEL_ORIGINS = ["pairing", "channel"];
22
+ const originList = (origins) => `(${origins.map((origin) => `'${origin}'`).join(", ")})`;
23
+ /** `origin IN (…)` of sign-in identities, for SQL on the alias `i`. */
24
+ export const SIGN_IN_ORIGIN_SQL = originList(SIGN_IN_ORIGINS);
25
+ /** `origin IN (…)` of channel accounts, for SQL on the alias `i`. */
26
+ export const CHANNEL_ORIGIN_SQL = originList(CHANNEL_ORIGINS);
27
+ /**
28
+ * Channel accounts as the runtime reads them: the identity `i`, beside its `_agent_identities` row
29
+ * `a`, which the dual write keeps with the same id. While earlier SDKs or platforms may still
30
+ * serve requests, a revocation one of them recorded only in `_agent_identities`, or a row it
31
+ * deleted there (a preview copy is cleared), ends the identity too; the next migration copies it.
32
+ */
33
+ export const CHANNEL_IDENTITIES_FROM = `"${USER_IDENTITY_TABLE}" AS "i" LEFT JOIN "${AGENT_IDENTITIES_TABLE}" AS "a" ` +
34
+ `ON "a"."id" = "i"."id"`;
35
+ /** The `user_identity` record `i` is a live channel account, whatever the legacy store holds. */
36
+ export const LIVE_CHANNEL_RECORD = `"i"."origin"::text IN ${CHANNEL_ORIGIN_SQL} AND "i"."revoked_at" IS NULL`;
37
+ /** The channel identity `i` (with `a`, see {@link CHANNEL_IDENTITIES_FROM}) is live. */
38
+ export const LIVE_CHANNEL_IDENTITY = `${LIVE_CHANNEL_RECORD} AND "a"."id" IS NOT NULL AND "a"."revoked_at" IS NULL`;
39
+ /**
40
+ * When the channel identity `i` (with `a`) stopped working: its own revocation, else the legacy
41
+ * store's, else, when the legacy row is gone, its last change.
42
+ */
43
+ export const CHANNEL_REVOKED_AT = `COALESCE("i"."revoked_at", "a"."revoked_at", ` +
44
+ `CASE WHEN "a"."id" IS NULL THEN "i"."updated_at" END)`;
45
+ /** The account a legacy `identity_provider` and `identity_subject` name. */
46
+ export function accountOfLegacy(identityProvider, subject) {
47
+ return identityProvider.startsWith(LEGACY_OIDC_PREFIX)
48
+ ? {
49
+ provider: OIDC_PROVIDER,
50
+ issuer: identityProvider.slice(LEGACY_OIDC_PREFIX.length),
51
+ subject,
52
+ }
53
+ : { provider: identityProvider, issuer: null, subject };
54
+ }
55
+ /** The legacy `identity_provider` of an account: `oidc:<issuer>`, or the provider itself. */
56
+ export function legacyProviderOf(account) {
57
+ return account.provider === OIDC_PROVIDER
58
+ ? `${LEGACY_OIDC_PREFIX}${account.issuer ?? ""}`
59
+ : account.provider;
60
+ }
61
+ /** Providers and issuers never hold whitespace, so the space-separated keys are unambiguous. */
62
+ function isKeyPart(value) {
63
+ return value !== "" && !/\s/.test(value);
64
+ }
65
+ function requireKeyPart(value, what) {
66
+ if (!isKeyPart(value)) {
67
+ throw new Error(`An identity ${what} must be non-empty and hold no whitespace.`);
68
+ }
69
+ return value;
70
+ }
71
+ /** Whether the account can be recorded: a key part never holds whitespace, a subject is set. */
72
+ export function isRecordableAccount(account) {
73
+ return (isKeyPart(account.provider) &&
74
+ (account.issuer === null || isKeyPart(account.issuer)) &&
75
+ account.subject !== "");
76
+ }
77
+ /**
78
+ * The live account key: `<provider> <subject>`, or `<provider> <issuer> <subject>` for an issuer.
79
+ * The provider decides whether an issuer is present, and neither holds whitespace, so two accounts
80
+ * never share a key. {@link accountKeySql} computes the same key in SQL.
81
+ */
82
+ export function accountKey(account) {
83
+ const provider = requireKeyPart(account.provider, "provider");
84
+ return account.issuer === null
85
+ ? `${provider} ${account.subject}`
86
+ : `${provider} ${requireKeyPart(account.issuer, "issuer")} ${account.subject}`;
87
+ }
88
+ /** The live member key, `<user id> <provider>`, or none for `oidc`, of which a member has several. */
89
+ export function memberKey(userId, provider) {
90
+ return provider === OIDC_PROVIDER ? null : `${userId} ${provider}`;
91
+ }
92
+ /** {@link accountKey} over the columns `provider`, `issuer` and `subject` of the alias given. */
93
+ export function accountKeySql(alias) {
94
+ return (`(${alias}."provider" || ' ' || COALESCE(${alias}."issuer" || ' ', '') || ` +
95
+ `${alias}."subject")`);
96
+ }
97
+ /** {@link memberKey} over the columns `user_id` and `provider` of the alias given. */
98
+ export function memberKeySql(alias) {
99
+ return (`(CASE WHEN ${alias}."provider" = '${OIDC_PROVIDER}' THEN NULL ` +
100
+ `ELSE ${alias}."user_id"::text || ' ' || ${alias}."provider" END)`);
101
+ }
102
+ /** The active member `u` has a live identity of `provider` that `extra` (SQL on `i`) narrows. */
103
+ const HOLDS = (provider, extra = "") => `EXISTS (SELECT 1 FROM "${USER_IDENTITY_TABLE}" i WHERE i.user_id = u.id ` +
104
+ `AND i.provider = '${provider}' AND i.revoked_at IS NULL${extra})`;
105
+ const ACTIVE_MEMBER = `u.kind::text = 'member' AND u.active = true`;
106
+ /**
107
+ * Refuses a deploy that drops email sign-in while an active member who signs in by email has no
108
+ * SegmentStream (OIDC) identity: they would lose access.
109
+ */
110
+ export const SEGMENTSTREAM_LINK_FENCE_SQL = `DO $$ BEGIN
111
+ IF EXISTS (SELECT 1 FROM "user" u WHERE ${ACTIVE_MEMBER}
112
+ AND ${HOLDS(NEON_AUTH_PROVIDER, ` AND i.origin::text IN ${SIGN_IN_ORIGIN_SQL}`)}
113
+ AND NOT ${HOLDS(OIDC_PROVIDER)})
114
+ THEN RAISE EXCEPTION 'browser_auth_segmentstream_link_required'; END IF;
115
+ END $$`;
116
+ /**
117
+ * Refuses a deploy that drops SegmentStream sign-in while an active member with a SegmentStream
118
+ * identity has no email sign-in: they would lose access.
119
+ */
120
+ export const EMAIL_LINK_FENCE_SQL = `DO $$ BEGIN
121
+ IF EXISTS (SELECT 1 FROM "user" u WHERE ${ACTIVE_MEMBER} AND ${HOLDS(OIDC_PROVIDER)}
122
+ AND NOT ${HOLDS(NEON_AUTH_PROVIDER, ` AND i.origin::text IN ${SIGN_IN_ORIGIN_SQL}`)})
123
+ THEN RAISE EXCEPTION 'browser_auth_email_link_required'; END IF;
124
+ END $$`;
125
+ const HISTORY = quoteIdentifier(`${USER_IDENTITY_TABLE}_history`);
126
+ const IDENTITIES = quoteIdentifier(USER_IDENTITY_TABLE);
127
+ const NOTICES = quoteIdentifier(IDENTITY_NOTICES_TABLE);
128
+ const AGENT = quoteIdentifier(AGENT_IDENTITIES_TABLE);
129
+ const SYNC_ACTION = `'${USER_IDENTITY_TABLE}.sync'`;
130
+ const INSTANT = (column) => `to_char(${column} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`;
131
+ const CHANGE = (field, before, after) => `CASE WHEN (${before}) IS DISTINCT FROM (${after}) THEN jsonb_build_object('${field}', ` +
132
+ `jsonb_build_object('before', to_jsonb(${before}), 'after', to_jsonb(${after}))) ` +
133
+ `ELSE '{}'::jsonb END`;
134
+ /** The history `changes` of a record created from nothing, over the alias `r`. */
135
+ const CREATED = [
136
+ CHANGE("provider", "NULL::text", "r.provider"),
137
+ CHANGE("issuer", "NULL::text", "r.issuer"),
138
+ CHANGE("subject", "NULL::text", "r.subject"),
139
+ CHANGE("username", "NULL::text", "r.username"),
140
+ CHANGE("display", "NULL::text", "r.display"),
141
+ CHANGE("origin", "NULL::text", "r.origin::text"),
142
+ CHANGE("revoked_at", "NULL::text", INSTANT("r.revoked_at")),
143
+ CHANGE("account_key", "NULL::text", "r.account_key"),
144
+ CHANGE("member_key", "NULL::text", "r.member_key"),
145
+ CHANGE("user_id", "NULL::text", "r.user_id::text"),
146
+ ].join(" || ");
147
+ const RECORD_HISTORY = (kind, changes, from) => `INSERT INTO ${HISTORY} ("id", "record_id", "action", "action_id", "kind", "principal_id", ` +
148
+ `"at", "changes") SELECT gen_random_uuid(), r.id, ${SYNC_ACTION}, sync_action, '${kind}', ` +
149
+ `NULL, now(), ${changes} FROM ${from} r`;
150
+ const INSERT_COLUMNS = `"id", "created_at", "updated_at", "created_by", "updated_by", "provider", "issuer", ` +
151
+ `"subject", "username", "display", "origin", "revoked_at", "account_key", "member_key", "user_id"`;
152
+ /** Inserts the rows of `source` (columns as {@link INSERT_COLUMNS}) whose keys are free. */
153
+ const INSERT_FREE = (source) => `WITH source AS (${source}), keyed AS (` +
154
+ `SELECT s.*, CASE WHEN s.revoked_at IS NULL THEN ${accountKeySql("s")} END AS account_key, ` +
155
+ `CASE WHEN s.revoked_at IS NULL THEN ${memberKeySql("s")} END AS member_key FROM source s), ` +
156
+ `free AS (SELECT k.* FROM keyed k ` +
157
+ `WHERE NOT EXISTS (SELECT 1 FROM ${IDENTITIES} i WHERE i.id = k.id ` +
158
+ `OR i.account_key = k.account_key OR i.member_key = k.member_key)), ` +
159
+ `inserted AS (INSERT INTO ${IDENTITIES} (${INSERT_COLUMNS}) ` +
160
+ `SELECT f.id, f.created_at, now(), NULL, NULL, f.provider, f.issuer, f.subject, f.username, ` +
161
+ `f.display, f.origin::"${USER_IDENTITY_TABLE}_origin", f.revoked_at, f.account_key, ` +
162
+ `f.member_key, f.user_id FROM free f RETURNING *) ` +
163
+ RECORD_HISTORY("create", CREATED, "inserted");
164
+ /**
165
+ * Whether the member claimed an invitation: as `_channel_users` records it since it exists, or as the
166
+ * history of `user.invite` does. A statement never names a table the database lacks, even one it
167
+ * would not read, so each variant is generated on its own.
168
+ */
169
+ const INVITED = (userId, channelUsers) => `(${channelUsers
170
+ ? `EXISTS (SELECT 1 FROM "_channel_users" c WHERE c.user_id = ${userId} ` +
171
+ `AND c.created_via = 'invite') OR `
172
+ : ""}EXISTS (SELECT 1 FROM "user_history" h WHERE h.record_id = ${userId} ` +
173
+ `AND h.action = 'user.invite' AND h.kind = 'create'))`;
174
+ /** Members' `identity_provider` and `identity_subject`: `oidc:<issuer>` is an `oidc` account. */
175
+ const MEMBER_SIGN_INS = (channelUsers) => INSERT_FREE(`SELECT gen_random_uuid() AS id, now() AS created_at, l.provider, l.issuer, l.subject,
176
+ NULL::text AS username, NULL::text AS display,
177
+ CASE WHEN ${INVITED("l.user_id", channelUsers)} THEN 'invite' ELSE 'sign_in' END AS origin,
178
+ NULL::timestamptz AS revoked_at, l.user_id
179
+ FROM (SELECT u.id AS user_id,
180
+ CASE WHEN u.identity_provider LIKE '${LEGACY_OIDC_PREFIX}%' THEN '${OIDC_PROVIDER}'
181
+ ELSE u.identity_provider END AS provider,
182
+ CASE WHEN u.identity_provider LIKE '${LEGACY_OIDC_PREFIX}%'
183
+ THEN substr(u.identity_provider, ${LEGACY_OIDC_PREFIX.length + 1}) END AS issuer,
184
+ u.identity_subject AS subject
185
+ FROM "user" u WHERE u.kind::text = 'member' AND u.identity_provider IS NOT NULL
186
+ AND u.identity_provider NOT IN ('', '${LEGACY_OIDC_PREFIX}')
187
+ AND u.identity_provider !~ '\\s' AND COALESCE(u.identity_subject, '') <> '') l
188
+ WHERE NOT EXISTS (SELECT 1 FROM ${IDENTITIES} i WHERE i.provider = l.provider
189
+ AND i.issuer IS NOT DISTINCT FROM l.issuer AND i.subject = l.subject)`);
190
+ /**
191
+ * `_user_identities` bindings. One the member's user columns or their history held is how they
192
+ * signed in; any other was linked to a signed-in member.
193
+ */
194
+ const OIDC_BINDINGS = (channelUsers) => INSERT_FREE(`SELECT gen_random_uuid() AS id, now() AS created_at, '${OIDC_PROVIDER}'::text AS provider,
195
+ b.issuer, b.subject, NULL::text AS username, NULL::text AS display,
196
+ CASE WHEN NOT EXISTS (SELECT 1 FROM "user_history" h WHERE h.record_id = b.user_id
197
+ AND h.changes->'identity_provider'->>'after' = '${LEGACY_OIDC_PREFIX}' || b.issuer
198
+ AND h.changes->'identity_subject'->>'after' = b.subject) THEN 'link'
199
+ WHEN ${INVITED("b.user_id", channelUsers)} THEN 'invite'
200
+ ELSE 'sign_in' END AS origin,
201
+ NULL::timestamptz AS revoked_at, b.user_id
202
+ FROM "_user_identities" b JOIN "user" u ON u.id = b.user_id
203
+ WHERE u.kind::text = 'member' AND b.issuer !~ '\\s' AND b.issuer <> ''
204
+ AND NOT EXISTS (SELECT 1 FROM ${IDENTITIES} i WHERE i.provider = '${OIDC_PROVIDER}'
205
+ AND i.issuer = b.issuer AND i.subject = b.subject)`);
206
+ /**
207
+ * Copies what the legacy stores hold and `user_identity` lacks, idempotently, so that a database
208
+ * served or migrated by an earlier SDK in between is in step again. Each migration runs it, a no-op
209
+ * one included, after the entity's table exists. It deletes channel identities whose
210
+ * `_agent_identities` row is gone (a preview copy clears them), revokes those revoked there, keeps
211
+ * their username and display current, adds missing channel accounts with their ids, members'
212
+ * `identity_provider`/`identity_subject` sign-ins and `_user_identities` bindings, and copies
213
+ * first-contact notices. A row whose key another live identity holds is skipped rather than failing
214
+ * the deploy. Every change is recorded in history under `user_identity.sync`.
215
+ */
216
+ export const USER_IDENTITY_SYNC_SQL = `DO $sync$
217
+ DECLARE
218
+ sync_action uuid := gen_random_uuid();
219
+ channel_users boolean := to_regclass('_channel_users') IS NOT NULL;
220
+ BEGIN
221
+ IF to_regclass('${USER_IDENTITY_TABLE}') IS NULL OR to_regclass('${USER_IDENTITY_TABLE}_history') IS NULL THEN
222
+ RETURN;
223
+ END IF;
224
+ IF to_regclass('${AGENT_IDENTITIES_TABLE}') IS NOT NULL THEN
225
+ WITH removed AS (
226
+ DELETE FROM ${IDENTITIES} i WHERE i.origin::text IN ${CHANNEL_ORIGIN_SQL}
227
+ AND NOT EXISTS (SELECT 1 FROM ${AGENT} a WHERE a.id = i.id)
228
+ RETURNING i.*
229
+ ) ${RECORD_HISTORY("delete", [
230
+ CHANGE("provider", "r.provider", "NULL::text"),
231
+ CHANGE("issuer", "r.issuer", "NULL::text"),
232
+ CHANGE("subject", "r.subject", "NULL::text"),
233
+ CHANGE("username", "r.username", "NULL::text"),
234
+ CHANGE("display", "r.display", "NULL::text"),
235
+ CHANGE("origin", "r.origin::text", "NULL::text"),
236
+ CHANGE("revoked_at", INSTANT("r.revoked_at"), "NULL::text"),
237
+ CHANGE("account_key", "r.account_key", "NULL::text"),
238
+ CHANGE("member_key", "r.member_key", "NULL::text"),
239
+ CHANGE("user_id", "r.user_id::text", "NULL::text"),
240
+ ].join(" || "), "removed")};
241
+ WITH stale AS (
242
+ SELECT i.id, i.account_key, i.member_key, a.revoked_at FROM ${IDENTITIES} i
243
+ JOIN ${AGENT} a ON a.id = i.id
244
+ WHERE a.revoked_at IS NOT NULL AND i.revoked_at IS NULL
245
+ FOR UPDATE OF i
246
+ ), revoked AS (
247
+ UPDATE ${IDENTITIES} i SET revoked_at = s.revoked_at, account_key = NULL, member_key = NULL,
248
+ updated_at = now(), updated_by = NULL
249
+ FROM stale s WHERE i.id = s.id RETURNING i.id
250
+ ) ${RECORD_HISTORY("update", [
251
+ CHANGE("revoked_at", "NULL::text", INSTANT("r.revoked_at")),
252
+ CHANGE("account_key", "r.account_key", "NULL::text"),
253
+ CHANGE("member_key", "r.member_key", "NULL::text"),
254
+ ].join(" || "), "stale")};
255
+ WITH described AS (
256
+ SELECT i.id, i.username AS old_username, i.display AS old_display,
257
+ a.username, a.display FROM ${IDENTITIES} i JOIN ${AGENT} a ON a.id = i.id
258
+ WHERE i.revoked_at IS NULL AND a.revoked_at IS NULL
259
+ AND (i.username IS DISTINCT FROM a.username OR i.display IS DISTINCT FROM a.display)
260
+ FOR UPDATE OF i
261
+ ), updated AS (
262
+ UPDATE ${IDENTITIES} i SET username = d.username, display = d.display, updated_at = now(),
263
+ updated_by = NULL FROM described d WHERE i.id = d.id RETURNING i.id
264
+ ) ${RECORD_HISTORY("update", [
265
+ CHANGE("username", "r.old_username", "r.username"),
266
+ CHANGE("display", "r.old_display", "r.display"),
267
+ ].join(" || "), "described")};
268
+ ${INSERT_FREE(`SELECT a.id, a.created_at, a.provider, NULL::text AS issuer, a.external_id AS subject,
269
+ a.username, a.display,
270
+ CASE WHEN a.origin = 'provisioned' THEN 'channel' ELSE 'pairing' END AS origin,
271
+ a.revoked_at, a.user_id FROM ${AGENT} a`)};
272
+ END IF;
273
+ IF channel_users THEN
274
+ ${MEMBER_SIGN_INS(true)};
275
+ ELSE
276
+ ${MEMBER_SIGN_INS(false)};
277
+ END IF;
278
+ IF to_regclass('_user_identities') IS NOT NULL THEN
279
+ IF channel_users THEN
280
+ ${OIDC_BINDINGS(true)};
281
+ ELSE
282
+ ${OIDC_BINDINGS(false)};
283
+ END IF;
284
+ END IF;
285
+ IF to_regclass('${IDENTITY_NOTICES_TABLE}') IS NOT NULL THEN
286
+ IF to_regclass('${AGENT_IDENTITIES_TABLE}') IS NOT NULL THEN
287
+ INSERT INTO ${NOTICES} (identity_id, noticed_at, notice_sha256, notice_version)
288
+ SELECT a.id, a.noticed_at, a.notice_sha256, a.notice_version FROM ${AGENT} a
289
+ WHERE a.noticed_at IS NOT NULL AND EXISTS (SELECT 1 FROM ${IDENTITIES} i WHERE i.id = a.id)
290
+ ON CONFLICT (identity_id) DO UPDATE SET noticed_at = EXCLUDED.noticed_at,
291
+ notice_sha256 = EXCLUDED.notice_sha256, notice_version = EXCLUDED.notice_version
292
+ WHERE (${NOTICES}.noticed_at, ${NOTICES}.notice_sha256, ${NOTICES}.notice_version)
293
+ IS DISTINCT FROM (EXCLUDED.noticed_at, EXCLUDED.notice_sha256, EXCLUDED.notice_version);
294
+ END IF;
295
+ DELETE FROM ${NOTICES} n WHERE NOT EXISTS (SELECT 1 FROM ${IDENTITIES} i WHERE i.id = n.identity_id);
296
+ END IF;
297
+ END $sync$`;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The built-in user's `roles`: the roles assigned to the user in `_user_roles`, sorted, without the
3
+ * `member` every active member holds implicitly. It is the only `list` property, and has no column.
4
+ */
5
+ export declare const USER_ROLES_PROPERTY = "roles";
6
+ /**
7
+ * The roles of the user whose id is the SQL expression `userId`, as a JSON array: sorted, without
8
+ * `member`, `[]` when none. As a subquery of the statement that reads the user, it is consistent
9
+ * with the row it reads.
10
+ */
11
+ export declare function userRolesExpression(userId: string): string;
12
+ /**
13
+ * Whether the user whose id is the SQL expression `userId` is assigned one of the roles, given as
14
+ * SQL expressions such as parameters. `member` is never listed, so it matches no user.
15
+ */
16
+ export declare function userHoldsRoleCondition(userId: string, roles: ReadonlyArray<string>): string;
@@ -0,0 +1,32 @@
1
+ import { USER_ROLES_TABLE, quoteIdentifier, quoteLiteral } from "../migrate/storage.js";
2
+ import { MEMBER_ROLE } from "../names.js";
3
+ /**
4
+ * The built-in user's `roles`: the roles assigned to the user in `_user_roles`, sorted, without the
5
+ * `member` every active member holds implicitly. It is the only `list` property, and has no column.
6
+ */
7
+ export const USER_ROLES_PROPERTY = "roles";
8
+ const ROLES = quoteIdentifier(USER_ROLES_TABLE);
9
+ /** Unlikely to shadow an alias of the enclosing statement, whose aliases are `t0`, `t1`, `j0`… */
10
+ const ASSIGNED = '"_assigned_role"';
11
+ const NOT_MEMBER = `${ASSIGNED}."role" <> ${quoteLiteral(MEMBER_ROLE)}`;
12
+ /**
13
+ * The roles of the user whose id is the SQL expression `userId`, as a JSON array: sorted, without
14
+ * `member`, `[]` when none. As a subquery of the statement that reads the user, it is consistent
15
+ * with the row it reads.
16
+ */
17
+ export function userRolesExpression(userId) {
18
+ return (`COALESCE((SELECT json_agg(${ASSIGNED}."role" ORDER BY ${ASSIGNED}."role") ` +
19
+ `FROM ${ROLES} AS ${ASSIGNED} WHERE ${ASSIGNED}."user_id" = ${userId} AND ${NOT_MEMBER}), ` +
20
+ `'[]'::json)`);
21
+ }
22
+ /**
23
+ * Whether the user whose id is the SQL expression `userId` is assigned one of the roles, given as
24
+ * SQL expressions such as parameters. `member` is never listed, so it matches no user.
25
+ */
26
+ export function userHoldsRoleCondition(userId, roles) {
27
+ if (roles.length === 0) {
28
+ return "FALSE";
29
+ }
30
+ return (`EXISTS (SELECT 1 FROM ${ROLES} AS ${ASSIGNED} WHERE ${ASSIGNED}."user_id" = ${userId} ` +
31
+ `AND ${NOT_MEMBER} AND ${ASSIGNED}."role" IN (${roles.join(", ")}))`);
32
+ }