@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,116 +0,0 @@
1
- /**
2
- * Composition root + shared helpers for the `/api/apps/admin/*` routes —
3
- * builds an `AppRegistryService` over the
4
- * `STOREFRONT_APPS_DB` `Queryable` binding and a `D1CredentialStore`, the same
5
- * construction `api/apps/oauth/token.ts` uses, and mirrors
6
- * `../grants/route.ts`'s `getService()` + no-store `json()` + 503-when-
7
- * unconfigured pattern. Kept out of the pure service module so that stays
8
- * transport-free and unit-testable against a fake `Queryable`.
9
- */
10
- import {
11
- AppRegistryService,
12
- RegistryError,
13
- type AppInstall,
14
- type RegistryErrorCode,
15
- } from "./registryService.js";
16
- import { D1CredentialStore } from "./credentials.js";
17
- import { DEFAULT_APP_GATEWAY_KID, APP_GATEWAY_KID_ENV } from "./gatewayKeys.js";
18
- import { fromD1 } from "../d1/catalog.js";
19
- import { readD1, readEnv } from "../env.js";
20
- import { MANAGE_ROLES, type AdminAuthResult } from "./adminSession.js";
21
- import { ManagedAnalyticsApiV1Facade } from "./managedAnalyticsService.js";
22
-
23
- /**
24
- * No-store JSON response — install/rotate bodies carry a one-time client
25
- * secret and must never be edge- or browser-cached.
26
- */
27
- export function json(body: unknown, status = 200): Response {
28
- return new Response(JSON.stringify(body), {
29
- status,
30
- headers: { "content-type": "application/json", "cache-control": "no-store" },
31
- });
32
- }
33
-
34
- /**
35
- * Build an `AppRegistryService` over the real `STOREFRONT_APPS_DB` D1
36
- * binding, or return a 503 Response when that binding isn't configured in
37
- * this runtime. Never leaks binding/secret detail in the response body.
38
- */
39
- export async function getRegistryService(): Promise<AppRegistryService | Response> {
40
- const d1 = await readD1("STOREFRONT_APPS_DB");
41
- if (!d1) return json({ error: "app registry not configured" }, 503);
42
- const db = fromD1(d1);
43
- const activeKid = (await readEnv(APP_GATEWAY_KID_ENV)) ?? DEFAULT_APP_GATEWAY_KID;
44
- const credentials = new D1CredentialStore(db, activeKid);
45
- return new AppRegistryService(db, credentials);
46
- }
47
-
48
- /** Build the managed-analytics v1 service over the same tenant control-plane D1. */
49
- export async function getManagedAnalyticsService(): Promise<ManagedAnalyticsApiV1Facade | Response> {
50
- const d1 = await readD1("STOREFRONT_APPS_DB");
51
- if (!d1) return json({ error: "app registry not configured" }, 503);
52
- return new ManagedAnalyticsApiV1Facade(fromD1(d1));
53
- }
54
-
55
- /** HTTP status per `RegistryError` code — the one shared fail-closed mapping. */
56
- const STATUS_BY_REGISTRY_CODE: Record<RegistryErrorCode, number> = {
57
- scope_denied: 400,
58
- not_found: 404,
59
- already_installed: 409,
60
- invalid_state: 409,
61
- invalid_webhook_endpoint: 400,
62
- invalid_widget_placement: 400,
63
- unknown_version: 404,
64
- invalid_version_facets: 400,
65
- };
66
-
67
- /** Map a `RegistryError` to its HTTP status. Never echoes internals — code + message only. */
68
- export function registryErrorResponse(err: RegistryError): Response {
69
- const body: Record<string, unknown> = { error: err.message, code: err.code };
70
- if (err.denials) body.denials = err.denials;
71
- return json(body, STATUS_BY_REGISTRY_CODE[err.code]);
72
- }
73
-
74
- /** Parse `{ installId }` from a JSON body — shared by every installId-bearing admin route. */
75
- export function parseInstallId(body: unknown): string | null {
76
- if (!body || typeof body !== "object") return null;
77
- const installId = (body as { installId?: unknown }).installId;
78
- return typeof installId === "string" && installId.trim() ? installId.trim() : null;
79
- }
80
-
81
- /**
82
- * Resolve `installId` and verify it belongs to `tenantId` — every mutating
83
- * admin route (update/suspend/resume/uninstall/rotate) MUST call this BEFORE
84
- * invoking a service method, since those methods take a bare `installId` with
85
- * no tenant check of their own. A foreign-tenant
86
- * `installId` is reported IDENTICALLY to a truly-missing one — 404, same
87
- * body shape as `RegistryError("not_found")` — so there is no cross-tenant
88
- * existence oracle.
89
- */
90
- export async function requireOwnedInstall(
91
- registry: AppRegistryService,
92
- installId: string,
93
- tenantId: string,
94
- ): Promise<AppInstall | Response> {
95
- const install = await registry.get(installId);
96
- if (!install || install.tenantId !== tenantId) {
97
- return json({ error: "App install not found.", code: "not_found" }, 404);
98
- }
99
- return install;
100
- }
101
-
102
- /**
103
- * Gate a mutating admin route on the resolved auth's role — call AFTER
104
- * `resolveOperatorSession` for every write route (suspend/resume/uninstall/
105
- * update/rotate/replay). A console session's `role` must be in
106
- * `MANAGE_ROLES`: a `developer` is read-only and gets a 403 here. The
107
- * host-bound/Bearer path (`resolveAdminSession`) carries no `role` at all —
108
- * it is already manage-capable (gated by `ADMIN_CAPABILITIES`/the dedicated
109
- * secret) — so an `undefined` role is exempt, not denied.
110
- */
111
- export function requireManageRole(auth: Extract<AdminAuthResult, { ok: true }>): Response | null {
112
- if (auth.role !== undefined && !MANAGE_ROLES.has(auth.role)) {
113
- return json({ error: "not authorized to manage apps for this tenant" }, 403);
114
- }
115
- return null;
116
- }
@@ -1,214 +0,0 @@
1
- /**
2
- * Operator-session resolution for the Private Apps admin API
3
- * (`/api/apps/admin/*`). Mirrors
4
- * `../grants/session.ts`'s owner-session resolution — same two paths, same
5
- * fail-closed shape — but resolves `{ tenantId, actor }` instead of `{ owner }`:
6
- *
7
- * - `tenantId` is the `AppInstall.tenantId` scope. It MUST equal the
8
- * host-resolved `appDomain` the OAuth token issuer checks installs
9
- * against (`tokenIssuer.ts` compares `install.tenantId` to the caller's
10
- * `context.locals.tenant.appDomain`) — so an app installed through this
11
- * admin API is later discoverable by the SAME tenant identity a minted
12
- * token is scoped to.
13
- * - `actor` is an OPAQUE id for the audit log (`app_audit_log.actor` —
14
- * "never email/PII", see `../d1/schema.ts`). A signed-in viewer's verified
15
- * email is one-way hashed (`sha256Hex`, the same primitive `credentials.ts`
16
- * uses for secrets) so distinct operators still produce distinct, stable
17
- * audit actors without the trail ever holding an email address.
18
- *
19
- * Two resolution paths, tried in order:
20
- * 1. SIGNED-IN TENANT OPERATOR (primary). `context.locals.viewer` (set by
21
- * the login-gate middleware from the `tot_session` cookie) plus
22
- * `context.locals.tenant`. Admitted only for an owner/admin capability
23
- * on the resolved tenant — a lower-capability viewer is a resolved
24
- * session with insufficient authority, so this fails closed with 403
25
- * rather than silently falling through to path 2.
26
- * 2. BEARER OPERATOR SECRET (fallback, headless console). Gated by a
27
- * DEDICATED `APPS_ADMIN_SECRET` only — unlike grants' session, this does
28
- * NOT fall back to the shared `PREVIEW_RECONCILE_SECRET`, since that
29
- * secret must not double as a cross-tenant app-registry master key
30
- * Unconfigured `APPS_ADMIN_SECRET`
31
- * means this path is unavailable — fails closed rather than trusting
32
- * another deployment's secret. The tenant is resolved server-side from
33
- * `APPS_ADMIN_TENANT` env or the `X-Tot-Tenant` header (honoured only
34
- * for an already-authenticated caller) — never from the request body.
35
- * There is no per-caller identity on this path, so `actor` is the fixed
36
- * literal below.
37
- *
38
- * Routes depend only on the `{ ok, tenantId, actor }` result. `authorizeAdmin`
39
- * is the pure core of path 2 (unit-testable, no I/O).
40
- *
41
- * Console admin session. The two paths above are host-bound:
42
- * they resolve exactly one tenant (`context.locals.tenant`). The
43
- * `/api/apps/admin/*` surface is also reachable from the multi-tenant vendor
44
- * console, where a signed-in viewer may hold memberships on several vendors —
45
- * so `resolveConsoleAdminSession` mirrors `../grants/team-members.ts`'s
46
- * pattern instead: `readViewerSession` (the FULL session, all `tenants[]`)
47
- * plus an explicit `requestedTenant` from the request, admitted via
48
- * `viewerCanAccess`/`membershipFor` (deny-by-default, staff-selection-aware).
49
- * Its `role` is the caller's resolved membership role
50
- * (`developer`|`appAdmin`|`appOwner`) so routes can gate mutations against
51
- * `MANAGE_ROLES` — a `developer` is read-only. `resolveOperatorSession` is
52
- * the single entry point routes call: it tries the console path first and
53
- * only falls back to `resolveAdminSession` (path 1/2 above) when there is NO
54
- * console session at all (401) — a console session that exists but lacks
55
- * access to `requestedTenant` fails closed with its own 403, the same
56
- * no-fall-through discipline path 1 already uses for an insufficient
57
- * capability.
58
- */
59
- import type { APIContext } from "astro";
60
- import { sha256Hex } from "@tot/public-runtime";
61
- import { readEnv } from "@/lib/env";
62
- import { readViewerSession } from "@/lib/auth/route.js";
63
- import { viewerCanAccess, membershipFor } from "@/lib/dashboard/tenantSelection.js";
64
- import {
65
- authorizeBearerOperator,
66
- resolveHostBoundSession,
67
- type SessionFailure,
68
- } from "@/lib/auth/operatorSession.js";
69
-
70
- /** Capabilities that make a signed-in viewer an app-registry operator for their tenant. */
71
- const ADMIN_CAPABILITIES: ReadonlySet<string> = new Set(["owner", "admin"]);
72
-
73
- /** Console membership roles authorized to mutate installs — a `developer` is read-only. */
74
- export const MANAGE_ROLES: ReadonlySet<string> = new Set(["appOwner", "appAdmin"]);
75
-
76
- /** Opaque `actor` stamped for the shared Bearer fallback — no per-caller identity to hash. */
77
- const BEARER_ACTOR = "bearer-operator";
78
-
79
- /** How many hex chars of the email digest to keep — enough entropy to distinguish operators. */
80
- const ACTOR_HASH_LENGTH = 32;
81
-
82
- /** Pure inputs to the Bearer-fallback authorization decision (env + request, no I/O). */
83
- export interface AdminAuthInput {
84
- /** The request `Authorization` header, if any. */
85
- authHeader: string | null;
86
- /** The configured operator gate secret (or undefined if unconfigured). */
87
- gateSecret: string | undefined;
88
- /** Server-configured tenant for this deployment (APPS_ADMIN_TENANT), if any. */
89
- configuredTenant: string | undefined;
90
- /** `X-Tot-Tenant` header — honoured only once the caller is authenticated. */
91
- requestedTenant: string | null;
92
- }
93
-
94
- export type AdminAuthResult =
95
- | { ok: true; tenantId: string; actor: string; role?: string }
96
- | SessionFailure;
97
-
98
- /** The one authorized-success shape both host-bound and Bearer admin paths return. */
99
- type AdminAuthOk = Extract<AdminAuthResult, { ok: true }>;
100
-
101
- /**
102
- * Decide the authenticated tenant from env + request, with NO I/O —
103
- * unit-testable. Fail-closed: unconfigured gate → 503, bad/absent Bearer →
104
- * 401, no resolvable tenant → 400. A thin adapter over the shared
105
- * Bearer-operator core that maps its resolved `principal` to this surface's
106
- * `tenantId` and stamps the fixed `BEARER_ACTOR` (no per-caller identity here).
107
- */
108
- export function authorizeAdmin(input: AdminAuthInput): AdminAuthResult {
109
- const res = authorizeBearerOperator({
110
- authHeader: input.authHeader,
111
- gateSecret: input.gateSecret,
112
- configuredPrincipal: input.configuredTenant,
113
- requestedPrincipal: input.requestedTenant,
114
- unconfiguredMessage: "apps admin operator secret not configured",
115
- unresolvedMessage: "tenant unresolved (set APPS_ADMIN_TENANT or X-Tot-Tenant)",
116
- });
117
- return res.ok
118
- ? { ok: true, tenantId: res.principal, actor: BEARER_ACTOR }
119
- : res;
120
- }
121
-
122
- /** One-way, stable pseudonym for an audit `actor` — never the email itself. */
123
- async function actorFromEmail(email: string): Promise<string> {
124
- return `viewer:${(await sha256Hex(email)).slice(0, ACTOR_HASH_LENGTH)}`;
125
- }
126
-
127
- /**
128
- * Resolve the authenticated `{ tenantId, actor }` for a Private Apps admin
129
- * request from the runtime env + the incoming request. Never reads `tenantId`
130
- * from the body.
131
- */
132
- export async function resolveAdminSession(context: APIContext): Promise<AdminAuthResult> {
133
- return resolveHostBoundSession<AdminAuthOk>(context, {
134
- capabilities: ADMIN_CAPABILITIES,
135
- // A resolved-but-insufficient viewer fails closed with 403 and does NOT
136
- // fall through to the Bearer gate — an authenticated-but-under-privileged
137
- // caller must not be silently admitted by a secret it also presents.
138
- onInsufficientCapability: {
139
- mode: "failClosed",
140
- failure: {
141
- ok: false,
142
- status: 403,
143
- message: "not authorized to manage apps for this tenant",
144
- },
145
- },
146
- // Path 1: the tenant IS the resolved host's appDomain — never the body.
147
- resolveViewer: async (viewer, tenantId) => ({
148
- ok: true,
149
- tenantId,
150
- actor: await actorFromEmail(viewer.email),
151
- }),
152
- // Path 2 (fallback): the headless-console Bearer operator secret. Dedicated
153
- // secret only — no fallback to another deployment's secret.
154
- resolveBearer: async (ctx) => {
155
- const gateSecret = await readEnv("APPS_ADMIN_SECRET");
156
- const configuredTenant = await readEnv("APPS_ADMIN_TENANT");
157
- return authorizeAdmin({
158
- authHeader: ctx.request.headers.get("authorization"),
159
- gateSecret,
160
- configuredTenant,
161
- requestedTenant: ctx.request.headers.get("x-tot-tenant"),
162
- });
163
- },
164
- });
165
- }
166
-
167
- /**
168
- * Resolve a signed-in console viewer's admin session for `requestedTenant`
169
- * (the `?tenant=` query param every admin route now reads) — the multi-tenant
170
- * counterpart to `resolveAdminSession`'s host-bound path 1, mirroring
171
- * `../grants/team-members.ts`'s `readViewerSession` + `viewerCanAccess`
172
- * pattern instead of the single-tenant `locals.tenant`/`locals.viewer` gate.
173
- * Fail-closed: no session → 401 (the signal `resolveOperatorSession` uses to
174
- * fall back to the host-bound/Bearer path); a session with no membership or
175
- * live staff admission for `requestedTenant` → 403 (does NOT fall back — an
176
- * authenticated-but-denied caller is not the "no console session" case).
177
- * `role` is the caller's resolved membership role for routes to gate
178
- * mutations against `MANAGE_ROLES`.
179
- */
180
- export async function resolveConsoleAdminSession(
181
- context: APIContext,
182
- requestedTenant: string | null,
183
- ): Promise<AdminAuthResult> {
184
- const session = await readViewerSession(context);
185
- if (!session) return { ok: false, status: 401, message: "not signed in" };
186
-
187
- const tenantId = (requestedTenant ?? "").trim();
188
- const staff = { selection: session.staffSelection, nowSeconds: Math.floor(Date.now() / 1000) };
189
- if (!viewerCanAccess(session.tenants, tenantId, staff)) {
190
- return {
191
- ok: false,
192
- status: 403,
193
- message: "not authorized to manage apps for this tenant",
194
- };
195
- }
196
- const role = membershipFor(session.tenants, tenantId, staff)?.role ?? "developer";
197
- return { ok: true, tenantId, actor: await actorFromEmail(session.email), role };
198
- }
199
-
200
- /**
201
- * The single entry point admin routes call: try the signed-in console
202
- * viewer's session first, and only fall back to the host-bound/Bearer path
203
- * (`resolveAdminSession`) when there is no console session at all (401) — see
204
- * {@link resolveConsoleAdminSession}'s doc for why a denied console session
205
- * (403) does not fall through.
206
- */
207
- export async function resolveOperatorSession(
208
- context: APIContext,
209
- requestedTenant: string | null,
210
- ): Promise<AdminAuthResult> {
211
- const consoleAuth = await resolveConsoleAdminSession(context, requestedTenant);
212
- if (consoleAuth.ok || consoleAuth.status !== 401) return consoleAuth;
213
- return resolveAdminSession(context);
214
- }
@@ -1,91 +0,0 @@
1
- /**
2
- * The scoped-API authorization boundary — every
3
- * `/api/apps/v1/*` route calls `authorizeAppRequest` FIRST. Verifies the
4
- * app-gateway bearer JWT (`AppTokenVerifier`), resolves the calling
5
- * install from the registry, and enforces the single scope the route
6
- * requires per `docs/private-apps/contract/openapi.yaml`'s `x-requiredScope`.
7
- *
8
- * Tenant is ALWAYS the host-resolved `context.locals.tenant.appDomain` —
9
- * never a header or query param — the same binding `tokenIssuer.ts` and
10
- * `oauth/token.ts` use, so a token can't be replayed against a different
11
- * tenant than the one it was minted for.
12
- *
13
- * Fail-closed throughout: an unconfigured signing key, a missing/invalid/
14
- * expired token, and an install that's gone missing/cross-tenant/suspended/
15
- * uninstalled are ALL reported identically as the generic 401 the contract's
16
- * `Unauthorized` response documents (no detail that would let a caller
17
- * distinguish "wrong tenant" from "suspended" from "never existed" — the
18
- * same no-oracle discipline `registryService.ts`'s `mustFindRow` and
19
- * `tokenIssuer.ts`'s `invalid_client` already keep).
20
- */
21
- import type { APIContext } from "astro";
22
- import { getAppTokenVerifier, type AppTokenClaims } from "./tokenVerifier.js";
23
- import { getRegistryService } from "./adminService.js";
24
- import type { AppInstall } from "./registryService.js";
25
- import { json } from "./apiRoute.js";
26
-
27
- export interface AuthorizedAppRequest {
28
- ok: true;
29
- claims: AppTokenClaims;
30
- install: AppInstall;
31
- }
32
-
33
- export type AuthorizeAppResult = AuthorizedAppRequest | { ok: false; response: Response };
34
-
35
- /** Generic, no-detail 401 — see the fail-closed note above. */
36
- function unauthorized(): Response {
37
- return json({ error: "Unauthorized", code: "invalid_token" }, 401);
38
- }
39
-
40
- /**
41
- * Authorize one `/api/apps/v1/*` request. Pass the single scope id the route
42
- * requires (per the contract's `x-requiredScope`), or `null` for the
43
- * metadata endpoints that only require a valid token.
44
- */
45
- export async function authorizeAppRequest(
46
- context: APIContext,
47
- requiredScope: string | null,
48
- ): Promise<AuthorizeAppResult> {
49
- const tenant = context.locals.tenant.appDomain;
50
-
51
- const verifier = await getAppTokenVerifier(tenant);
52
- if (!verifier) {
53
- return { ok: false, response: json({ error: "app gateway not configured", code: "unconfigured" }, 503) };
54
- }
55
-
56
- const authHeader = context.request.headers.get("authorization");
57
- const token = authHeader?.startsWith("Bearer ") ? authHeader.slice("Bearer ".length).trim() : "";
58
- if (!token) {
59
- return { ok: false, response: unauthorized() };
60
- }
61
-
62
- let claims: AppTokenClaims;
63
- try {
64
- claims = await verifier.verify(token);
65
- } catch {
66
- return { ok: false, response: unauthorized() };
67
- }
68
-
69
- const registry = await getRegistryService();
70
- if (registry instanceof Response) return { ok: false, response: registry };
71
-
72
- const install = await registry.get(claims.sub);
73
- if (!install || install.tenantId !== tenant || install.status !== "active") {
74
- return { ok: false, response: unauthorized() };
75
- }
76
-
77
- // Enforce the scope against BOTH the live install grant and the token claims.
78
- // install.scopes is the authoritative, real-time grant — so an operator
79
- // narrowing scopes via update() takes effect immediately (not only after the
80
- // ~300s token TTL), matching how install *status* is already live-checked
81
- // above. Requiring it in the token too keeps a token from ever exceeding the
82
- // grant it was minted with. Fail-closed: absent from either → denied.
83
- if (
84
- requiredScope &&
85
- !(install.scopes.includes(requiredScope) && claims.scopes.includes(requiredScope))
86
- ) {
87
- return { ok: false, response: json({ error: "scope_denied", code: "scope_denied" }, 403) };
88
- }
89
-
90
- return { ok: true, claims, install };
91
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * Response helpers shared by every `/api/apps/v1/*` route — a no-store JSON
3
- * responder (mirrors `../grants/route.ts` /
4
- * `./adminService.ts`'s pattern) plus the `tot-request-id` / `traceparent`
5
- * response headers `docs/private-apps/contract/openapi.yaml` documents on
6
- * every operation.
7
- */
8
- import type { APIContext } from "astro";
9
-
10
- /** No-store JSON response — scoped-app API bodies must never be edge/browser-cached. */
11
- export function json(body: unknown, status = 200): Response {
12
- return new Response(JSON.stringify(body), {
13
- status,
14
- headers: { "content-type": "application/json", "cache-control": "no-store" },
15
- });
16
- }
17
-
18
- /** The W3C Trace Context shape the contract's `Traceparent` parameter/header pins. */
19
- const TRACEPARENT_RE = /^[0-9a-f]{2}-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/;
20
-
21
- /**
22
- * Stamp a fresh `tot-request-id` on every response, and echo `traceparent`
23
- * back ONLY when the request sent a well-formed one — never fabricate a
24
- * trace context the caller didn't start. Callers apply this to BOTH success
25
- * and error responses (including `authorizeAppRequest`'s), so every response
26
- * off a `/api/apps/v1/*` route carries a request id.
27
- */
28
- export function withRequestId(res: Response, context: Pick<APIContext, "request">): Response {
29
- res.headers.set("tot-request-id", crypto.randomUUID());
30
- const traceparent = context.request.headers.get("traceparent");
31
- if (traceparent && TRACEPARENT_RE.test(traceparent)) {
32
- res.headers.set("traceparent", traceparent);
33
- }
34
- return res;
35
- }
@@ -1,39 +0,0 @@
1
- /**
2
- * Maps the internal `CatalogProduct` read model to the scoped-API contract's
3
- * `Product` shape (`docs/private-apps/contract/openapi.yaml`, schema
4
- * `Product` — `additionalProperties: false`). Drops every internal field
5
- * the contract doesn't declare (variants, images, metafields, source, …) so
6
- * an app only ever sees the minimized public catalog surface.
7
- */
8
- import type { CatalogProduct } from "@tot/public-runtime";
9
-
10
- export interface ContractProduct {
11
- id: string;
12
- handle: string;
13
- title: string;
14
- status: "active" | "draft" | "archived";
15
- vendor?: string;
16
- productType?: string;
17
- tags?: string[];
18
- priceRange: { min: number; max: number; currency: string };
19
- updatedAt?: string;
20
- }
21
-
22
- /** Project one `CatalogProduct` into the contract's `Product` — nothing else survives. */
23
- export function toContractProduct(p: CatalogProduct): ContractProduct {
24
- return {
25
- id: p.id,
26
- handle: p.handle,
27
- title: p.title,
28
- status: p.status,
29
- vendor: p.vendor,
30
- productType: p.product_type,
31
- tags: p.tags,
32
- priceRange: {
33
- min: p.price_range.min,
34
- max: p.price_range.max,
35
- currency: p.price_range.currency,
36
- },
37
- updatedAt: p.updated_at,
38
- };
39
- }