@noodleseed/one 0.162.0 → 0.164.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 (326) hide show
  1. package/dist/banner.d.ts +6 -0
  2. package/dist/banner.d.ts.map +1 -0
  3. package/dist/banner.js +29 -0
  4. package/dist/banner.js.map +1 -0
  5. package/dist/commands/billing-catalog-ops.d.ts +4 -0
  6. package/dist/commands/billing-catalog-ops.d.ts.map +1 -0
  7. package/dist/commands/billing-catalog-ops.js +58 -0
  8. package/dist/commands/billing-catalog-ops.js.map +1 -0
  9. package/dist/commands/billing-ops.d.ts.map +1 -1
  10. package/dist/commands/billing-ops.js +3 -0
  11. package/dist/commands/billing-ops.js.map +1 -1
  12. package/dist/commands/catalog.d.ts.map +1 -1
  13. package/dist/commands/catalog.js +2 -0
  14. package/dist/commands/catalog.js.map +1 -1
  15. package/dist/commands/config-values.d.ts.map +1 -1
  16. package/dist/commands/config-values.js +16 -0
  17. package/dist/commands/config-values.js.map +1 -1
  18. package/dist/commands/installation-variables.d.ts +26 -0
  19. package/dist/commands/installation-variables.d.ts.map +1 -0
  20. package/dist/commands/installation-variables.js +171 -0
  21. package/dist/commands/installation-variables.js.map +1 -0
  22. package/dist/commands/project-setup.d.ts.map +1 -1
  23. package/dist/commands/project-setup.js +2 -0
  24. package/dist/commands/project-setup.js.map +1 -1
  25. package/dist/commands/solutions-activity.d.ts +5 -0
  26. package/dist/commands/solutions-activity.d.ts.map +1 -0
  27. package/dist/commands/solutions-activity.js +116 -0
  28. package/dist/commands/solutions-activity.js.map +1 -0
  29. package/dist/commands/solutions-connections.d.ts +7 -0
  30. package/dist/commands/solutions-connections.d.ts.map +1 -0
  31. package/dist/commands/solutions-connections.js +88 -0
  32. package/dist/commands/solutions-connections.js.map +1 -0
  33. package/dist/commands/solutions-installation-options.d.ts +5 -0
  34. package/dist/commands/solutions-installation-options.d.ts.map +1 -0
  35. package/dist/commands/solutions-installation-options.js +52 -0
  36. package/dist/commands/solutions-installation-options.js.map +1 -0
  37. package/dist/commands/solutions-onboarding.d.ts +5 -0
  38. package/dist/commands/solutions-onboarding.d.ts.map +1 -0
  39. package/dist/commands/solutions-onboarding.js +113 -0
  40. package/dist/commands/solutions-onboarding.js.map +1 -0
  41. package/dist/commands/solutions-ops.d.ts.map +1 -1
  42. package/dist/commands/solutions-ops.js +278 -17
  43. package/dist/commands/solutions-ops.js.map +1 -1
  44. package/dist/first-run.d.ts.map +1 -1
  45. package/dist/first-run.js +2 -0
  46. package/dist/first-run.js.map +1 -1
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +1 -1
  50. package/dist/index.js.map +1 -1
  51. package/node_modules/@noodle-borg/admission-limits/dist/counter-store.d.ts +21 -2
  52. package/node_modules/@noodle-borg/admission-limits/dist/counter-store.js +10 -1
  53. package/node_modules/@noodle-borg/admission-limits/dist/in-memory-counter-store.d.ts +5 -1
  54. package/node_modules/@noodle-borg/admission-limits/dist/in-memory-counter-store.js +31 -2
  55. package/node_modules/@noodle-borg/admission-limits/dist/portable.d.ts +3 -0
  56. package/node_modules/@noodle-borg/admission-limits/dist/portable.js +3 -0
  57. package/node_modules/@noodle-borg/admission-limits/dist/public-admission-assertion.d.ts +28 -0
  58. package/node_modules/@noodle-borg/admission-limits/dist/public-admission-assertion.js +124 -0
  59. package/node_modules/@noodle-borg/admission-limits/dist/public-record-admission.d.ts +54 -0
  60. package/node_modules/@noodle-borg/admission-limits/dist/public-record-admission.js +74 -0
  61. package/node_modules/@noodle-borg/admission-limits/dist/request-attribution.d.ts +11 -0
  62. package/node_modules/@noodle-borg/admission-limits/dist/request-attribution.js +19 -0
  63. package/node_modules/@noodle-borg/agent-kit/dist/curated/error-fixes.js +2 -0
  64. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +5 -5
  65. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +3 -0
  66. package/node_modules/@noodle-borg/agent-kit/dist/index.d.ts +1 -0
  67. package/node_modules/@noodle-borg/agent-kit/dist/index.js +1 -0
  68. package/node_modules/@noodle-borg/agent-kit/dist/plugin-bootstrap-skill.js +10 -0
  69. package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +15 -3
  70. package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js +1 -1
  71. package/node_modules/@noodle-borg/agent-kit/dist/welcome-wordmark.d.ts +3 -0
  72. package/node_modules/@noodle-borg/agent-kit/dist/welcome-wordmark.js +10 -0
  73. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  74. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-configuration.d.ts +9 -1
  75. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-configuration.js +33 -2
  76. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-execution-bound.d.ts +3 -0
  77. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-execution-bound.js +29 -0
  78. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-interaction-state.d.ts +5 -3
  79. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-interaction-state.js +21 -10
  80. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.d.ts +1 -1
  81. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.js +3 -3
  82. package/node_modules/@noodle-borg/assistant-gateway/dist/portable.d.ts +1 -0
  83. package/node_modules/@noodle-borg/assistant-gateway/dist/portable.js +1 -0
  84. package/node_modules/@noodle-borg/assistant-gateway/dist/session-target.js +5 -4
  85. package/node_modules/@noodle-borg/assistant-gateway/package.json +1 -1
  86. package/node_modules/@noodle-borg/authoring/dist/config.d.ts +20 -0
  87. package/node_modules/@noodle-borg/authoring/dist/config.js +29 -2
  88. package/node_modules/@noodle-borg/authoring/dist/connectors.d.ts +6 -1
  89. package/node_modules/@noodle-borg/authoring/dist/connectors.js +5 -0
  90. package/node_modules/@noodle-borg/authoring/dist/index.d.ts +2 -2
  91. package/node_modules/@noodle-borg/authoring/dist/json-schema.d.ts +1 -1
  92. package/node_modules/@noodle-borg/authoring/dist/json-schema.js +15 -2
  93. package/node_modules/@noodle-borg/authoring/dist/load-authored.js +1 -1
  94. package/node_modules/@noodle-borg/authoring/dist/managed-collection.d.ts +18 -4
  95. package/node_modules/@noodle-borg/authoring/dist/managed-collection.js +22 -3
  96. package/node_modules/@noodle-borg/authoring/dist/platform.d.ts +3 -0
  97. package/node_modules/@noodle-borg/authoring/dist/platform.js +4 -0
  98. package/node_modules/@noodle-borg/authoring/dist/server-presentation.js +43 -0
  99. package/node_modules/@noodle-borg/authoring/dist/server.d.ts +3 -1
  100. package/node_modules/@noodle-borg/authoring/dist/server.js +4 -44
  101. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-billing.js +18 -0
  102. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-config.js +31 -4
  103. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solutions.js +778 -0
  104. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-tenant-resources.js +0 -241
  105. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-types.js +7 -0
  106. package/node_modules/@noodle-borg/cli-catalog/dist/index.js +20 -0
  107. package/node_modules/@noodle-borg/compiler/dist/artifact/assemble.js +2 -1
  108. package/node_modules/@noodle-borg/compiler/dist/artifact/catalog-emission.js +3 -1
  109. package/node_modules/@noodle-borg/compiler/dist/artifact/config.js +3 -0
  110. package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +17 -1
  111. package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +6 -1
  112. package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +6 -1
  113. package/node_modules/@noodle-borg/compiler/dist/business-variables.d.ts +27 -0
  114. package/node_modules/@noodle-borg/compiler/dist/business-variables.js +230 -0
  115. package/node_modules/@noodle-borg/compiler/dist/compile.js +7 -1
  116. package/node_modules/@noodle-borg/compiler/dist/errors.d.ts +1 -1
  117. package/node_modules/@noodle-borg/compiler/dist/index.d.ts +3 -0
  118. package/node_modules/@noodle-borg/compiler/dist/index.js +3 -0
  119. package/node_modules/@noodle-borg/compiler/dist/managed-collection-controls.d.ts +52 -0
  120. package/node_modules/@noodle-borg/compiler/dist/managed-collection-controls.js +92 -0
  121. package/node_modules/@noodle-borg/compiler/dist/managed-collections.d.ts +26 -1
  122. package/node_modules/@noodle-borg/compiler/dist/managed-collections.js +190 -1
  123. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +100 -36
  124. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +2 -0
  125. package/node_modules/@noodle-borg/compiler/dist/native-record-operations.d.ts +7 -0
  126. package/node_modules/@noodle-borg/compiler/dist/native-record-operations.js +59 -0
  127. package/node_modules/@noodle-borg/connector-defs/dist/compile-http.js +83 -8
  128. package/node_modules/@noodle-borg/connector-defs/dist/schema.d.ts +31 -1
  129. package/node_modules/@noodle-borg/connector-defs/dist/schema.js +16 -0
  130. package/node_modules/@noodle-borg/connector-http/dist/http-connector.d.ts +12 -3
  131. package/node_modules/@noodle-borg/connector-http/dist/http-connector.js +41 -2
  132. package/node_modules/@noodle-borg/connector-http/dist/http-response.js +3 -2
  133. package/node_modules/@noodle-borg/connector-http/dist/mcp/config.js +1 -1
  134. package/node_modules/@noodle-borg/connector-http/dist/url-resolution.js +1 -1
  135. package/node_modules/@noodle-borg/control-plane/dist/contracts.d.ts +4 -1
  136. package/node_modules/@noodle-borg/control-plane/dist/deploy-gates.js +1 -0
  137. package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.d.ts +3 -0
  138. package/node_modules/@noodle-borg/control-plane/dist/in-memory-organization-store.js +11 -0
  139. package/node_modules/@noodle-borg/control-plane/dist/organization-agreements.d.ts +45 -0
  140. package/node_modules/@noodle-borg/control-plane/dist/organization-agreements.js +74 -0
  141. package/node_modules/@noodle-borg/control-plane/dist/portable.d.ts +1 -0
  142. package/node_modules/@noodle-borg/control-plane/dist/portable.js +1 -0
  143. package/node_modules/@noodle-borg/module/dist/contract.d.ts +22 -0
  144. package/node_modules/@noodle-borg/module/dist/platform-human-identity.d.ts +2 -0
  145. package/node_modules/@noodle-borg/protocol/dist/request-deps.js +1 -0
  146. package/node_modules/@noodle-borg/protocol/dist/request-state.d.ts +1 -0
  147. package/node_modules/@noodle-borg/protocol/dist/request-state.js +11 -2
  148. package/node_modules/@noodle-borg/protocol/dist/sdk-server.d.ts +2 -0
  149. package/node_modules/@noodle-borg/protocol/dist/v2/input-required.js +2 -1
  150. package/node_modules/@noodle-borg/protocol/dist/v2/server.js +2 -1
  151. package/node_modules/@noodle-borg/runtime/dist/ambient-context.js +6 -1
  152. package/node_modules/@noodle-borg/runtime/dist/broker/types.d.ts +2 -0
  153. package/node_modules/@noodle-borg/runtime/dist/business-variables.d.ts +15 -0
  154. package/node_modules/@noodle-borg/runtime/dist/business-variables.js +75 -0
  155. package/node_modules/@noodle-borg/runtime/dist/confirmation-continuation.js +2 -1
  156. package/node_modules/@noodle-borg/runtime/dist/confirmation.js +23 -3
  157. package/node_modules/@noodle-borg/runtime/dist/connector/types.d.ts +17 -1
  158. package/node_modules/@noodle-borg/runtime/dist/connector-snapshot.js +6 -0
  159. package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +18 -3
  160. package/node_modules/@noodle-borg/runtime/dist/execute.js +13 -3
  161. package/node_modules/@noodle-borg/runtime/dist/index.d.ts +2 -0
  162. package/node_modules/@noodle-borg/runtime/dist/index.js +1 -0
  163. package/node_modules/@noodle-borg/runtime/dist/interactive.js +11 -0
  164. package/node_modules/@noodle-borg/runtime/dist/managed-origins.d.ts +3 -1
  165. package/node_modules/@noodle-borg/runtime/dist/managed-origins.js +32 -7
  166. package/node_modules/@noodle-borg/runtime/dist/operation-credential.js +6 -0
  167. package/node_modules/@noodle-borg/runtime/dist/operation-evidence.d.ts +30 -0
  168. package/node_modules/@noodle-borg/runtime/dist/operation-evidence.js +68 -0
  169. package/node_modules/@noodle-borg/runtime/dist/operation-execution.d.ts +2 -2
  170. package/node_modules/@noodle-borg/runtime/dist/operation-execution.js +142 -71
  171. package/node_modules/@noodle-borg/runtime/dist/result.d.ts +6 -4
  172. package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.d.ts +7 -0
  173. package/node_modules/@noodle-borg/runtime/dist/tool-dispatch.js +48 -4
  174. package/node_modules/@noodle-borg/service/dist/admission.js +2 -1
  175. package/node_modules/@noodle-borg/service/dist/application-activity.js +236 -0
  176. package/node_modules/@noodle-borg/service/dist/application-business-notice.js +28 -0
  177. package/node_modules/@noodle-borg/service/dist/application-runtime-target.js +141 -0
  178. package/node_modules/@noodle-borg/service/dist/application-settings-targets.js +72 -0
  179. package/node_modules/@noodle-borg/service/dist/application-settings.js +210 -0
  180. package/node_modules/@noodle-borg/service/dist/business-api-admission.js +121 -0
  181. package/node_modules/@noodle-borg/service/dist/business-information/activity-pagination.js +73 -0
  182. package/node_modules/@noodle-borg/service/dist/business-information/business-notice.d.ts +24 -0
  183. package/node_modules/@noodle-borg/service/dist/business-information/business-notice.js +18 -0
  184. package/node_modules/@noodle-borg/service/dist/business-information/collection-controls.js +51 -0
  185. package/node_modules/@noodle-borg/service/dist/business-information/contracts.d.ts +439 -0
  186. package/node_modules/@noodle-borg/service/dist/business-information/definition-resolver.js +94 -0
  187. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-installation-lifecycle.js +136 -0
  188. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-invitations.js +160 -0
  189. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-locks.js +23 -0
  190. package/node_modules/@noodle-borg/service/dist/business-information/in-memory-store.js +287 -132
  191. package/node_modules/@noodle-borg/service/dist/business-information/installation-capacity.js +10 -0
  192. package/node_modules/@noodle-borg/service/dist/business-information/invitations.js +68 -0
  193. package/node_modules/@noodle-borg/service/dist/business-information/legacy-request-migration.js +60 -0
  194. package/node_modules/@noodle-borg/service/dist/business-information/managed-releases.js +245 -0
  195. package/node_modules/@noodle-borg/service/dist/business-information/managed-solution-blueprints.js +51 -0
  196. package/node_modules/@noodle-borg/service/dist/business-information/managed-solution-executable.js +76 -0
  197. package/node_modules/@noodle-borg/service/dist/business-information/model.js +124 -23
  198. package/node_modules/@noodle-borg/service/dist/business-information/native-query.js +162 -0
  199. package/node_modules/@noodle-borg/service/dist/business-information/native-storage-budget.js +60 -0
  200. package/node_modules/@noodle-borg/service/dist/business-information/pagination.js +28 -0
  201. package/node_modules/@noodle-borg/service/dist/business-information/portable.js +9 -0
  202. package/node_modules/@noodle-borg/service/dist/business-information/principal-authority.d.ts +11 -0
  203. package/node_modules/@noodle-borg/service/dist/business-information/principal-authority.js +42 -0
  204. package/node_modules/@noodle-borg/service/dist/business-information/profiles.js +137 -6
  205. package/node_modules/@noodle-borg/service/dist/business-information/reader-floor.js +26 -0
  206. package/node_modules/@noodle-borg/service/dist/business-information/source-credential-fence.js +79 -0
  207. package/node_modules/@noodle-borg/service/dist/business-information/source-custody-budget.js +30 -0
  208. package/node_modules/@noodle-borg/service/dist/business-information/source-custody-memory.js +122 -0
  209. package/node_modules/@noodle-borg/service/dist/business-information/source-executor.js +191 -0
  210. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-contracts.js +2 -0
  211. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-coordinator.js +136 -0
  212. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-failures.js +32 -0
  213. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-memory-state.js +154 -0
  214. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-memory-store.js +568 -0
  215. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-memory-types.js +26 -0
  216. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-memory-values.js +59 -0
  217. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-pagination.js +54 -0
  218. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-validation.js +163 -0
  219. package/node_modules/@noodle-borg/service/dist/business-information/source-refresh-retention.js +29 -0
  220. package/node_modules/@noodle-borg/service/dist/business-information-runtime.js +80 -0
  221. package/node_modules/@noodle-borg/service/dist/business-onboarding.js +73 -0
  222. package/node_modules/@noodle-borg/service/dist/connections/types.js +8 -0
  223. package/node_modules/@noodle-borg/service/dist/credential-binding-index.js +38 -33
  224. package/node_modules/@noodle-borg/service/dist/deployment-execution.js +275 -0
  225. package/node_modules/@noodle-borg/service/dist/external-credential-binding-broker.js +19 -1
  226. package/node_modules/@noodle-borg/service/dist/external-credential-exchange.d.ts +16 -1
  227. package/node_modules/@noodle-borg/service/dist/modules/host.js +4 -1
  228. package/node_modules/@noodle-borg/service/dist/native-record-connector.d.ts +20 -0
  229. package/node_modules/@noodle-borg/service/dist/native-record-connector.js +206 -0
  230. package/node_modules/@noodle-borg/service/dist/oauth/store.d.ts +3 -0
  231. package/node_modules/@noodle-borg/service/dist/operation-evidence.js +89 -0
  232. package/node_modules/@noodle-borg/service/dist/recovery-quarantine.js +49 -0
  233. package/node_modules/@noodle-borg/service/dist/registry-compile.js +60 -11
  234. package/node_modules/@noodle-borg/service/dist/registry-deploy-transaction.js +18 -0
  235. package/node_modules/@noodle-borg/service/dist/registry-rollback.js +2 -1
  236. package/node_modules/@noodle-borg/service/dist/registry-state.d.ts +1 -1
  237. package/node_modules/@noodle-borg/service/dist/registry-state.js +6 -3
  238. package/node_modules/@noodle-borg/service/dist/registry-targets.js +49 -0
  239. package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +2 -0
  240. package/node_modules/@noodle-borg/service/dist/registry.d.ts +15 -3
  241. package/node_modules/@noodle-borg/service/dist/registry.js +177 -137
  242. package/node_modules/@noodle-borg/service/dist/routes/assistant-appearance.js +3 -2
  243. package/node_modules/@noodle-borg/service/dist/routes/assistant-clients.js +2 -1
  244. package/node_modules/@noodle-borg/service/dist/routes/assistant-doctor.js +2 -1
  245. package/node_modules/@noodle-borg/service/dist/routes/assistant-embeds.js +8 -3
  246. package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-replay.js +1 -1
  247. package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js +48 -36
  248. package/node_modules/@noodle-borg/service/dist/routes/assistant-public-configuration.js +3 -2
  249. package/node_modules/@noodle-borg/service/dist/routes/assistant-public-session.js +10 -10
  250. package/node_modules/@noodle-borg/service/dist/routes/assistant-session-target.js +32 -3
  251. package/node_modules/@noodle-borg/service/dist/routes/assistant-suggestions.js +1 -1
  252. package/node_modules/@noodle-borg/service/dist/routes/assistant-transcript.js +1 -1
  253. package/node_modules/@noodle-borg/service/dist/routes/assistant.js +10 -10
  254. package/node_modules/@noodle-borg/service/dist/routes/business-information-activity.js +83 -0
  255. package/node_modules/@noodle-borg/service/dist/routes/business-information-admission.js +26 -0
  256. package/node_modules/@noodle-borg/service/dist/routes/business-information-channels.js +153 -0
  257. package/node_modules/@noodle-borg/service/dist/routes/business-information-connections.js +107 -0
  258. package/node_modules/@noodle-borg/service/dist/routes/business-information-dispatch.js +87 -4
  259. package/node_modules/@noodle-borg/service/dist/routes/business-information-external.js +79 -0
  260. package/node_modules/@noodle-borg/service/dist/routes/business-information-installation.js +24 -0
  261. package/node_modules/@noodle-borg/service/dist/routes/business-information-notice.js +69 -0
  262. package/node_modules/@noodle-borg/service/dist/routes/business-information-onboarding.js +58 -0
  263. package/node_modules/@noodle-borg/service/dist/routes/business-information-paths.js +76 -0
  264. package/node_modules/@noodle-borg/service/dist/routes/business-information-public.js +151 -0
  265. package/node_modules/@noodle-borg/service/dist/routes/business-information-reader-floor.js +15 -0
  266. package/node_modules/@noodle-borg/service/dist/routes/business-information-record-create.js +29 -0
  267. package/node_modules/@noodle-borg/service/dist/routes/business-information-record-reads.js +36 -0
  268. package/node_modules/@noodle-borg/service/dist/routes/business-information-request.js +64 -0
  269. package/node_modules/@noodle-borg/service/dist/routes/business-information-settings.js +64 -0
  270. package/node_modules/@noodle-borg/service/dist/routes/business-information-source.js +249 -0
  271. package/node_modules/@noodle-borg/service/dist/routes/business-information-staff.js +258 -0
  272. package/node_modules/@noodle-borg/service/dist/routes/business-information-wire.js +226 -26
  273. package/node_modules/@noodle-borg/service/dist/routes/business-information.js +238 -197
  274. package/node_modules/@noodle-borg/service/dist/routes/config-values-dispatch.js +1 -1
  275. package/node_modules/@noodle-borg/service/dist/routes/config-values.js +26 -4
  276. package/node_modules/@noodle-borg/service/dist/routes/control-plane.js +33 -234
  277. package/node_modules/@noodle-borg/service/dist/routes/deployment-activation-response.js +13 -4
  278. package/node_modules/@noodle-borg/service/dist/service-resource-cleanup.js +4 -0
  279. package/node_modules/@noodle-borg/service/dist/service.js +57 -11
  280. package/node_modules/@noodle-borg/service/dist/solution-installation-activation.js +149 -0
  281. package/node_modules/@noodle-borg/service/dist/source-configuration-authority.js +94 -0
  282. package/node_modules/@noodle-borg/service/dist/state-catalog.js +6 -5
  283. package/node_modules/@noodle-borg/service/dist/store/config-values.d.ts +42 -17
  284. package/node_modules/@noodle-borg/service/dist/store/config-values.js +123 -24
  285. package/node_modules/@noodle-borg/service/dist/store/in-memory.d.ts +1 -0
  286. package/node_modules/@noodle-borg/service/dist/store/in-memory.js +3 -0
  287. package/node_modules/@noodle-borg/service/dist/store/json-file.d.ts +1 -0
  288. package/node_modules/@noodle-borg/service/dist/store/json-file.js +3 -0
  289. package/node_modules/@noodle-borg/service/dist/store.d.ts +3 -1
  290. package/node_modules/@noodle-borg/service/package.json +2 -2
  291. package/node_modules/@noodle-borg/transport-http/dist/serve-request.js +9 -0
  292. package/node_modules/@noodle-borg/transport-http/package.json +1 -0
  293. package/node_modules/@noodle-borg/wire-contracts/dist/application-activity.d.ts +143 -0
  294. package/node_modules/@noodle-borg/wire-contracts/dist/application-activity.js +90 -0
  295. package/node_modules/@noodle-borg/wire-contracts/dist/application-channels.d.ts +130 -0
  296. package/node_modules/@noodle-borg/wire-contracts/dist/application-channels.js +77 -0
  297. package/node_modules/@noodle-borg/wire-contracts/dist/application-connections.d.ts +105 -0
  298. package/node_modules/@noodle-borg/wire-contracts/dist/application-connections.js +67 -0
  299. package/node_modules/@noodle-borg/wire-contracts/dist/application-onboarding.d.ts +27 -0
  300. package/node_modules/@noodle-borg/wire-contracts/dist/application-onboarding.js +28 -0
  301. package/node_modules/@noodle-borg/wire-contracts/dist/application-settings.d.ts +112 -0
  302. package/node_modules/@noodle-borg/wire-contracts/dist/application-settings.js +88 -0
  303. package/node_modules/@noodle-borg/wire-contracts/dist/assistant.d.ts +1 -1
  304. package/node_modules/@noodle-borg/wire-contracts/dist/billing-catalog.d.ts +62 -0
  305. package/node_modules/@noodle-borg/wire-contracts/dist/billing-catalog.js +57 -0
  306. package/node_modules/@noodle-borg/wire-contracts/dist/billing-enforcement.d.ts +12 -12
  307. package/node_modules/@noodle-borg/wire-contracts/dist/billing-metering.d.ts +4 -4
  308. package/node_modules/@noodle-borg/wire-contracts/dist/billing-org-transfer.d.ts +3 -3
  309. package/node_modules/@noodle-borg/wire-contracts/dist/business-information-query.d.ts +25 -0
  310. package/node_modules/@noodle-borg/wire-contracts/dist/business-information-query.js +37 -0
  311. package/node_modules/@noodle-borg/wire-contracts/dist/business-information.d.ts +1816 -158
  312. package/node_modules/@noodle-borg/wire-contracts/dist/business-information.js +416 -41
  313. package/node_modules/@noodle-borg/wire-contracts/dist/control-plane.d.ts +2 -2
  314. package/node_modules/@noodle-borg/wire-contracts/dist/distribution.d.ts +5 -5
  315. package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +8 -0
  316. package/node_modules/@noodle-borg/wire-contracts/dist/index.js +8 -0
  317. package/node_modules/@noodle-borg/wire-contracts/dist/knowledge.d.ts +3 -3
  318. package/node_modules/@noodle-borg/wire-contracts/dist/managed-assistant-sponsorship.d.ts +7 -7
  319. package/node_modules/@noodle-borg/wire-contracts/dist/platform-account-reset.d.ts +5 -0
  320. package/node_modules/@noodle-borg/wire-contracts/dist/platform-account-reset.js +1 -0
  321. package/node_modules/@noodle-borg/wire-contracts/dist/platform-auth.d.ts +66 -66
  322. package/node_modules/@noodle-borg/wire-contracts/dist/solution-onboarding.d.ts +143 -0
  323. package/node_modules/@noodle-borg/wire-contracts/dist/solution-onboarding.js +94 -0
  324. package/node_modules/@noodleseed/assistant/README.md +5 -0
  325. package/node_modules/@noodleseed/assistant/package.json +1 -1
  326. package/package.json +2 -2
@@ -1,11 +1,14 @@
1
- import { createHash } from 'node:crypto';
2
- import { clientAddressBucket, } from '@noodle-borg/admission-limits/portable';
3
1
  import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
4
- import { BusinessGrantCreateRequestSchema, formatWireError, ManagedRecordCreateRequestSchema, ManagedRecordMutationRequestSchema, ManagedRecordStatusSchema, SolutionInstallationCreateRequestSchema, } from '@noodle-borg/wire-contracts';
5
- import { BUILT_IN_SOLUTION_PROFILES, businessGrantAllows, CursorValidationError, PayloadValidationError, validateProfilePayload, } from '../business-information/portable.js';
2
+ import { BusinessGrantCreateRequestSchema, formatWireError, ManagedRecordCreateRequestSchema, ManagedRecordMutationRequestSchema, ManagedRecordStatusSchema, SolutionInstallationCreateRequestSchema, SolutionInstallationIntakeRequestSchema, } from '@noodle-borg/wire-contracts';
3
+ import { admitBusinessMutation, admitBusinessTarget, authorizeBusinessApi, } from '../business-api-admission.js';
4
+ import { BUILT_IN_SOLUTION_PROFILES, businessGrantAllows, MANAGED_SOLUTION_PROFILE_KEYS, PayloadValidationError, validateCollectionEnabled, } from '../business-information/portable.js';
6
5
  import { sendForbidden } from '../http-util.js';
7
- import { activityToWire, grantToWire, installationToWire, profileToWire, recordToWire, } from './business-information-wire.js';
8
- import { authorizeControlPlane } from './control-plane.js';
6
+ import { loadExternalRecord, sendExternalRecordPage, sourceBindingKey, unsupportedExternalOperation, } from './business-information-external.js';
7
+ import { resolveInstallDefinition, stableInstallationId, } from './business-information-installation.js';
8
+ import { createNativeRecord } from './business-information-record-create.js';
9
+ import { cursorRequest, sendNativeRecordActivity } from './business-information-record-reads.js';
10
+ import { expectedRevision, mutationPermission, parseNativeRecordQuery, parseBusinessPaging as parsePaging, requestIdempotencyKey, } from './business-information-request.js';
11
+ import { collectionToWire, externalRecordToWire, grantToWire, installationToWire, profileToWire, recordDetailToWire, recordToWire, } from './business-information-wire.js';
9
12
  import { canManageMembers } from './org-admin.js';
10
13
  export function handleSolutionCatalog(req, res) {
11
14
  if (req.method !== 'GET') {
@@ -14,7 +17,9 @@ export function handleSolutionCatalog(req, res) {
14
17
  }
15
18
  sendJson(res, 200, {
16
19
  ok: true,
17
- data: { profiles: Object.values(BUILT_IN_SOLUTION_PROFILES).map(profileToWire) },
20
+ data: {
21
+ profiles: MANAGED_SOLUTION_PROFILE_KEYS.map((key) => profileToWire(BUILT_IN_SOLUTION_PROFILES[key])),
22
+ },
18
23
  });
19
24
  }
20
25
  export async function handleSolutionInstallations(req, res, ref, deps) {
@@ -25,13 +30,21 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
25
30
  if (!(await canManageMembers(deps.controlPlane, ref.org, identity))) {
26
31
  return sendForbidden(res, 'organization owner required');
27
32
  }
33
+ if (!(await admitBusinessTarget(res, ref)))
34
+ return;
28
35
  const body = await readJsonBody(req, deps.maxBody);
29
36
  if (!body.ok)
30
37
  return sendJson(res, body.status, { error: body.error });
31
38
  const parsed = SolutionInstallationCreateRequestSchema.safeParse(body.value);
32
39
  if (!parsed.success)
33
40
  return invalid(res, parsed.error);
34
- const profile = BUILT_IN_SOLUTION_PROFILES[parsed.data.profileId];
41
+ const definition = await resolveInstallDefinition(parsed.data.definition, ref.org, deps.resolvePrivateDefinition);
42
+ if (definition === undefined) {
43
+ return sendJson(res, 404, {
44
+ error: 'solution definition is unavailable',
45
+ code: 'definition_unavailable',
46
+ });
47
+ }
35
48
  const installationId = stableInstallationId(ref.org, parsed.data.appSlug, parsed.data.environment);
36
49
  const result = await deps.store.createInstallation({
37
50
  scope: {
@@ -40,8 +53,10 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
40
53
  env: parsed.data.environment,
41
54
  installationId,
42
55
  },
43
- profileKey: parsed.data.profileId,
44
- managedCollections: profile.collections.map((collection) => collection.key),
56
+ ...(parsed.data.definition.kind === 'managed'
57
+ ? { profileKey: parsed.data.definition.profileId }
58
+ : { definition }),
59
+ managedCollections: definition.collections.map((collection) => collection.key),
45
60
  retentionDays: parsed.data.retentionDays,
46
61
  actorSubject: identity.subject,
47
62
  actorEmail: identity.email,
@@ -56,10 +71,32 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
56
71
  if (grant === undefined || grant.revokedAt !== undefined) {
57
72
  return sendForbidden(res, 'business grant required');
58
73
  }
74
+ if (parsed.data.businessNotice &&
75
+ !(await deps.store.getBusinessNotice(result.installation.scope))) {
76
+ await deps.store.setBusinessNotice({
77
+ scope: result.installation.scope,
78
+ expectedRevision: 0,
79
+ notice: parsed.data.businessNotice,
80
+ actorSubject: identity.subject,
81
+ });
82
+ }
83
+ const activated = await deps.activateInstallation?.({
84
+ installation: result.installation,
85
+ actor: identity,
86
+ });
87
+ if (activated === undefined || !activated.ok) {
88
+ return sendJson(res, activated?.status ?? 503, {
89
+ ok: false,
90
+ code: activated?.code ?? 'installation_activation_unavailable',
91
+ error: activated?.message ??
92
+ 'The installation is saved, but application activation is unavailable. Retry installation when the service is ready.',
93
+ installationId: result.installation.scope.installationId,
94
+ });
95
+ }
59
96
  return sendJson(res, result.disposition === 'created' ? 201 : 200, {
60
97
  ok: true,
61
98
  data: {
62
- installation: installationToWire(result.installation, profile, grant.role),
99
+ installation: installationToWire(result.installation, grant.role),
63
100
  },
64
101
  });
65
102
  }
@@ -72,10 +109,12 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
72
109
  permitted.push({ installation, role: grant.role });
73
110
  }
74
111
  }
112
+ if (permitted.length > 0 && !(await admitBusinessTarget(res, ref)))
113
+ return;
75
114
  return sendJson(res, 200, {
76
115
  ok: true,
77
116
  data: {
78
- installations: permitted.map(({ installation, role }) => installationToWire(installation, BUILT_IN_SOLUTION_PROFILES[installation.profileKey], role)),
117
+ installations: permitted.map(({ installation, role }) => installationToWire(installation, role)),
79
118
  },
80
119
  });
81
120
  }
@@ -86,10 +125,33 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
86
125
  return sendJson(res, 200, {
87
126
  ok: true,
88
127
  data: {
89
- installation: installationToWire(authorized.installation, BUILT_IN_SOLUTION_PROFILES[authorized.installation.profileKey], authorized.grant.role),
128
+ installation: installationToWire(authorized.installation, authorized.grant.role),
90
129
  },
91
130
  });
92
131
  }
132
+ if (req.method === 'PATCH' && ref.installationId !== undefined) {
133
+ const authorized = await requireInstallationPermission(res, ref, identity, 'installation:administer', deps);
134
+ if (authorized === undefined)
135
+ return;
136
+ const body = await readJsonBody(req, deps.maxBody);
137
+ if (!body.ok)
138
+ return sendJson(res, body.status, { error: body.error });
139
+ const parsed = SolutionInstallationIntakeRequestSchema.safeParse(body.value);
140
+ if (!parsed.success)
141
+ return invalid(res, parsed.error);
142
+ const result = await deps.store.setIntakeState({
143
+ scope: authorized.scope,
144
+ expectedRevision: parsed.data.expectedRevision,
145
+ active: parsed.data.active,
146
+ actorSubject: identity.subject,
147
+ });
148
+ if (!result.ok)
149
+ return mutationFailure(res, result);
150
+ return sendJson(res, 200, {
151
+ ok: true,
152
+ data: { installation: installationToWire(result.installation, authorized.grant.role) },
153
+ });
154
+ }
93
155
  return methodNotAllowed(res);
94
156
  }
95
157
  export async function handleBusinessGrants(req, res, ref, deps) {
@@ -101,7 +163,7 @@ export async function handleBusinessGrants(req, res, ref, deps) {
101
163
  return;
102
164
  const { scope } = authorized.installation;
103
165
  if (req.method === 'GET' && ref.subject === undefined) {
104
- const grants = (await deps.store.listGrants(scope)).filter((grant) => grant.revokedAt === undefined);
166
+ const grants = await deps.store.listGrants(scope);
105
167
  return sendJson(res, 200, { ok: true, data: { grants: grants.map(grantToWire) } });
106
168
  }
107
169
  if (req.method === 'POST' && ref.subject === undefined) {
@@ -157,23 +219,27 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
157
219
  const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
158
220
  if (authorized === undefined)
159
221
  return;
160
- if (!collectionEnabled(res, authorized.installation, collection))
222
+ const definition = enabledCollection(res, authorized.installation, collection);
223
+ if (definition === undefined)
161
224
  return;
162
- const activities = await deps.store.listActivity(authorized.installation.scope, collection, ref.recordId);
163
- return sendJson(res, 200, {
164
- ok: true,
165
- data: { activities: activities.map(activityToWire) },
166
- });
225
+ if (definition.authority.authority === 'external') {
226
+ return sendJson(res, 200, { ok: true, data: { activities: [] } });
227
+ }
228
+ return sendNativeRecordActivity(res, url, authorized.installation.scope, collection, ref.recordId, deps.store);
167
229
  }
168
230
  if (ref.action === 'export' && req.method === 'GET') {
169
231
  const authorized = await requireInstallationPermission(res, ref, identity, 'records:export', deps);
170
232
  if (authorized === undefined)
171
233
  return;
172
- if (!collectionEnabled(res, authorized.installation, collection))
234
+ const definition = enabledCollection(res, authorized.installation, collection);
235
+ if (definition === undefined)
173
236
  return;
174
237
  const paging = parsePaging(url, 500);
175
238
  if (!paging.ok)
176
239
  return sendJson(res, 400, { error: paging.error });
240
+ if (definition.authority.authority === 'external') {
241
+ return sendExternalRecordPage(res, authorized.installation, definition, { ...paging.value, limit: paging.value.limit ?? 500 }, deps);
242
+ }
177
243
  const page = await cursorRequest(res, () => deps.store.exportRequests({
178
244
  scope: authorized.installation.scope,
179
245
  collectionKey: collection,
@@ -185,7 +251,10 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
185
251
  return sendJson(res, 200, {
186
252
  ok: true,
187
253
  data: {
188
- records: page.records.map(recordToWire),
254
+ records: page.records.map((record) => ({
255
+ ...recordToWire(record),
256
+ ...(record.content ? { notes: record.content.notes } : {}),
257
+ })),
189
258
  ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),
190
259
  },
191
260
  });
@@ -194,11 +263,23 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
194
263
  const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
195
264
  if (authorized === undefined)
196
265
  return;
197
- if (!collectionEnabled(res, authorized.installation, collection))
266
+ const definition = enabledCollection(res, authorized.installation, collection);
267
+ if (definition === undefined)
198
268
  return;
199
269
  const paging = parsePaging(url, 100);
200
270
  if (!paging.ok)
201
271
  return sendJson(res, 400, { error: paging.error });
272
+ const query = parseNativeRecordQuery(url);
273
+ if (!query.ok)
274
+ return sendJson(res, 400, { error: query.error, code: 'invalid_query' });
275
+ if (definition.authority.authority === 'external') {
276
+ if (Object.keys(query.value).length > 0)
277
+ return sendJson(res, 400, {
278
+ error: 'Field and date queries currently require a native collection.',
279
+ code: 'invalid_query',
280
+ });
281
+ return sendExternalRecordPage(res, authorized.installation, definition, paging.value, deps);
282
+ }
202
283
  const statusValue = url.searchParams.get('status');
203
284
  const status = statusValue === null ? undefined : ManagedRecordStatusSchema.safeParse(statusValue);
204
285
  if (status !== undefined && !status.success)
@@ -208,6 +289,7 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
208
289
  scope: authorized.installation.scope,
209
290
  collectionKey: collection,
210
291
  ...paging.value,
292
+ ...query.value,
211
293
  ...(status === undefined ? {} : { status: status.data }),
212
294
  ...(assigneeSubject === undefined ? {} : { assigneeSubject }),
213
295
  includeDeleted: url.searchParams.get('includeDeleted') === 'true',
@@ -226,8 +308,12 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
226
308
  const authorized = await requireInstallationPermission(res, ref, identity, 'records:create', deps);
227
309
  if (authorized === undefined)
228
310
  return;
229
- if (!collectionEnabled(res, authorized.installation, collection))
311
+ const definition = enabledCollection(res, authorized.installation, collection);
312
+ if (definition === undefined)
230
313
  return;
314
+ if (definition.authority.authority === 'external') {
315
+ return unsupportedExternalOperation(res, 'create');
316
+ }
231
317
  const idempotencyKey = requestIdempotencyKey(req);
232
318
  if (idempotencyKey === undefined) {
233
319
  return sendJson(res, 400, { error: 'Idempotency-Key header is required (1-128 characters)' });
@@ -238,19 +324,25 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
238
324
  const parsed = ManagedRecordCreateRequestSchema.safeParse(body.value);
239
325
  if (!parsed.success)
240
326
  return invalid(res, parsed.error);
241
- const payload = profilePayload(res, authorized.installation, collection, parsed.data.payload);
242
- if (payload === undefined)
243
- return;
244
- const result = await deps.store.createRequest({
245
- scope: authorized.installation.scope,
246
- collectionKey: collection,
327
+ const result = await createNativeRecord(res, deps, {
328
+ installation: authorized.installation,
329
+ collection,
247
330
  idempotencyKey,
248
- payload,
331
+ payload: parsed.data.payload,
249
332
  origin: { kind: 'portal' },
250
333
  actorSubject: identity.subject,
334
+ admit: () => admitBusinessMutation(res, authorized.scope),
251
335
  });
336
+ if (result === undefined)
337
+ return;
252
338
  if (result.disposition === 'conflict')
253
339
  return idempotencyConflict(res);
340
+ if (result.disposition === 'paused') {
341
+ return sendJson(res, 503, {
342
+ error: 'Record creation requires an active application.',
343
+ code: 'application_unavailable',
344
+ });
345
+ }
254
346
  return sendJson(res, result.disposition === 'created' ? 201 : 200, {
255
347
  ok: true,
256
348
  data: { record: recordToWire(result.record) },
@@ -260,12 +352,30 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
260
352
  const authorized = await requireInstallationPermission(res, ref, identity, 'records:read', deps);
261
353
  if (authorized === undefined)
262
354
  return;
263
- if (!collectionEnabled(res, authorized.installation, collection))
355
+ const definition = enabledCollection(res, authorized.installation, collection);
356
+ if (definition === undefined)
264
357
  return;
358
+ if (definition.authority.authority === 'external') {
359
+ const loaded = await loadExternalRecord(authorized.installation, definition, ref.recordId, deps);
360
+ if (loaded === undefined)
361
+ return sendJson(res, 503, { error: 'collection source unavailable' });
362
+ if (loaded.record === undefined)
363
+ return sendJson(res, 404, { error: 'record not found' });
364
+ return sendJson(res, 200, {
365
+ ok: true,
366
+ data: {
367
+ record: externalRecordToWire(loaded.record, loaded.binding),
368
+ collection: collectionToWire(definition),
369
+ },
370
+ });
371
+ }
265
372
  const record = await deps.store.getRequest(authorized.installation.scope, collection, ref.recordId);
266
373
  if (record === undefined)
267
374
  return sendJson(res, 404, { error: 'record not found' });
268
- return sendJson(res, 200, { ok: true, data: { record: recordToWire(record) } });
375
+ return sendJson(res, 200, {
376
+ ok: true,
377
+ data: recordDetailToWire(authorized.installation, record),
378
+ });
269
379
  }
270
380
  if (ref.recordId !== undefined && req.method === 'PATCH') {
271
381
  const body = await readJsonBody(req, deps.maxBody);
@@ -278,20 +388,31 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
278
388
  const authorized = await requireInstallationPermission(res, ref, identity, permission, deps);
279
389
  if (authorized === undefined)
280
390
  return;
281
- if (!collectionEnabled(res, authorized.installation, collection))
391
+ const definition = enabledCollection(res, authorized.installation, collection);
392
+ if (definition === undefined)
282
393
  return;
394
+ if (definition.authority.authority === 'external') {
395
+ return unsupportedExternalOperation(res, parsed.data.operation);
396
+ }
397
+ if (parsed.data.operation === 'migrate-schema') {
398
+ const result = await deps.store.migrateLegacyRequest({
399
+ scope: authorized.installation.scope,
400
+ collectionKey: collection,
401
+ id: ref.recordId,
402
+ expectedRevision: parsed.data.expectedRevision,
403
+ actorSubject: identity.subject,
404
+ });
405
+ if (!result.ok)
406
+ return mutationFailure(res, result);
407
+ return sendJson(res, 200, { ok: true, data: { record: recordToWire(result.record) } });
408
+ }
283
409
  let operation;
284
410
  if (parsed.data.operation === 'update') {
285
- const current = await deps.store.getRequest(authorized.installation.scope, collection, ref.recordId);
286
- if (current?.content === undefined)
287
- return sendJson(res, 404, { error: 'record not found' });
288
- const payload = profilePayload(res, authorized.installation, collection, {
289
- ...current.content.payload,
290
- ...parsed.data.patch,
291
- });
292
- if (payload === undefined)
293
- return;
294
- operation = { kind: 'update', payload };
411
+ operation = {
412
+ kind: 'update',
413
+ payload: parsed.data.patch,
414
+ ...(parsed.data.unset ? { unset: parsed.data.unset } : {}),
415
+ };
295
416
  }
296
417
  else if (parsed.data.operation === 'assign') {
297
418
  if (parsed.data.assigneeSubject !== null) {
@@ -316,14 +437,23 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
316
437
  else {
317
438
  operation = { kind: 'add_note', note: parsed.data.note };
318
439
  }
319
- const result = await deps.store.mutateRequest({
320
- scope: authorized.installation.scope,
321
- collectionKey: collection,
322
- id: ref.recordId,
323
- expectedRevision: parsed.data.expectedRevision,
324
- actorSubject: identity.subject,
325
- operation,
326
- });
440
+ let result;
441
+ try {
442
+ result = await deps.store.mutateRequest({
443
+ scope: authorized.installation.scope,
444
+ collectionKey: collection,
445
+ id: ref.recordId,
446
+ expectedRevision: parsed.data.expectedRevision,
447
+ actorSubject: identity.subject,
448
+ operation,
449
+ });
450
+ }
451
+ catch (error) {
452
+ if (error instanceof PayloadValidationError) {
453
+ return sendJson(res, 400, { error: error.message, code: error.code });
454
+ }
455
+ throw error;
456
+ }
327
457
  if (!result.ok)
328
458
  return mutationFailure(res, result);
329
459
  return sendJson(res, 200, { ok: true, data: { record: recordToWire(result.record) } });
@@ -332,7 +462,8 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
332
462
  const authorized = await requireInstallationPermission(res, ref, identity, 'records:delete', deps);
333
463
  if (authorized === undefined)
334
464
  return;
335
- if (!collectionEnabled(res, authorized.installation, collection))
465
+ const definition = enabledCollection(res, authorized.installation, collection);
466
+ if (definition === undefined)
336
467
  return;
337
468
  const body = await readJsonBody(req, deps.maxBody);
338
469
  if (!body.ok)
@@ -341,6 +472,37 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
341
472
  if (revision === undefined) {
342
473
  return sendJson(res, 400, { error: 'expectedRevision must be a positive integer' });
343
474
  }
475
+ if (definition.authority.authority === 'external') {
476
+ const loaded = await loadExternalRecord(authorized.installation, definition, ref.recordId, deps);
477
+ if (loaded === undefined)
478
+ return sendJson(res, 503, { error: 'collection source unavailable' });
479
+ if (loaded.record === undefined)
480
+ return sendJson(res, 404, { error: 'record not found' });
481
+ const { record } = loaded;
482
+ if (record.revision !== revision) {
483
+ return sendJson(res, 409, {
484
+ error: 'record revision conflict',
485
+ code: 'revision_conflict',
486
+ currentRevision: record.revision,
487
+ });
488
+ }
489
+ await deps.sourceStore?.suppressExternalRecord({
490
+ ...sourceBindingKey(authorized.installation, definition),
491
+ sourceId: record.source.id,
492
+ reason: 'customer_request',
493
+ now: now(deps),
494
+ });
495
+ const deletedAt = now(deps).toISOString();
496
+ return sendJson(res, 200, {
497
+ ok: true,
498
+ data: {
499
+ recordId: record.id,
500
+ authority: 'external',
501
+ disposition: 'suppressed',
502
+ deletedAt,
503
+ },
504
+ });
505
+ }
344
506
  const result = await deps.store.deleteRequest({
345
507
  scope: authorized.installation.scope,
346
508
  collectionKey: collection,
@@ -351,72 +513,22 @@ export async function handleManagedRecords(req, res, url, ref, deps) {
351
513
  });
352
514
  if (!result.ok)
353
515
  return mutationFailure(res, result);
354
- return sendJson(res, 200, {
355
- ok: true,
356
- data: { recordId: result.record.id, deletedAt: result.record.deletedAt },
357
- });
358
- }
359
- return methodNotAllowed(res);
360
- }
361
- export async function handlePublicSolutionIntake(req, res, ref, deps) {
362
- const installation = await deps.store.resolveInstallationByPublicId(ref.publicId);
363
- if (installation === undefined)
364
- return sendJson(res, 404, { error: 'solution not found' });
365
- const profile = BUILT_IN_SOLUTION_PROFILES[installation.profileKey];
366
- if (req.method === 'GET' && ref.collection === undefined) {
367
- const wire = profileToWire(profile);
368
516
  return sendJson(res, 200, {
369
517
  ok: true,
370
518
  data: {
371
- publicId: installation.publicId,
372
- title: wire.title,
373
- description: wire.description,
374
- collection: wire.collection,
519
+ recordId: result.record.id,
520
+ authority: 'native',
521
+ disposition: 'deleted',
522
+ deletedAt: result.record.deletedAt,
375
523
  },
376
524
  });
377
525
  }
378
- if (req.method === 'POST' && ref.collection !== undefined) {
379
- if (!collectionEnabled(res, installation, ref.collection))
380
- return;
381
- const quota = await consumePublicIntakeQuota(req, ref.publicId, deps);
382
- if (!quota.allowed) {
383
- res.setHeader('retry-after', String(Math.max(1, Math.ceil((quota.resetAt.getTime() - now(deps).getTime()) / 1000))));
384
- return sendJson(res, 429, { error: 'public intake limit exceeded', code: 'quota_exceeded' });
385
- }
386
- const idempotencyKey = requestIdempotencyKey(req);
387
- if (idempotencyKey === undefined) {
388
- return sendJson(res, 400, { error: 'Idempotency-Key header is required (1-128 characters)' });
389
- }
390
- const body = await readJsonBody(req, deps.maxBody);
391
- if (!body.ok)
392
- return sendJson(res, body.status, { error: body.error });
393
- const parsed = ManagedRecordCreateRequestSchema.safeParse(body.value);
394
- if (!parsed.success)
395
- return invalid(res, parsed.error);
396
- const payload = profilePayload(res, installation, ref.collection, parsed.data.payload);
397
- if (payload === undefined)
398
- return;
399
- const result = await deps.store.createRequest({
400
- scope: installation.scope,
401
- collectionKey: ref.collection,
402
- idempotencyKey,
403
- payload,
404
- origin: { kind: 'embedded', reference: 'public-intake' },
405
- actorSubject: 'anonymous',
406
- });
407
- if (result.disposition === 'conflict')
408
- return idempotencyConflict(res);
409
- return sendJson(res, result.disposition === 'created' ? 201 : 200, {
410
- ok: true,
411
- data: { recordId: result.record.id, receivedAt: result.record.createdAt },
412
- });
413
- }
414
526
  return methodNotAllowed(res);
415
527
  }
416
- async function requireIdentity(req, res, deps) {
417
- return authorizeControlPlane(req, res, deps.gate, { requireIdentity: true });
528
+ export async function requireIdentity(req, res, deps) {
529
+ return authorizeBusinessApi(req, res, deps);
418
530
  }
419
- async function requireInstallationGrant(res, ref, identity, deps) {
531
+ export async function requireInstallationGrant(res, ref, identity, deps, permission) {
420
532
  if (ref.installationId === undefined)
421
533
  return undefined;
422
534
  const installation = await deps.store.getInstallationById(ref.org, ref.installationId);
@@ -429,59 +541,21 @@ async function requireInstallationGrant(res, ref, identity, deps) {
429
541
  sendForbidden(res, 'business grant required');
430
542
  return undefined;
431
543
  }
432
- return { installation, scope: installation.scope, grant };
433
- }
434
- async function requireInstallationPermission(res, ref, identity, permission, deps) {
435
- const authorized = await requireInstallationGrant(res, ref, identity, deps);
436
- if (authorized === undefined)
437
- return undefined;
438
- if (!businessGrantAllows(authorized.grant, permission)) {
544
+ if (permission && !businessGrantAllows(grant, permission)) {
439
545
  sendForbidden(res, `business permission required: ${permission}`);
440
546
  return undefined;
441
547
  }
442
- return authorized;
443
- }
444
- function stableInstallationId(org, app, env) {
445
- return `ins-${createHash('sha256').update(`${org}\0${app}\0${env}`).digest('hex').slice(0, 24)}`;
446
- }
447
- function requestIdempotencyKey(req) {
448
- const value = req.headers['idempotency-key'];
449
- if (typeof value !== 'string' || value.length < 1 || value.length > 128)
548
+ if (!(await admitBusinessTarget(res, installation.scope)))
450
549
  return undefined;
451
- return value;
452
- }
453
- function expectedRevision(value) {
454
- if (value === null || typeof value !== 'object')
455
- return undefined;
456
- const revision = value.expectedRevision;
457
- return typeof revision === 'number' && Number.isInteger(revision) && revision > 0
458
- ? revision
459
- : undefined;
460
- }
461
- function parsePaging(url, maximum) {
462
- const cursor = url.searchParams.get('cursor') ?? undefined;
463
- const rawLimit = url.searchParams.get('limit');
464
- if (rawLimit === null)
465
- return { ok: true, value: cursor === undefined ? {} : { cursor } };
466
- const limit = Number(rawLimit);
467
- if (!Number.isInteger(limit) || limit < 1 || limit > maximum) {
468
- return { ok: false, error: `limit must be an integer from 1 to ${maximum}` };
469
- }
470
- return { ok: true, value: { ...(cursor === undefined ? {} : { cursor }), limit } };
550
+ return { installation, scope: installation.scope, grant };
471
551
  }
472
- function mutationPermission(operation) {
473
- if (operation === 'assign')
474
- return 'records:assign';
475
- if (operation === 'set-status')
476
- return 'records:status';
477
- if (operation === 'add-note')
478
- return 'records:note';
479
- return 'records:update';
552
+ export async function requireInstallationPermission(res, ref, identity, permission, deps) {
553
+ return requireInstallationGrant(res, ref, identity, deps, permission);
480
554
  }
481
- function mutationFailure(res, result) {
555
+ export function mutationFailure(res, result) {
482
556
  const status = result.reason === 'not_found'
483
557
  ? 404
484
- : result.reason === 'conflict' || result.reason === 'last_administrator'
558
+ : ['conflict', 'last_administrator', 'application_unavailable'].includes(result.reason)
485
559
  ? 409
486
560
  : 422;
487
561
  sendJson(res, status, {
@@ -490,62 +564,29 @@ function mutationFailure(res, result) {
490
564
  currentRevision: result.currentRevision,
491
565
  });
492
566
  }
493
- function collectionEnabled(res, installation, collection) {
494
- if (installation.managedCollections.includes(collection))
495
- return true;
496
- sendJson(res, 404, { error: 'collection not found' });
497
- return false;
498
- }
499
- function profilePayload(res, installation, collection, value) {
500
- try {
501
- return validateProfilePayload(installation.profileKey, collection, value);
502
- }
503
- catch (error) {
504
- if (!(error instanceof PayloadValidationError))
505
- throw error;
506
- sendJson(res, 400, { error: error.message, code: error.code });
507
- return undefined;
508
- }
509
- }
510
- async function cursorRequest(res, request) {
567
+ export function enabledCollection(res, installation, collection) {
511
568
  try {
512
- return await request();
569
+ return validateCollectionEnabled(installation, collection);
513
570
  }
514
- catch (error) {
515
- if (!(error instanceof CursorValidationError))
516
- throw error;
517
- sendJson(res, 400, { error: 'cursor is invalid', code: 'invalid_cursor' });
571
+ catch {
572
+ sendJson(res, 404, { error: 'collection not found' });
518
573
  return undefined;
519
574
  }
520
575
  }
521
- async function consumePublicIntakeQuota(req, publicId, deps) {
522
- const timestamp = now(deps);
523
- const address = deps.trustProxy
524
- ? typeof req.headers['x-forwarded-for'] === 'string'
525
- ? req.headers['x-forwarded-for']
526
- : undefined
527
- : req.socket.remoteAddress;
528
- const bucket = clientAddressBucket(address);
529
- if (bucket !== undefined) {
530
- const addressOutcome = await deps.publicCounters.consume({ key: `solution-intake:address:${publicId}:${bucket}`, limit: 60, window: 'hour' }, timestamp);
531
- if (!addressOutcome.allowed)
532
- return addressOutcome;
533
- }
534
- return deps.publicCounters.consume({ key: `solution-intake:surface:${publicId}`, limit: 10_000, window: 'day' }, timestamp);
535
- }
536
- function now(deps) {
576
+ export function now(deps) {
537
577
  return deps.now?.() ?? new Date();
538
578
  }
539
- function invalid(res, error) {
579
+ export function invalid(res, error) {
540
580
  sendJson(res, 400, { error: formatWireError(error) });
541
581
  }
542
- function idempotencyConflict(res) {
582
+ export function idempotencyConflict(res) {
543
583
  sendJson(res, 409, {
544
584
  error: 'the idempotency key was already used with different content',
545
585
  code: 'idempotency_conflict',
546
586
  });
547
587
  }
548
- function methodNotAllowed(res) {
588
+ export function methodNotAllowed(res) {
549
589
  sendJson(res, 405, { error: 'method not allowed' });
550
590
  }
591
+ export { createNativeRecord } from './business-information-record-create.js';
551
592
  //# sourceMappingURL=business-information.js.map
@@ -25,7 +25,7 @@ export function dispatchConfigValueRequest(req, res, url, deps) {
25
25
  deps.applySecurityHeaders(res, deps.tls);
26
26
  if (deps.enforceHttps(req, res, deps.tls))
27
27
  return true;
28
- handleConfigValues(req, res, deps.gate, deps.controlPlane, deps.configStore, deps.registry, deps.maxBody, ref, deps.audit, deps.developerGrants).catch(() => {
28
+ handleConfigValues(req, res, deps.gate, deps.controlPlane, deps.configStore, deps.registry, deps.maxBody, ref, deps.audit, deps.developerGrants, deps.installations).catch(() => {
29
29
  if (!res.headersSent)
30
30
  deps.sendJson(res, 500, { error: 'internal error' });
31
31
  });