@tokenoftrust/storefront-runner 2.0.2 → 2.0.4

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 (254) hide show
  1. package/apps/storefront/.astro/content.d.ts +159 -0
  2. package/apps/storefront/.astro/integrations/_astrojs_cloudflare/cloudflare.d.ts +1 -0
  3. package/apps/storefront/.astro/types.d.ts +3 -0
  4. package/apps/storefront/node_modules/.bin/acorn +43 -0
  5. package/apps/storefront/node_modules/.bin/astro +43 -0
  6. package/apps/storefront/node_modules/.bin/astro-check +43 -0
  7. package/apps/storefront/node_modules/.bin/browserslist +43 -0
  8. package/apps/storefront/node_modules/.bin/cf-wrangler +43 -0
  9. package/apps/storefront/node_modules/.bin/depcruise +43 -0
  10. package/apps/storefront/node_modules/.bin/depcruise-baseline +43 -0
  11. package/apps/storefront/node_modules/.bin/depcruise-fmt +43 -0
  12. package/apps/storefront/node_modules/.bin/depcruise-wrap-stream-in-html +43 -0
  13. package/apps/storefront/node_modules/.bin/dependency-cruise +43 -0
  14. package/apps/storefront/node_modules/.bin/dependency-cruiser +43 -0
  15. package/apps/storefront/node_modules/.bin/drizzle-kit +43 -0
  16. package/apps/storefront/node_modules/.bin/esbuild +43 -0
  17. package/apps/storefront/node_modules/.bin/jiti +43 -0
  18. package/apps/storefront/node_modules/.bin/playwright +43 -0
  19. package/apps/storefront/node_modules/.bin/playwright-core +43 -0
  20. package/apps/storefront/node_modules/.bin/prettier +43 -0
  21. package/apps/storefront/node_modules/.bin/rollup +43 -0
  22. package/apps/storefront/node_modules/.bin/tsc +43 -0
  23. package/apps/storefront/node_modules/.bin/tsserver +43 -0
  24. package/apps/storefront/node_modules/.bin/tsx +43 -0
  25. package/apps/storefront/node_modules/.bin/vite +43 -0
  26. package/apps/storefront/node_modules/.bin/vitest +43 -0
  27. package/apps/storefront/node_modules/.bin/workerd +43 -0
  28. package/apps/storefront/node_modules/.bin/wrangler +43 -0
  29. package/apps/storefront/node_modules/.bin/wrangler2 +43 -0
  30. package/apps/storefront/node_modules/.bin/yaml +43 -0
  31. package/apps/storefront/node_modules/.vite/deps/@astrojs_preact_client__js.js +58 -0
  32. package/apps/storefront/node_modules/.vite/deps/@astrojs_preact_client__js.js.map +1 -0
  33. package/apps/storefront/node_modules/.vite/deps/@astrojs_preact_n_@preact_signals.js +741 -0
  34. package/apps/storefront/node_modules/.vite/deps/@astrojs_preact_n_@preact_signals.js.map +1 -0
  35. package/apps/storefront/node_modules/.vite/deps/@astrojs_preact_server__js.js +2549 -0
  36. package/apps/storefront/node_modules/.vite/deps/@astrojs_preact_server__js.js.map +1 -0
  37. package/apps/storefront/node_modules/.vite/deps/_metadata.json +150 -0
  38. package/apps/storefront/node_modules/.vite/deps/astro-BIHuWFxm.js +434 -0
  39. package/apps/storefront/node_modules/.vite/deps/astro-BIHuWFxm.js.map +1 -0
  40. package/apps/storefront/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
  41. package/apps/storefront/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  42. package/apps/storefront/node_modules/.vite/deps/astro_n_axobject-query.js +2705 -0
  43. package/apps/storefront/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  44. package/apps/storefront/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
  45. package/apps/storefront/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  46. package/apps/storefront/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
  47. package/apps/storefront/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  48. package/apps/storefront/node_modules/.vite/deps/audit-DKDpcdEI.js +1535 -0
  49. package/apps/storefront/node_modules/.vite/deps/audit-DKDpcdEI.js.map +1 -0
  50. package/apps/storefront/node_modules/.vite/deps/highlight-B9UoX1wa.js +48 -0
  51. package/apps/storefront/node_modules/.vite/deps/highlight-B9UoX1wa.js.map +1 -0
  52. package/apps/storefront/node_modules/.vite/deps/icons-BWi2wI9n.js +42 -0
  53. package/apps/storefront/node_modules/.vite/deps/icons-BWi2wI9n.js.map +1 -0
  54. package/apps/storefront/node_modules/.vite/deps/package.json +3 -0
  55. package/apps/storefront/node_modules/.vite/deps/preact.js +310 -0
  56. package/apps/storefront/node_modules/.vite/deps/preact.js.map +1 -0
  57. package/apps/storefront/node_modules/.vite/deps/preact_compat.js +420 -0
  58. package/apps/storefront/node_modules/.vite/deps/preact_compat.js.map +1 -0
  59. package/apps/storefront/node_modules/.vite/deps/preact_compat_jsx-runtime.js +4 -0
  60. package/apps/storefront/node_modules/.vite/deps/preact_debug.js +236 -0
  61. package/apps/storefront/node_modules/.vite/deps/preact_debug.js.map +1 -0
  62. package/apps/storefront/node_modules/.vite/deps/preact_devtools.js +12 -0
  63. package/apps/storefront/node_modules/.vite/deps/preact_devtools.js.map +1 -0
  64. package/apps/storefront/node_modules/.vite/deps/preact_hooks.js +192 -0
  65. package/apps/storefront/node_modules/.vite/deps/preact_hooks.js.map +1 -0
  66. package/apps/storefront/node_modules/.vite/deps/preact_jsx-dev-runtime.js +3 -0
  67. package/apps/storefront/node_modules/.vite/deps/preact_jsx-runtime.js +92 -0
  68. package/apps/storefront/node_modules/.vite/deps/preact_jsx-runtime.js.map +1 -0
  69. package/apps/storefront/node_modules/.vite/deps/preact_test-utils.js +59 -0
  70. package/apps/storefront/node_modules/.vite/deps/preact_test-utils.js.map +1 -0
  71. package/apps/storefront/node_modules/.vite/deps/rolldown-runtime-BPOCksWG.js +24 -0
  72. package/apps/storefront/node_modules/.vite/deps/settings-BVDV0Roj.js +189 -0
  73. package/apps/storefront/node_modules/.vite/deps/settings-BVDV0Roj.js.map +1 -0
  74. package/apps/storefront/node_modules/.vite/deps/static-html-DveYqwMo.js +13 -0
  75. package/apps/storefront/node_modules/.vite/deps/static-html-DveYqwMo.js.map +1 -0
  76. package/apps/storefront/node_modules/.vite/deps/toolbar-B3VIHCXg.js +458 -0
  77. package/apps/storefront/node_modules/.vite/deps/toolbar-B3VIHCXg.js.map +1 -0
  78. package/apps/storefront/node_modules/.vite/deps/ui-library-BK6ricUd.js +1016 -0
  79. package/apps/storefront/node_modules/.vite/deps/ui-library-BK6ricUd.js.map +1 -0
  80. package/apps/storefront/node_modules/.vite/deps/window-BvxDenKN.js +32 -0
  81. package/apps/storefront/node_modules/.vite/deps/window-BvxDenKN.js.map +1 -0
  82. package/apps/storefront/node_modules/.vite/deps/xray-YFiRUU0Z.js +113 -0
  83. package/apps/storefront/node_modules/.vite/deps/xray-YFiRUU0Z.js.map +1 -0
  84. package/apps/storefront/node_modules/.vite/deps_ssr/_metadata.json +8 -0
  85. package/apps/storefront/node_modules/.vite/deps_ssr/package.json +3 -0
  86. package/apps/storefront/src/layouts/Layout.astro +1 -1
  87. package/apps/storefront/src/lib/apps/registryAccess.ts +45 -0
  88. package/apps/storefront/src/lib/auth/adminEntry.ts +4 -4
  89. package/apps/storefront/src/lib/shared/capability.ts +68 -0
  90. package/apps/storefront/src/lib/shared/developerInvites.ts +1250 -0
  91. package/apps/storefront/src/lib/shared/invitePreflight.ts +123 -0
  92. package/apps/storefront/src/lib/webhooks/deliveryEngine.ts +38 -4
  93. package/apps/storefront/src/lib/webhooks/emit.ts +1 -1
  94. package/apps/storefront/src/lib/webhooks/getDispatcher.ts +1 -1
  95. package/apps/storefront/src/pages/api/auth/magic-exchange.ts +1 -1
  96. package/apps/storefront/src/pages/index.astro +1 -1
  97. package/apps/storefront/src/pages/products/[handle].astro +1 -1
  98. package/package.json +1 -1
  99. package/packages/public-runtime/node_modules/.bin/tsc +43 -0
  100. package/packages/public-runtime/node_modules/.bin/tsserver +43 -0
  101. package/packages/public-runtime/node_modules/.bin/vitest +43 -0
  102. package/pnpm-workspace.yaml +3 -0
  103. package/scripts/lib/tenant-dirs.mjs +80 -0
  104. package/scripts/tenant/lint-embeds.mjs +180 -0
  105. package/scripts/tenant/materialize-tenant-content.mjs +533 -0
  106. package/scripts/tenant/validate.mjs +837 -0
  107. package/apps/storefront/scripts/build-v84-clean-clone-standalone.mjs +0 -68
  108. package/apps/storefront/scripts/deny-v84-clean-clone-standalone-capabilities.mjs +0 -111
  109. package/apps/storefront/scripts/deny-v84-dogfood-capabilities.mjs +0 -2
  110. package/apps/storefront/scripts/deny-v84-lifecycle-capabilities.mjs +0 -247
  111. package/apps/storefront/scripts/dogfood-v84-nonportable-routes.ts +0 -73
  112. package/apps/storefront/scripts/fixed-v84-native-install-producer.ts +0 -79
  113. package/apps/storefront/scripts/generated/v84-clean-clone-replay.bundle.mjs +0 -10982
  114. package/apps/storefront/scripts/import-v84-through-ws2.ts +0 -38
  115. package/apps/storefront/scripts/initialize-v84-lifecycle-tooling-dependency.ts +0 -2
  116. package/apps/storefront/scripts/initialize-v84-lifecycle-tooling.ts +0 -4
  117. package/apps/storefront/scripts/install-v84-native-through-ws1.ts +0 -185
  118. package/apps/storefront/scripts/prove-clone-isolation.ts +0 -506
  119. package/apps/storefront/scripts/replay-v84-clean-clone-pass.ts +0 -148
  120. package/apps/storefront/scripts/replay-v84-clean-clone-standalone.ts +0 -35
  121. package/apps/storefront/scripts/replay-v84-clean-clone.ts +0 -214
  122. package/apps/storefront/scripts/run-fixed-v84-native-install-producer.mjs +0 -18
  123. package/apps/storefront/scripts/run-v84-clone-isolation-proof.mjs +0 -18
  124. package/apps/storefront/scripts/run-v84-clone-lifecycle-proof.mjs +0 -18
  125. package/apps/storefront/scripts/run-v84-import-through-ws2-proof.mjs +0 -17
  126. package/apps/storefront/scripts/run-v84-nonportable-route-dogfood.mjs +0 -15
  127. package/apps/storefront/scripts/sanitize-v84-proof-environment.mjs +0 -21
  128. package/apps/storefront/scripts/v84CleanCloneGraphPin.ts +0 -42
  129. package/apps/storefront/scripts/v84CleanCloneSourceGraph.ts +0 -145
  130. package/apps/storefront/scripts/validate-v84-clone-lifecycle.ts +0 -18
  131. package/apps/storefront/src/components/admin/AdminAIWorkflowsTab.astro +0 -531
  132. package/apps/storefront/src/components/admin/AdminBlogDetailRail.astro +0 -878
  133. package/apps/storefront/src/components/admin/AdminBlogTab.astro +0 -1435
  134. package/apps/storefront/src/components/admin/AdminCheckoutSettingsPanel.astro +0 -226
  135. package/apps/storefront/src/components/admin/AdminCustomersTab.astro +0 -593
  136. package/apps/storefront/src/components/admin/AdminFulfillmentTab.astro +0 -465
  137. package/apps/storefront/src/components/admin/AdminIntegrationsTab.astro +0 -105
  138. package/apps/storefront/src/components/admin/AdminProductsTab.astro +0 -901
  139. package/apps/storefront/src/components/admin/AdminPublishTab.astro +0 -2983
  140. package/apps/storefront/src/components/admin/AdminReportingTab.astro +0 -435
  141. package/apps/storefront/src/components/admin/AdminSettingsTab.astro +0 -782
  142. package/apps/storefront/src/components/admin/AdminSubscriptionsTab.astro +0 -611
  143. package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +0 -1223
  144. package/apps/storefront/src/lib/apps/adminService.ts +0 -116
  145. package/apps/storefront/src/lib/apps/adminSession.ts +0 -214
  146. package/apps/storefront/src/lib/apps/apiAuth.ts +0 -91
  147. package/apps/storefront/src/lib/apps/apiRoute.ts +0 -35
  148. package/apps/storefront/src/lib/apps/catalogMapper.ts +0 -39
  149. package/apps/storefront/src/lib/apps/consentConfigStore.ts +0 -228
  150. package/apps/storefront/src/lib/apps/gtmMigrationInstall.ts +0 -447
  151. package/apps/storefront/src/lib/apps/gtmMigrationReport.ts +0 -367
  152. package/apps/storefront/src/lib/apps/gtmMigrationTab.ts +0 -315
  153. package/apps/storefront/src/lib/apps/healthAggregate.ts +0 -66
  154. package/apps/storefront/src/lib/apps/integrationLifecycle.ts +0 -614
  155. package/apps/storefront/src/lib/apps/integrationLifecycleController.ts +0 -125
  156. package/apps/storefront/src/lib/apps/integrationReadModel.ts +0 -563
  157. package/apps/storefront/src/lib/apps/integrationsTab.ts +0 -547
  158. package/apps/storefront/src/lib/apps/integrationsView.ts +0 -106
  159. package/apps/storefront/src/lib/apps/managedAnalyticsService.ts +0 -599
  160. package/apps/storefront/src/lib/apps/tenantIntegrationMaterialization.ts +0 -170
  161. package/apps/storefront/src/lib/apps/tokenIssuer.ts +0 -121
  162. package/apps/storefront/src/lib/apps/tokenVerifier.ts +0 -148
  163. package/apps/storefront/src/lib/apps/v84CleanCloneReplayContext.ts +0 -16
  164. package/apps/storefront/src/lib/apps/v84CloneLifecycleCacheEvidence.ts +0 -105
  165. package/apps/storefront/src/lib/apps/v84CloneLifecycleEvidence.ts +0 -177
  166. package/apps/storefront/src/lib/apps/v84CloneLifecycleMaterialization.ts +0 -251
  167. package/apps/storefront/src/lib/apps/v84CloneLifecycleSemantics.ts +0 -241
  168. package/apps/storefront/src/lib/apps/v84CloneMigrationEvidence.ts +0 -211
  169. package/apps/storefront/src/lib/apps/v84CloneNativeInstallEvidence.ts +0 -409
  170. package/apps/storefront/src/lib/apps/v84NonportableCodeCoaching.ts +0 -368
  171. package/apps/storefront/src/lib/apps/v84NonportableRouteContract.ts +0 -188
  172. package/apps/storefront/src/lib/apps/v84NonportableRouteDogfood.ts +0 -291
  173. package/apps/storefront/src/lib/apps/ws1ManagedAnalyticsClient.ts +0 -95
  174. package/apps/storefront/src/lib/content-edit/applyDiff.ts +0 -91
  175. package/apps/storefront/src/lib/content-edit/client.ts +0 -286
  176. package/apps/storefront/src/lib/content-edit/index.ts +0 -14
  177. package/apps/storefront/src/lib/content-edit/route.ts +0 -25
  178. package/apps/storefront/src/lib/content-edit/types.ts +0 -19
  179. package/apps/storefront/src/lib/dev/cockpitStore.ts +0 -57
  180. package/apps/storefront/src/lib/publish/adminPublishTab.ts +0 -4625
  181. package/apps/storefront/src/lib/publish/apex-readiness.ts +0 -360
  182. package/apps/storefront/src/lib/publish/buildStream.ts +0 -269
  183. package/apps/storefront/src/lib/publish/collapsePersistence.ts +0 -72
  184. package/apps/storefront/src/lib/publish/dispatchHealth.ts +0 -267
  185. package/apps/storefront/src/lib/publish/domainState.ts +0 -360
  186. package/apps/storefront/src/lib/publish/lifecycleState.ts +0 -369
  187. package/apps/storefront/src/lib/publish/liveReleaseSummary.ts +0 -29
  188. package/apps/storefront/src/lib/publish/mergeDoctorOnFailure.ts +0 -78
  189. package/apps/storefront/src/lib/publish/mergeHealthBanner.ts +0 -62
  190. package/apps/storefront/src/lib/publish/mergeRowFindings.ts +0 -124
  191. package/apps/storefront/src/lib/publish/mergeSupportEscalation.ts +0 -75
  192. package/apps/storefront/src/lib/publish/panelPolling.ts +0 -78
  193. package/apps/storefront/src/lib/publish/publish-guard.ts +0 -88
  194. package/apps/storefront/src/lib/publish/publishFormat.ts +0 -165
  195. package/apps/storefront/src/lib/publish/publishHero.ts +0 -177
  196. package/apps/storefront/src/lib/publish/reviewRelease/changeState.ts +0 -66
  197. package/apps/storefront/src/lib/publish/reviewRelease/copy.ts +0 -141
  198. package/apps/storefront/src/lib/publish/reviewRelease/index.ts +0 -41
  199. package/apps/storefront/src/lib/publish/reviewRelease/permissions.ts +0 -47
  200. package/apps/storefront/src/lib/publish/reviewRelease/releaseState.ts +0 -42
  201. package/apps/storefront/src/lib/publish/reviewRelease/types.ts +0 -59
  202. package/apps/storefront/src/lib/publish/reviewRelease/viewModel.ts +0 -440
  203. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/actions.ts +0 -161
  204. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/controller.ts +0 -325
  205. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/render.ts +0 -241
  206. package/apps/storefront/src/lib/publish/shipWorkspace.ts +0 -439
  207. package/apps/storefront/src/lib/publish/sseRoute.ts +0 -119
  208. package/apps/storefront/src/lib/publish/stageBundleUpload.ts +0 -215
  209. package/apps/storefront/src/lib/publish/streamLogConsole.ts +0 -142
  210. package/apps/storefront/src/lib/publish/versionNumber.ts +0 -52
  211. package/apps/storefront/src/pages/admin/ops-timeline.astro +0 -420
  212. package/apps/storefront/src/pages/admin/review-release.astro +0 -265
  213. package/apps/storefront/src/pages/admin/select.astro +0 -96
  214. package/apps/storefront/src/pages/admin.astro +0 -570
  215. package/apps/storefront/src/pages/api/apps/admin/credentials/rotate.ts +0 -86
  216. package/apps/storefront/src/pages/api/apps/admin/gtm-migration-install.ts +0 -174
  217. package/apps/storefront/src/pages/api/apps/admin/gtm-migration.ts +0 -96
  218. package/apps/storefront/src/pages/api/apps/admin/health.ts +0 -44
  219. package/apps/storefront/src/pages/api/apps/admin/install.ts +0 -125
  220. package/apps/storefront/src/pages/api/apps/admin/integration-lifecycle.ts +0 -118
  221. package/apps/storefront/src/pages/api/apps/admin/integrations.ts +0 -89
  222. package/apps/storefront/src/pages/api/apps/admin/list.ts +0 -26
  223. package/apps/storefront/src/pages/api/apps/admin/platform-adapters.ts +0 -85
  224. package/apps/storefront/src/pages/api/apps/admin/resume.ts +0 -79
  225. package/apps/storefront/src/pages/api/apps/admin/suspend.ts +0 -80
  226. package/apps/storefront/src/pages/api/apps/admin/uninstall.ts +0 -98
  227. package/apps/storefront/src/pages/api/apps/admin/update.ts +0 -126
  228. package/apps/storefront/src/pages/api/apps/admin/webhooks/deliveries/[deliveryId]/replay.ts +0 -70
  229. package/apps/storefront/src/pages/api/apps/admin/webhooks/deliveries.ts +0 -51
  230. package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +0 -255
  231. package/apps/storefront/src/pages/api/apps/oauth/token.ts +0 -87
  232. package/apps/storefront/src/pages/api/apps/v1/attribution.ts +0 -162
  233. package/apps/storefront/src/pages/api/apps/v1/catalog/products/[handle].ts +0 -39
  234. package/apps/storefront/src/pages/api/apps/v1/catalog/products.ts +0 -49
  235. package/apps/storefront/src/pages/api/apps/v1/health.ts +0 -32
  236. package/apps/storefront/src/pages/api/apps/v1/inventory.ts +0 -59
  237. package/apps/storefront/src/pages/api/apps/v1/orders/[id].ts +0 -48
  238. package/apps/storefront/src/pages/api/apps/v1/orders.ts +0 -73
  239. package/apps/storefront/src/pages/api/apps/v1/reports.ts +0 -21
  240. package/apps/storefront/src/pages/api/apps/v1/webhooks/deliveries/[deliveryId]/replay.ts +0 -74
  241. package/apps/storefront/src/pages/api/apps/v1/webhooks/deliveries.ts +0 -47
  242. package/apps/storefront/src/pages/api/cache-purge.ts +0 -55
  243. package/apps/storefront/src/pages/api/compliance/tamper.ts +0 -88
  244. package/apps/storefront/src/pages/api/content-edit/ai-edit.ts +0 -164
  245. package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +0 -154
  246. package/apps/storefront/src/pages/api/dashboard/vendor-search.ts +0 -120
  247. package/apps/storefront/src/pages/api/integrations/v1/[operation].ts +0 -108
  248. package/apps/storefront/src/pages/api/publish/stage-bundle.ts +0 -70
  249. package/apps/storefront/src/pages/api/test/dev-session.ts +0 -133
  250. package/apps/storefront/src/pages/cockpit.astro +0 -1548
  251. package/apps/storefront/src/pages/dashboard/[appDomain]/apps/index.astro +0 -119
  252. package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +0 -105
  253. package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +0 -177
  254. package/apps/storefront/src/pages/dashboard/index.astro +0 -160
@@ -1,89 +0,0 @@
1
- /**
2
- * GET /api/apps/admin/integrations — the effective integration admin read model
3
- * (ext-admin-02): the tenant-scoped data behind ext-admin-01's `/admin#integrations`
4
- * IA. Combines each install's desired config, resolved effective plan, compiled CSP,
5
- * consent, assurance, candidate, and rollback availability into ONE safe view.
6
- *
7
- * Auth mirrors `list.ts` exactly: the `?tenant=` query param is only ever a CANDIDATE
8
- * into `resolveOperatorSession` — the tenant actually used is `auth.tenantId` from the
9
- * resolved session, never the raw param — so another tenant, or a vendor with no
10
- * membership, is denied (401/403) before any read model is assembled. Read-only: any
11
- * membership role admits. The pure {@link assembleIntegrationReadModel} is the second,
12
- * defense-in-depth gate: it re-asserts every materialized input belongs to
13
- * `auth.tenantId` and redacts secrets, so a mis-plumbed control plane cannot leak.
14
- *
15
- * The control-plane materialization of effective plans, candidate evidence, and
16
- * assurance records is resolved per install where present; an install with none yet
17
- * surfaces honestly as `configuring` (no effective authority, no rollback), never a
18
- * fabricated live state.
19
- */
20
- import type { APIContext } from "astro";
21
- import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
22
- import { getRegistryService, json } from "@/lib/apps/adminService.js";
23
- import { parseEnvironment, type IntegrationEnvironment } from "@tot/public-runtime";
24
- import {
25
- assembleIntegrationReadModel,
26
- type IntegrationReadModelInputItem,
27
- } from "@/lib/apps/integrationReadModel.js";
28
- import { tenantLocalReadModelItems } from "@/lib/apps/tenantIntegrationMaterialization.js";
29
- import { resolveAdminTenant } from "@/config/adminTenantLookup";
30
-
31
- export const prerender = false;
32
-
33
- /** A merchant-legible purpose line for an install, never an internal adapter name. */
34
- function purposeFor(appId: string): string {
35
- return `Integration: ${appId}`;
36
- }
37
-
38
- export async function GET(context: APIContext): Promise<Response> {
39
- const url = new URL(context.request.url);
40
- const requestedTenant = url.searchParams.get("tenant");
41
- const auth = await resolveOperatorSession(context, requestedTenant);
42
- if (!auth.ok) return json({ error: auth.message }, auth.status);
43
-
44
- const registry = await getRegistryService();
45
- if (registry instanceof Response) return registry;
46
-
47
- const stage: IntegrationEnvironment = parseEnvironment(url.searchParams.get("stage")) ?? "staged";
48
-
49
- const installs = await registry.listByTenant(auth.tenantId);
50
- const items: IntegrationReadModelInputItem[] = installs
51
- .filter((install) => install.status !== "uninstalled")
52
- .map((install) => ({
53
- install: {
54
- installId: install.installId,
55
- appId: install.appId,
56
- appVersion: install.appVersion,
57
- tenantId: install.tenantId,
58
- status: install.status,
59
- },
60
- purpose: purposeFor(install.appId),
61
- // The desired config is the tenant's own input; when the manifest snapshot is not
62
- // a structured object it contributes nothing — never a fabricated value.
63
- desiredConfig: {},
64
- }));
65
-
66
- // ext-kernel-09: a tenant's OWN (tenant-local) declarations are materialized through
67
- // the interim bridge and appended with their REAL effective plan + compiled CSP, so a
68
- // declared integration surfaces effective state — not `configuring`. Resolved off the
69
- // auth-bound tenant config only (the tenant id is `auth.tenantId`, never the param).
70
- // Best-effort + additive: a resolver hiccup degrades to the managed-app view rather
71
- // than failing the whole read model closed.
72
- try {
73
- const tenantConfig = await resolveAdminTenant(auth.tenantId);
74
- if (tenantConfig && tenantConfig.tenant_id === auth.tenantId) {
75
- items.push(...tenantLocalReadModelItems(tenantConfig, stage));
76
- }
77
- } catch (err) {
78
- console.error(`[admin-integrations] tenant-local materialization skipped for ${auth.tenantId}: ${String(err)}`);
79
- }
80
-
81
- const result = assembleIntegrationReadModel({ tenantPublicId: auth.tenantId, stage, items });
82
- if (!result.ok) {
83
- // A cross-tenant input or surviving secret is a server-side integrity failure, not
84
- // something to echo back field-by-field.
85
- return json({ error: "integration read model failed integrity checks" }, 500);
86
- }
87
-
88
- return json({ readModel: result.value });
89
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * GET /api/apps/admin/list — list the app installs for the resolved operator
3
- * tenant (PrivateApps epic, D2 Chunk C; D8 console-session auth added). The
4
- * `?tenant=` query param (read by console callers with several memberships,
5
- * mirroring `../../grants/team-members.ts`) is only ever a CANDIDATE into
6
- * `resolveOperatorSession` — the tenant actually used below is `auth.tenantId`
7
- * from the resolved session, never the raw param, so a caller can only ever
8
- * see their own tenant's installs. Read-only: any membership role admits.
9
- */
10
- import type { APIContext } from "astro";
11
- import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
12
- import { getRegistryService, json } from "@/lib/apps/adminService.js";
13
-
14
- export const prerender = false;
15
-
16
- export async function GET(context: APIContext): Promise<Response> {
17
- const requestedTenant = new URL(context.request.url).searchParams.get("tenant");
18
- const auth = await resolveOperatorSession(context, requestedTenant);
19
- if (!auth.ok) return json({ error: auth.message }, auth.status);
20
-
21
- const registry = await getRegistryService();
22
- if (registry instanceof Response) return registry;
23
-
24
- const installs = await registry.listByTenant(auth.tenantId);
25
- return json({ installs });
26
- }
@@ -1,85 +0,0 @@
1
- /**
2
- * POST /api/apps/admin/platform-adapters — the first-class native adapter
3
- * surface (ext-admin-04). Two actions over the pure, edge-safe adapter core
4
- * ({@link platformAdapterCatalog} / {@link buildPlatformAdapterDeclaration}):
5
- *
6
- * - `catalog` — the first-class adapter cards (consent purposes + performance
7
- * budget + CSP origins + per-stage destination behavior), so a merchant sees the
8
- * material effects before configuring anything.
9
- * - `build` — turn a merchant's public destination ids (per environment) into a
10
- * tenant-scoped declaration + resolved effective plan + read-model card, or
11
- * refuse. Fail-closed: an unknown adapter, a missing/invalid live id, or a
12
- * non-live stage that reuses the live id blocks with violations.
13
- *
14
- * Auth mirrors the other `/api/apps/admin/*` routes: the tenant is `auth.tenantId`
15
- * from the resolved operator session — NEVER the request body — so a build is only
16
- * ever scoped to the caller's own tenant. The build environment is derived server-side
17
- * as a `candidate` stage, so the browser can never forge a live-stage declaration.
18
- * Configuring is a manage action ({@link requireManageRole}). The route does NOT
19
- * persist — staging/publishing a produced candidate is ext-admin-07's lifecycle.
20
- */
21
- import type { APIContext } from "astro";
22
- import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
23
- import { json, requireManageRole } from "@/lib/apps/adminService.js";
24
- import {
25
- platformAdapterCatalog,
26
- buildPlatformAdapterDeclaration,
27
- resolveBrowserEnvironment,
28
- INTEGRATION_SITE_SURFACES,
29
- type IntegrationSiteSurface,
30
- } from "@tot/public-runtime";
31
-
32
- export const prerender = false;
33
-
34
- export async function POST(context: APIContext): Promise<Response> {
35
- const url = new URL(context.request.url);
36
- const requestedTenant = url.searchParams.get("tenant");
37
- const auth = await resolveOperatorSession(context, requestedTenant);
38
- if (!auth.ok) return json({ error: auth.message }, auth.status);
39
- const roleDenied = requireManageRole(auth);
40
- if (roleDenied) return roleDenied;
41
-
42
- let body: unknown;
43
- try {
44
- body = await context.request.json();
45
- } catch {
46
- return json({ error: "request body must be JSON" }, 400);
47
- }
48
- if (typeof body !== "object" || body === null) {
49
- return json({ error: "request body must be a JSON object" }, 400);
50
- }
51
- const action = (body as { action?: unknown }).action;
52
-
53
- if (action === "catalog") {
54
- return json({ catalog: platformAdapterCatalog() });
55
- }
56
-
57
- if (action === "build") {
58
- const fields = (body as { fields?: unknown }).fields;
59
- const base = typeof fields === "object" && fields !== null ? (fields as Record<string, unknown>) : {};
60
- const surfaceParam = (base["siteSurface"] as IntegrationSiteSurface | undefined) ?? "storefront";
61
- const siteSurface = INTEGRATION_SITE_SURFACES.includes(surfaceParam) ? surfaceParam : "storefront";
62
- // A build always targets a candidate; the environment is server-derived, so a
63
- // browser can never forge a live-stage declaration.
64
- const environment = resolveBrowserEnvironment({
65
- siteSurface,
66
- canonicalHost: url.host,
67
- revision: typeof base["revision"] === "string" ? (base["revision"] as string) : "adapter-candidate",
68
- dev: false,
69
- localHost: false,
70
- candidate: true,
71
- previewHost: false,
72
- customizationEnv: "test",
73
- });
74
- const result = buildPlatformAdapterDeclaration({
75
- adapterId: base["adapterId"],
76
- ids: base["ids"],
77
- tenantPublicId: auth.tenantId,
78
- environment,
79
- });
80
- const status = result.ok ? 200 : result.reason === "unknown-adapter" ? 404 : 422;
81
- return json({ result }, status);
82
- }
83
-
84
- return json({ error: 'action must be "catalog" or "build"' }, 400);
85
- }
@@ -1,79 +0,0 @@
1
- /**
2
- * POST /api/apps/admin/resume — resume a suspended install back to active
3
- * (PrivateApps epic, D2 Chunk C; D8 console-session auth added).
4
- *
5
- * `registryService.resume()` takes a bare `installId` with no tenant check of
6
- * its own (Chunk A assumption #1) — so this route resolves the install via
7
- * `requireOwnedInstall` BEFORE calling it, rejecting a foreign-tenant
8
- * `installId` with the SAME 404 a truly-missing one gets (no cross-tenant
9
- * existence oracle). Mutating: `requireManageRole` gates a console
10
- * `developer` role out — the host-bound/Bearer path is exempt (no `role`).
11
- */
12
- import type { APIContext } from "astro";
13
- import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
14
- import {
15
- getRegistryService,
16
- registryErrorResponse,
17
- requireOwnedInstall,
18
- requireManageRole,
19
- parseInstallId,
20
- json,
21
- } from "@/lib/apps/adminService.js";
22
- import { RegistryError } from "@/lib/apps/registryService.js";
23
- import { resolveUiActor } from "@/lib/activity/uiActor";
24
- import { recordActivity } from "@/lib/activity/recordActivity";
25
-
26
- export const prerender = false;
27
-
28
- export async function POST(context: APIContext): Promise<Response> {
29
- const requestedTenant = new URL(context.request.url).searchParams.get("tenant");
30
- const auth = await resolveOperatorSession(context, requestedTenant);
31
- if (!auth.ok) return json({ error: auth.message }, auth.status);
32
- const manageDenied = requireManageRole(auth);
33
- if (manageDenied) return manageDenied;
34
-
35
- let body: unknown;
36
- try {
37
- body = await context.request.json();
38
- } catch {
39
- return json({ error: "invalid JSON body" }, 400);
40
- }
41
-
42
- const installId = parseInstallId(body);
43
- if (!installId) return json({ error: "installId is required" }, 400);
44
-
45
- const registry = await getRegistryService();
46
- if (registry instanceof Response) return registry;
47
-
48
- const owned = await requireOwnedInstall(registry, installId, auth.tenantId);
49
- if (owned instanceof Response) return owned;
50
-
51
- // D10: acting cohort (merchant/admin), emitted source "server" per the app.* catalog.
52
- const activityActor = await resolveUiActor(context, { owner: auth.tenantId });
53
-
54
- try {
55
- const install = await registry.resume(installId, auth.actor);
56
- recordActivity({
57
- action: "app.resume",
58
- actor: activityActor,
59
- source: "server",
60
- outcome: { status: "succeeded" },
61
- scope: { tenantId: auth.tenantId },
62
- payload: { args: { appId: owned.appId, env: owned.env } },
63
- });
64
- return json({ install });
65
- } catch (err) {
66
- if (err instanceof RegistryError) {
67
- recordActivity({
68
- action: "app.resume",
69
- actor: activityActor,
70
- source: "server",
71
- outcome: { status: err.code === "invalid_state" ? "refused" : "failed", errorClass: err.code },
72
- scope: { tenantId: auth.tenantId },
73
- payload: { args: { appId: owned.appId, env: owned.env } },
74
- });
75
- return registryErrorResponse(err);
76
- }
77
- throw err;
78
- }
79
- }
@@ -1,80 +0,0 @@
1
- /**
2
- * POST /api/apps/admin/suspend — suspend an active install: immediately
3
- * disables its API tokens, webhook delivery, and widget placements
4
- * (PrivateApps epic, D2 Chunk C; D8 console-session auth added).
5
- *
6
- * `registryService.suspend()` takes a bare `installId` with no tenant check
7
- * of its own (Chunk A assumption #1) — so this route resolves the install via
8
- * `requireOwnedInstall` BEFORE calling it, rejecting a foreign-tenant
9
- * `installId` with the SAME 404 a truly-missing one gets (no cross-tenant
10
- * existence oracle). Mutating: `requireManageRole` gates a console
11
- * `developer` role out — the host-bound/Bearer path is exempt (no `role`).
12
- */
13
- import type { APIContext } from "astro";
14
- import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
15
- import {
16
- getRegistryService,
17
- registryErrorResponse,
18
- requireOwnedInstall,
19
- requireManageRole,
20
- parseInstallId,
21
- json,
22
- } from "@/lib/apps/adminService.js";
23
- import { RegistryError } from "@/lib/apps/registryService.js";
24
- import { resolveUiActor } from "@/lib/activity/uiActor";
25
- import { recordActivity } from "@/lib/activity/recordActivity";
26
-
27
- export const prerender = false;
28
-
29
- export async function POST(context: APIContext): Promise<Response> {
30
- const requestedTenant = new URL(context.request.url).searchParams.get("tenant");
31
- const auth = await resolveOperatorSession(context, requestedTenant);
32
- if (!auth.ok) return json({ error: auth.message }, auth.status);
33
- const manageDenied = requireManageRole(auth);
34
- if (manageDenied) return manageDenied;
35
-
36
- let body: unknown;
37
- try {
38
- body = await context.request.json();
39
- } catch {
40
- return json({ error: "invalid JSON body" }, 400);
41
- }
42
-
43
- const installId = parseInstallId(body);
44
- if (!installId) return json({ error: "installId is required" }, 400);
45
-
46
- const registry = await getRegistryService();
47
- if (registry instanceof Response) return registry;
48
-
49
- const owned = await requireOwnedInstall(registry, installId, auth.tenantId);
50
- if (owned instanceof Response) return owned;
51
-
52
- // D10: acting cohort (merchant/admin), emitted source "server" per the app.* catalog.
53
- const activityActor = await resolveUiActor(context, { owner: auth.tenantId });
54
-
55
- try {
56
- const install = await registry.suspend(installId, auth.actor);
57
- recordActivity({
58
- action: "app.suspend",
59
- actor: activityActor,
60
- source: "server",
61
- outcome: { status: "succeeded" },
62
- scope: { tenantId: auth.tenantId },
63
- payload: { args: { appId: owned.appId, env: owned.env } },
64
- });
65
- return json({ install });
66
- } catch (err) {
67
- if (err instanceof RegistryError) {
68
- recordActivity({
69
- action: "app.suspend",
70
- actor: activityActor,
71
- source: "server",
72
- outcome: { status: err.code === "invalid_state" ? "refused" : "failed", errorClass: err.code },
73
- scope: { tenantId: auth.tenantId },
74
- payload: { args: { appId: owned.appId, env: owned.env } },
75
- });
76
- return registryErrorResponse(err);
77
- }
78
- throw err;
79
- }
80
- }
@@ -1,98 +0,0 @@
1
- /**
2
- * POST /api/apps/admin/uninstall — uninstall an app: revokes credentials and
3
- * clears placements, but retains the install row + audit trail (PrivateApps
4
- * epic, D2 Chunk C; D8 console-session auth added).
5
- *
6
- * `registryService.uninstall()` takes a bare `installId` with no tenant check
7
- * of its own (Chunk A assumption #1) — so this route resolves the install via
8
- * `requireOwnedInstall` BEFORE calling it, rejecting a foreign-tenant
9
- * `installId` with the SAME 404 a truly-missing one gets (no cross-tenant
10
- * existence oracle). Mutating: `requireManageRole` gates a console
11
- * `developer` role out — the host-bound/Bearer path is exempt (no `role`).
12
- */
13
- import type { APIContext } from "astro";
14
- import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
15
- import {
16
- getRegistryService,
17
- registryErrorResponse,
18
- requireOwnedInstall,
19
- requireManageRole,
20
- parseInstallId,
21
- json,
22
- } from "@/lib/apps/adminService.js";
23
- import { RegistryError } from "@/lib/apps/registryService.js";
24
- import { emitWebhookEvent } from "@/lib/webhooks/emit.js";
25
- import { resolveUiActor } from "@/lib/activity/uiActor";
26
- import { recordActivity } from "@/lib/activity/recordActivity";
27
-
28
- export const prerender = false;
29
-
30
- export async function POST(context: APIContext): Promise<Response> {
31
- const requestedTenant = new URL(context.request.url).searchParams.get("tenant");
32
- const auth = await resolveOperatorSession(context, requestedTenant);
33
- if (!auth.ok) return json({ error: auth.message }, auth.status);
34
- const manageDenied = requireManageRole(auth);
35
- if (manageDenied) return manageDenied;
36
-
37
- let body: unknown;
38
- try {
39
- body = await context.request.json();
40
- } catch {
41
- return json({ error: "invalid JSON body" }, 400);
42
- }
43
-
44
- const installId = parseInstallId(body);
45
- if (!installId) return json({ error: "installId is required" }, 400);
46
-
47
- const registry = await getRegistryService();
48
- if (registry instanceof Response) return registry;
49
-
50
- const owned = await requireOwnedInstall(registry, installId, auth.tenantId);
51
- if (owned instanceof Response) return owned;
52
-
53
- // D10: acting cohort (merchant/admin), emitted source "server" per the app.*
54
- // catalog. Best-effort, never alters control flow.
55
- const activityActor = await resolveUiActor(context, { owner: auth.tenantId });
56
-
57
- try {
58
- const install = await registry.uninstall(installId, auth.actor);
59
- try {
60
- // Best-effort, and deliberately AFTER uninstall has already flipped the
61
- // install to "uninstalled" — this is the final farewell delivery; see
62
- // emit.ts / deliveryEngine.ts's matching status exemption for it.
63
- await emitWebhookEvent("app.uninstalled", auth.tenantId, {}, { installId });
64
- } catch (cause) {
65
- console.warn(
66
- "[diag:webhooks:emit]",
67
- JSON.stringify({
68
- topic: "app.uninstalled",
69
- tenantId: auth.tenantId,
70
- installId,
71
- error: cause instanceof Error ? cause.message : String(cause),
72
- }),
73
- );
74
- }
75
- recordActivity({
76
- action: "app.uninstall",
77
- actor: activityActor,
78
- source: "server",
79
- outcome: { status: "succeeded" },
80
- scope: { tenantId: auth.tenantId },
81
- payload: { args: { appId: owned.appId, env: owned.env } },
82
- });
83
- return json({ install });
84
- } catch (err) {
85
- if (err instanceof RegistryError) {
86
- recordActivity({
87
- action: "app.uninstall",
88
- actor: activityActor,
89
- source: "server",
90
- outcome: { status: "failed", errorClass: err.code },
91
- scope: { tenantId: auth.tenantId },
92
- payload: { args: { appId: owned.appId, env: owned.env } },
93
- });
94
- return registryErrorResponse(err);
95
- }
96
- throw err;
97
- }
98
- }
@@ -1,126 +0,0 @@
1
- /**
2
- * POST /api/apps/admin/update — patch an existing install's version, scopes,
3
- * manifest snapshot, or webhook endpoint (PrivateApps epic, D2 Chunk C; D8
4
- * console-session auth added).
5
- *
6
- * `registryService.update()` takes a bare `installId` with no tenant check of
7
- * its own (Chunk A assumption #1) — so this route resolves the install via
8
- * `requireOwnedInstall` BEFORE calling it, rejecting a foreign-tenant
9
- * `installId` with the SAME 404 a truly-missing one gets (no cross-tenant
10
- * existence oracle). Mutating: `requireManageRole` gates a console
11
- * `developer` role out — the host-bound/Bearer path is exempt (no `role`).
12
- */
13
- import type { APIContext } from "astro";
14
- import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
15
- import {
16
- getRegistryService,
17
- registryErrorResponse,
18
- requireOwnedInstall,
19
- requireManageRole,
20
- parseInstallId,
21
- json,
22
- } from "@/lib/apps/adminService.js";
23
- import { RegistryError, type AppInstallPatch } from "@/lib/apps/registryService.js";
24
- import { resolveUiActor } from "@/lib/activity/uiActor";
25
- import { recordActivity } from "@/lib/activity/recordActivity";
26
-
27
- export const prerender = false;
28
-
29
- interface UpdateBody {
30
- installId?: unknown;
31
- appVersion?: unknown;
32
- scopes?: unknown;
33
- manifest?: unknown;
34
- webhookEndpoint?: unknown;
35
- widgetPlacements?: unknown;
36
- }
37
-
38
- /** Validate + narrow the given fields into `AppInstallPatch`, or a 400 message. */
39
- function parsePatch(body: UpdateBody): AppInstallPatch | string {
40
- const patch: AppInstallPatch = {};
41
- if (body.appVersion !== undefined) {
42
- if (typeof body.appVersion !== "string" || !body.appVersion.trim()) {
43
- return "appVersion, when given, must be a non-empty string";
44
- }
45
- patch.appVersion = body.appVersion;
46
- }
47
- if (body.scopes !== undefined) {
48
- if (!Array.isArray(body.scopes) || body.scopes.some((s) => typeof s !== "string")) {
49
- return "scopes, when given, must be a string[]";
50
- }
51
- patch.scopes = body.scopes as string[];
52
- }
53
- if (body.manifest !== undefined) {
54
- if (body.manifest === null || typeof body.manifest !== "object" || Array.isArray(body.manifest)) {
55
- return "manifest, when given, must be an object";
56
- }
57
- patch.manifest = body.manifest;
58
- }
59
- if (body.webhookEndpoint !== undefined) {
60
- if (body.webhookEndpoint !== null && typeof body.webhookEndpoint !== "string") {
61
- return "webhookEndpoint, when given, must be a string or null";
62
- }
63
- patch.webhookEndpoint = body.webhookEndpoint as string | null;
64
- }
65
- if (body.widgetPlacements !== undefined) {
66
- if (!Array.isArray(body.widgetPlacements)) return "widgetPlacements, when given, must be an array";
67
- patch.widgetPlacements = body.widgetPlacements;
68
- }
69
- return patch;
70
- }
71
-
72
- export async function POST(context: APIContext): Promise<Response> {
73
- const requestedTenant = new URL(context.request.url).searchParams.get("tenant");
74
- const auth = await resolveOperatorSession(context, requestedTenant);
75
- if (!auth.ok) return json({ error: auth.message }, auth.status);
76
- const manageDenied = requireManageRole(auth);
77
- if (manageDenied) return manageDenied;
78
-
79
- let body: UpdateBody;
80
- try {
81
- body = (await context.request.json()) as UpdateBody;
82
- } catch {
83
- return json({ error: "invalid JSON body" }, 400);
84
- }
85
-
86
- const installId = parseInstallId(body);
87
- if (!installId) return json({ error: "installId is required" }, 400);
88
-
89
- const patch = parsePatch(body);
90
- if (typeof patch === "string") return json({ error: patch }, 400);
91
-
92
- const registry = await getRegistryService();
93
- if (registry instanceof Response) return registry;
94
-
95
- const owned = await requireOwnedInstall(registry, installId, auth.tenantId);
96
- if (owned instanceof Response) return owned;
97
-
98
- // D10: acting cohort (merchant/admin), emitted source "server" per the app.* catalog.
99
- const activityActor = await resolveUiActor(context, { owner: auth.tenantId });
100
-
101
- try {
102
- const install = await registry.update(installId, patch, auth.actor);
103
- recordActivity({
104
- action: "app.update",
105
- actor: activityActor,
106
- source: "server",
107
- outcome: { status: "succeeded" },
108
- scope: { tenantId: auth.tenantId },
109
- payload: { args: { appId: owned.appId, env: owned.env } },
110
- });
111
- return json({ install });
112
- } catch (err) {
113
- if (err instanceof RegistryError) {
114
- recordActivity({
115
- action: "app.update",
116
- actor: activityActor,
117
- source: "server",
118
- outcome: { status: err.code === "invalid_state" ? "refused" : "failed", errorClass: err.code },
119
- scope: { tenantId: auth.tenantId },
120
- payload: { args: { appId: owned.appId, env: owned.env } },
121
- });
122
- return registryErrorResponse(err);
123
- }
124
- throw err;
125
- }
126
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * POST /api/apps/admin/webhooks/deliveries/{deliveryId}/replay — the
3
- * ops/support replay (PrivateApps epic, D4 Chunk E; D8 console-session auth
4
- * added). Operator session only; `tenantId` comes from `auth.tenantId`
5
- * (`resolveOperatorSession`), never the request. A `deliveryId` whose
6
- * `tenantId` doesn't match the operator's resolved tenant 404s identically to
7
- * a truly-missing one — same no-cross-tenant-oracle discipline
8
- * `requireOwnedInstall` keeps for install ids. `webhook_deliveries` already
9
- * carries its own `tenantId` (set at creation, mirroring the owning
10
- * install's), so this checks that column directly rather than round-tripping
11
- * through the registry. Mutating (re-enqueues a delivery): `requireManageRole`
12
- * gates a console `developer` role out — the host-bound/Bearer path is
13
- * exempt (no `role`).
14
- *
15
- * Not part of the app-facing `openapi.yaml` contract (same as the rest of
16
- * `admin/*`) — no `Idempotency-Key` requirement; an authenticated operator
17
- * retriggering a replay isn't the untrusted-client-retry case that header
18
- * guards against.
19
- *
20
- * Same `requeueForReplay` + same-`deliveryId` re-enqueue as the app-facing
21
- * replay — see that route's doc comment for the full rationale.
22
- */
23
- import type { APIContext } from "astro";
24
- import { resolveOperatorSession } from "@/lib/apps/adminSession.js";
25
- import { json, requireManageRole } from "@/lib/apps/adminService.js";
26
- import { WebhookDeliveryStore } from "@/lib/webhooks/deliveryStore.js";
27
- import { getDispatcher } from "@/lib/webhooks/getDispatcher.js";
28
- import { fromD1 } from "@/lib/d1/catalog.js";
29
- import { readD1 } from "@/lib/env";
30
- import { resolveUiActor, recordUiActivity } from "@/lib/activity/uiActor";
31
-
32
- export const prerender = false;
33
-
34
- export async function POST(context: APIContext): Promise<Response> {
35
- const requestedTenant = new URL(context.request.url).searchParams.get("tenant");
36
- const auth = await resolveOperatorSession(context, requestedTenant);
37
- if (!auth.ok) return json({ error: auth.message }, auth.status);
38
- const manageDenied = requireManageRole(auth);
39
- if (manageDenied) return manageDenied;
40
-
41
- const deliveryId = context.params.deliveryId;
42
- if (!deliveryId) return json({ error: "Delivery not found.", code: "not_found" }, 404);
43
-
44
- const d1 = await readD1("STOREFRONT_APPS_DB");
45
- if (!d1) return json({ error: "webhook store not configured" }, 503);
46
- const store = new WebhookDeliveryStore(fromD1(d1));
47
-
48
- const delivery = await store.getDelivery(deliveryId);
49
- if (!delivery || delivery.tenantId !== auth.tenantId) {
50
- return json({ error: "Delivery not found.", code: "not_found" }, 404);
51
- }
52
-
53
- const dispatcher = await getDispatcher();
54
- if (dispatcher instanceof Response) return dispatcher;
55
-
56
- const requeued = await store.requeueForReplay(deliveryId);
57
- await dispatcher.enqueue({ deliveryId });
58
-
59
- // D11: ops/support console replay. Resolve the acting cohort (admin/merchant per
60
- // resolveOperatorSession) from the session; `surface: "admin"` disambiguates from the
61
- // app-facing v1 call site that shares this key. deliveryId is the opaque wire id.
62
- const activityActor = await resolveUiActor(context, {});
63
- recordUiActivity(activityActor, {
64
- action: "webhook.delivery.replayed",
65
- outcome: { status: "succeeded" },
66
- scope: { tenantId: auth.tenantId },
67
- payload: { args: { deliveryId, surface: "admin" } },
68
- });
69
- return json({ delivery: requeued }, 202);
70
- }