@aglyn/plugins-marketplace 1.14.0 → 1.15.1

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 (107) hide show
  1. package/README.md +1 -0
  2. package/package.json +15 -14
  3. package/src/lib/components/editor-connections-provider.component.d.ts +37 -0
  4. package/src/lib/components/editor-connections-provider.component.js +161 -0
  5. package/src/lib/components/editor-connections-provider.component.js.map +1 -0
  6. package/src/lib/components/listing-connection-credentials-card.component.d.ts +33 -0
  7. package/src/lib/components/listing-connection-credentials-card.component.js +318 -0
  8. package/src/lib/components/listing-connection-credentials-card.component.js.map +1 -0
  9. package/src/lib/components/listing-detail-page.component.js +10 -2
  10. package/src/lib/components/listing-detail-page.component.js.map +1 -1
  11. package/src/lib/components/site-plugin-connections-card.component.d.ts +38 -0
  12. package/src/lib/components/site-plugin-connections-card.component.js +576 -0
  13. package/src/lib/components/site-plugin-connections-card.component.js.map +1 -0
  14. package/src/lib/declarations.console-server.d.ts +17 -0
  15. package/src/lib/declarations.console-server.js +41 -0
  16. package/src/lib/declarations.console-server.js.map +1 -0
  17. package/src/lib/declarations.js +11 -2
  18. package/src/lib/declarations.js.map +1 -1
  19. package/src/lib/declarations.server.js +68 -1
  20. package/src/lib/declarations.server.js.map +1 -1
  21. package/src/lib/hooks/use-plugin-connections-api.d.ts +89 -0
  22. package/src/lib/hooks/use-plugin-connections-api.js +132 -0
  23. package/src/lib/hooks/use-plugin-connections-api.js.map +1 -0
  24. package/src/lib/model/editor-connections.d.ts +46 -0
  25. package/src/lib/model/editor-connections.js +70 -0
  26. package/src/lib/model/editor-connections.js.map +1 -0
  27. package/src/lib/model/listing-price-floor.js +7 -4
  28. package/src/lib/model/listing-price-floor.js.map +1 -1
  29. package/src/lib/model/marketplace-publisher-permissions.d.ts +3 -1
  30. package/src/lib/model/marketplace-publisher-permissions.js +14 -0
  31. package/src/lib/model/marketplace-publisher-permissions.js.map +1 -1
  32. package/src/lib/model/marketplace-site-permissions.d.ts +9 -0
  33. package/src/lib/model/marketplace-site-permissions.js +29 -0
  34. package/src/lib/model/marketplace-site-permissions.js.map +1 -1
  35. package/src/lib/model/plugin-connection-card.d.ts +88 -0
  36. package/src/lib/model/plugin-connection-card.js +187 -0
  37. package/src/lib/model/plugin-connection-card.js.map +1 -0
  38. package/src/lib/model/plugin-connections.d.ts +172 -0
  39. package/src/lib/model/plugin-connections.js +119 -0
  40. package/src/lib/model/plugin-connections.js.map +1 -0
  41. package/src/lib/plugin.js +21 -1
  42. package/src/lib/plugin.js.map +1 -1
  43. package/src/lib/server/admin-reviews.js +18 -12
  44. package/src/lib/server/admin-reviews.js.map +1 -1
  45. package/src/lib/server/artifact-inventory.js +3 -1
  46. package/src/lib/server/artifact-inventory.js.map +1 -1
  47. package/src/lib/server/checkout.js +4 -0
  48. package/src/lib/server/checkout.js.map +1 -1
  49. package/src/lib/server/connections/cleanup.d.ts +84 -0
  50. package/src/lib/server/connections/cleanup.js +116 -0
  51. package/src/lib/server/connections/cleanup.js.map +1 -0
  52. package/src/lib/server/connections/config.d.ts +42 -0
  53. package/src/lib/server/connections/config.js +48 -0
  54. package/src/lib/server/connections/config.js.map +1 -0
  55. package/src/lib/server/connections/connection-store.d.ts +173 -0
  56. package/src/lib/server/connections/connection-store.js +331 -0
  57. package/src/lib/server/connections/connection-store.js.map +1 -0
  58. package/src/lib/server/connections/credentials-store.d.ts +71 -0
  59. package/src/lib/server/connections/credentials-store.js +78 -0
  60. package/src/lib/server/connections/credentials-store.js.map +1 -0
  61. package/src/lib/server/connections/erasure.d.ts +25 -0
  62. package/src/lib/server/connections/erasure.js +72 -0
  63. package/src/lib/server/connections/erasure.js.map +1 -0
  64. package/src/lib/server/connections/installed-connection.d.ts +64 -0
  65. package/src/lib/server/connections/installed-connection.js +92 -0
  66. package/src/lib/server/connections/installed-connection.js.map +1 -0
  67. package/src/lib/server/connections/oauth-state.d.ts +129 -0
  68. package/src/lib/server/connections/oauth-state.js +252 -0
  69. package/src/lib/server/connections/oauth-state.js.map +1 -0
  70. package/src/lib/server/connections/provider-http.d.ts +99 -0
  71. package/src/lib/server/connections/provider-http.js +253 -0
  72. package/src/lib/server/connections/provider-http.js.map +1 -0
  73. package/src/lib/server/connections/record-announce.d.ts +20 -0
  74. package/src/lib/server/connections/record-announce.js +53 -0
  75. package/src/lib/server/connections/record-announce.js.map +1 -0
  76. package/src/lib/server/connections/record-mapping.d.ts +63 -0
  77. package/src/lib/server/connections/record-mapping.js +151 -0
  78. package/src/lib/server/connections/record-mapping.js.map +1 -0
  79. package/src/lib/server/connections/record-routes.d.ts +17 -0
  80. package/src/lib/server/connections/record-routes.js +96 -0
  81. package/src/lib/server/connections/record-routes.js.map +1 -0
  82. package/src/lib/server/connections/revoke.d.ts +29 -0
  83. package/src/lib/server/connections/revoke.js +52 -0
  84. package/src/lib/server/connections/revoke.js.map +1 -0
  85. package/src/lib/server/connections/routes.d.ts +77 -0
  86. package/src/lib/server/connections/routes.js +706 -0
  87. package/src/lib/server/connections/routes.js.map +1 -0
  88. package/src/lib/server/connections/site-records-platform.d.ts +24 -0
  89. package/src/lib/server/connections/site-records-platform.js +94 -0
  90. package/src/lib/server/connections/site-records-platform.js.map +1 -0
  91. package/src/lib/server/connections/site-records.d.ts +95 -0
  92. package/src/lib/server/connections/site-records.js +221 -0
  93. package/src/lib/server/connections/site-records.js.map +1 -0
  94. package/src/lib/server/connections/sync.d.ts +110 -0
  95. package/src/lib/server/connections/sync.js +414 -0
  96. package/src/lib/server/connections/sync.js.map +1 -0
  97. package/src/lib/server/install-plugin.js +56 -6
  98. package/src/lib/server/install-plugin.js.map +1 -1
  99. package/src/lib/server/publish-plugin.js +5 -2
  100. package/src/lib/server/publish-plugin.js.map +1 -1
  101. package/src/lib/server/revenue-source.js +6 -5
  102. package/src/lib/server/revenue-source.js.map +1 -1
  103. package/src/lib/server.js +60 -0
  104. package/src/lib/server.js.map +1 -1
  105. package/src/lib/testing/memory-firestore.d.ts +34 -0
  106. package/src/lib/testing/memory-firestore.js +250 -0
  107. package/src/lib/testing/memory-firestore.js.map +1 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n registerBillingWebhookHandler,\n registerPluginApiRoute,\n registerCustomFieldType,\n} from '@aglyn/aglyn/server'\n// Its own subpath, never the plugin-manager barrel: what a published page\n// does not need, it must not import.\nimport { registerPluginRouteMetadata } from '@aglyn/aglyn/plugin-manager/plugin-route-metadata'\nimport { registerPluginArtifactInventory } from '@aglyn/aglyn/plugin-manager/plugin-artifact-inventory'\nimport { registerTaxReturnSource } from '@aglyn/aglyn/plugin-manager/plugin-tax-return-sources'\nimport { registerRevenueSource } from '@aglyn/aglyn/plugin-manager/plugin-revenue-sources'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { marketplaceBillingWebhookHandler } from './server/billing-webhook'\nimport { registerMarketplaceLockdown } from './server/publisher-lockdown'\nimport { publishPluginHandler } from './server/publish-plugin'\nimport { verificationRequestHandler } from './server/verification-request'\nimport { checkoutHandler } from './server/checkout'\nimport { payHandler } from './server/pay'\nimport { publisherStandingHandler } from './server/publisher-standing'\nimport { starterPublishFactsHandler } from './server/starter-publish-facts'\nimport { connectHandler } from './server/connect'\nimport { installHandler } from './server/install'\nimport { installPluginHandler } from './server/install-plugin'\nimport { listingVersionsHandler } from './server/listing-versions'\nimport { RATING_FIELD } from './model/rating-field'\nimport { installDatasetSchemaHandler } from './server/install-dataset-schema'\nimport { installEmailStarterHandler } from './server/install-email-starter'\nimport { installEmailTemplateHandler } from './server/install-email-template'\nimport { installLayoutHandler } from './server/install-layout'\nimport { installTemplateHandler } from './server/install-template'\nimport { installThemeHandler } from './server/install-theme'\nimport { previewImageHandler } from './server/preview-image'\nimport { publishHandler } from './server/publish'\nimport { marketplaceArtifactInventory } from './server/artifact-inventory'\nimport { marketplaceTaxReturnSource } from './server/tax-return-source'\nimport { marketplaceRevenueSource } from './server/revenue-source'\nimport { marketplaceAdminReports } from './server/admin-reports'\nimport { marketplaceAdminReviews } from './server/admin-reviews'\nimport { marketplaceAdminOverview } from './server/admin-overview'\nimport { marketplaceAdminTrust } from './server/admin-trust'\nimport { reportHandler } from './server/report'\nimport { reviewsHandler } from './server/reviews'\nimport { publisherProfileSaveHandler } from './server/publisher-profile-save'\nimport { publishDatasetSchemaHandler } from './server/publish-dataset-schema'\nimport { publishEmailStarterHandler } from './server/publish-email-starter'\nimport { publishEmailTemplateHandler } from './server/publish-email-template'\nimport { publishLayoutHandler } from './server/publish-layout'\nimport { publishStarterHandler } from './server/publish-starter'\nimport { marketplaceStarterAnswers, marketplaceStarters } from './server/starters'\nimport { publishTemplateHandler } from './server/publish-template'\nimport { publishThemeHandler } from './server/publish-theme'\nimport { updateArtifactHandler } from './server/update-artifact'\n\n/**\n * Registers the marketplace plugin's console-side API routes (AGL-396):\n * marketplace publish/install of templates and plugins, and the Stripe\n * Connect + checkout flows for paid listings.\n *\n * Upload-bodied routes register here too. The note that used to sit here —\n * that they had to stay as named console routes because the dispatcher\n * \"can't grant per-route bodyParser limits\" — was a Pages Router leftover:\n * `runLegacyHandler` reads the request through the same\n * `pluginRequestFromWeb` a named App Router route would, and imposes no\n * limit of its own. publish-plugin's 8 MB bundle has been going through the\n * dispatcher the whole time.\n */\nexport function registerMarketplaceConsoleApi(): void {\n // Server side of the rating custom field (AGL-434): validators run\n // on import/write paths even when no client loaded the plugin.\n registerCustomFieldType(RATING_FIELD)\n /*\n * What a listing link unfurls as (AGL-876, handed to the platform by\n * AGL-3080).\n *\n * The card used to be built by a hand-written console route with a server\n * layout of its own, which is what kept that route out of the generic\n * plugin route — moving it would have dropped every listing's card with\n * nothing red. The shell asks this instead, so the card survives the move\n * and no console file reads `marketplaceListings` to build a head.\n *\n * One segment and one only: `/{org}/marketplace/{listingId}`. The hub, the\n * publish page and every other address under this route answer `null`,\n * which leaves the shell's own title exactly as it was.\n */\n registerPluginRouteMetadata(\n {\n route: 'marketplace',\n resolve: async (segments) => {\n if (segments.length !== 1) return null\n const { readListingForSocialCard } = await import(\n './server/listing-social-card.server'\n )\n const { listingSocialCard } = await import('./model/listing-social-card')\n return listingSocialCard(await readListingForSocialCard(segments[0]))\n },\n },\n // Named, because this registrar is called directly by the app's server\n // loader rather than from inside a plugin `register` fn, where the\n // loader's owner marker would be set.\n { pluginId: BUNDLE_ID },\n )\n /*\n * Who claims the bytes in the artifacts bucket (AGL-3080).\n *\n * The platform's two scheduled sweeps run from `/api/admin` routes that\n * used to walk `pluginVersions` and `marketplaceListings` themselves. They\n * ask here now — and an unregistered inventory REFUSES both runs rather\n * than reporting an empty bucket, which is the whole point of the\n * contract's shape.\n */\n registerPluginArtifactInventory(marketplaceArtifactInventory, {\n pluginId: BUNDLE_ID,\n })\n /*\n * Its sales on the operator's own sales tax return (AGL-3080): the tax a\n * marketplace charge adds on the platform's own account. The staff return\n * awaits this surface before it asks, and refuses to be filed without this\n * source — the marketplace declares `taxReturnSource`.\n */\n registerTaxReturnSource(marketplaceTaxReturnSource, { pluginId: BUNDLE_ID })\n // …and the commission its sales earn the operator, on the staff revenue\n // report — declared `revenueSource`, so a missing registration is named as\n // unread there rather than counted as zero.\n registerRevenueSource(marketplaceRevenueSource, { pluginId: BUNDLE_ID })\n registerPluginApiRoute('marketplace/checkout', checkoutHandler)\n registerPluginApiRoute('marketplace/pay', payHandler)\n registerPluginApiRoute('marketplace/publisher-standing', publisherStandingHandler)\n registerPluginApiRoute('marketplace/connect', connectHandler)\n registerPluginApiRoute('marketplace/install', installHandler)\n registerPluginApiRoute('marketplace/install-plugin', installPluginHandler)\n registerPluginApiRoute('marketplace/install-layout', installLayoutHandler)\n registerPluginApiRoute('marketplace/install-template', installTemplateHandler)\n // A theme install DOES change the running site (AGL-1020) — it is the site's\n // appearance — so this route also owns the ways back: `revert` and `reset`.\n registerPluginApiRoute('marketplace/install-theme', installThemeHandler)\n registerPluginApiRoute(\n 'marketplace/install-dataset-schema',\n installDatasetSchemaHandler,\n )\n registerPluginApiRoute(\n 'marketplace/install-email-starter',\n installEmailStarterHandler,\n )\n registerPluginApiRoute(\n 'marketplace/install-email-template',\n installEmailTemplateHandler,\n )\n // Updating a copied artifact is its own route (AGL-1018), not a flag on\n // install: install writes the publisher's version, this one reconciles it\n // with a copy that has diverged and refuses to overwrite silently.\n registerPluginApiRoute('marketplace/update-artifact', updateArtifactHandler)\n registerPluginApiRoute('marketplace/listing-versions', listingVersionsHandler)\n registerPluginApiRoute('marketplace/preview-image', previewImageHandler)\n registerPluginApiRoute('marketplace/publish', publishHandler)\n registerPluginApiRoute('marketplace/report', reportHandler)\n /*\n * The staff end of that button (AGL-2310), moved out of\n * `apps/console/app/api/admin/` by AGL-3080. `web:` because it is a plain\n * fetch from this plugin's own staff page, not a plugin-request handler —\n * the same shape the AI plugin's `ai/admin/*` routes use, and for the same\n * reason: a staff route names no host, so there is no subject to resolve.\n */\n registerPluginApiRoute('marketplace/admin/reports', {\n web: marketplaceAdminReports,\n })\n // The review queue (AGL-432, moved by AGL-3080). Same shape and the same\n // reason: a staff route names no host, so there is no subject to resolve.\n registerPluginApiRoute('marketplace/admin/reviews', {\n web: marketplaceAdminReviews,\n })\n // Realm trust (AGL-420, moved by AGL-3080). Super-staff only, and the\n // SIGNATURE comes from the shell — the key is the console's and stays\n // there. See `server/admin-trust.ts`.\n registerPluginApiRoute('marketplace/admin/trust', {\n web: marketplaceAdminTrust,\n })\n // The staff overview's marketplace cards (AGL-3080): purchases and the\n // refund-reversal recovery queue. Staff-gated like the queues above.\n registerPluginApiRoute('marketplace/admin/overview', {\n web: marketplaceAdminOverview,\n })\n registerPluginApiRoute('marketplace/reviews', reviewsHandler)\n registerPluginApiRoute(\n 'marketplace/publisher-profile',\n publisherProfileSaveHandler,\n )\n registerPluginApiRoute(\n 'marketplace/verification-request',\n verificationRequestHandler,\n )\n registerPluginApiRoute('marketplace/publish-layout', publishLayoutHandler)\n registerPluginApiRoute('marketplace/publish-template', publishTemplateHandler)\n // A whole site as a site starter, picked in \"Create site\" (AGL-4049).\n registerPluginApiRoute('marketplace/publish-starter', publishStarterHandler)\n // What that publish would capture and what stands in its way, for the native\n // apps, which cannot work out a site's built-in theme for themselves.\n registerPluginApiRoute('marketplace/starter-publish-facts', starterPublishFactsHandler)\n /*\n * And the search \"Choose your starter\" lists them from (AGL-4049):\n * summaries only, behind `hosts.create` and `release_site_starters`. `web:`\n * because it is a plain GET from this plugin's own widget that names a\n * workspace rather than a site; the subject is that workspace, so the\n * release gate in front asks about the right organization.\n */\n registerPluginApiRoute(\n 'marketplace/starters',\n { web: marketplaceStarters },\n { subject: (request) => ({ orgId: new URL(request.url).searchParams.get('orgId') || null }) },\n )\n /*\n * And an AI starter's answers, once one is picked (AGL-4049 phase 4): what\n * fills the AI start's questions, behind the same gates and the starter's\n * purchase. The same shape and subject as the search.\n */\n registerPluginApiRoute(\n 'marketplace/starters/answers',\n { web: marketplaceStarterAnswers },\n { subject: (request) => ({ orgId: new URL(request.url).searchParams.get('orgId') || null }) },\n )\n registerPluginApiRoute('marketplace/publish-theme', publishThemeHandler)\n registerPluginApiRoute(\n 'marketplace/publish-dataset-schema',\n publishDatasetSchemaHandler,\n )\n registerPluginApiRoute(\n 'marketplace/publish-email-starter',\n publishEmailStarterHandler,\n )\n registerPluginApiRoute(\n 'marketplace/publish-email-template',\n publishEmailTemplateHandler,\n )\n // Relocated console routes (AGL-418): URLs preserved via the dispatcher.\n registerPluginApiRoute('marketplace/publish-plugin', publishPluginHandler)\n // Marketplace purchases ride the platform Stripe webhook (AGL-418).\n registerBillingWebhookHandler(marketplaceBillingWebhookHandler)\n // A workspace lock reaches the publisher's payout account and its\n // listings (AGL-3365).\n registerMarketplaceLockdown()\n}\n\n// Type-only (AGL-3080): the plugin's entitlement keys, declared by module\n// augmentation, for every program that loads this entry point.\nexport type { marketplacePlanEntitlements } from './plan-entitlements'\n"],"names":["registerBillingWebhookHandler","registerPluginApiRoute","registerCustomFieldType","registerPluginRouteMetadata","registerPluginArtifactInventory","registerTaxReturnSource","registerRevenueSource","BUNDLE_ID","marketplaceBillingWebhookHandler","registerMarketplaceLockdown","publishPluginHandler","verificationRequestHandler","checkoutHandler","payHandler","publisherStandingHandler","starterPublishFactsHandler","connectHandler","installHandler","installPluginHandler","listingVersionsHandler","RATING_FIELD","installDatasetSchemaHandler","installEmailStarterHandler","installEmailTemplateHandler","installLayoutHandler","installTemplateHandler","installThemeHandler","previewImageHandler","publishHandler","marketplaceArtifactInventory","marketplaceTaxReturnSource","marketplaceRevenueSource","marketplaceAdminReports","marketplaceAdminReviews","marketplaceAdminOverview","marketplaceAdminTrust","reportHandler","reviewsHandler","publisherProfileSaveHandler","publishDatasetSchemaHandler","publishEmailStarterHandler","publishEmailTemplateHandler","publishLayoutHandler","publishStarterHandler","marketplaceStarterAnswers","marketplaceStarters","publishTemplateHandler","publishThemeHandler","updateArtifactHandler","registerMarketplaceConsoleApi","route","resolve","segments","length","readListingForSocialCard","listingSocialCard","pluginId","web","subject","request","orgId","URL","url","searchParams","get"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../libs/plugins/marketplace/src/lib/server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n registerBillingWebhookHandler,\n registerPluginApiRoute,\n registerCustomFieldType,\n} from '@aglyn/aglyn/server'\n// Its own subpath, never the plugin-manager barrel: what a published page\n// does not need, it must not import.\nimport { registerPluginRouteMetadata } from '@aglyn/aglyn/plugin-manager/plugin-route-metadata'\nimport { registerPluginArtifactInventory } from '@aglyn/aglyn/plugin-manager/plugin-artifact-inventory'\nimport { registerTaxReturnSource } from '@aglyn/aglyn/plugin-manager/plugin-tax-return-sources'\nimport { registerRevenueSource } from '@aglyn/aglyn/plugin-manager/plugin-revenue-sources'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport { PLUGIN_CONNECTIONS_API_ROUTES } from './model/plugin-connections'\nimport { marketplaceBillingWebhookHandler } from './server/billing-webhook'\nimport { registerMarketplaceLockdown } from './server/publisher-lockdown'\nimport { publishPluginHandler } from './server/publish-plugin'\nimport { verificationRequestHandler } from './server/verification-request'\nimport { checkoutHandler } from './server/checkout'\nimport { payHandler } from './server/pay'\nimport { publisherStandingHandler } from './server/publisher-standing'\nimport { starterPublishFactsHandler } from './server/starter-publish-facts'\nimport { connectHandler } from './server/connect'\nimport { installHandler } from './server/install'\nimport { installPluginHandler } from './server/install-plugin'\nimport { listingVersionsHandler } from './server/listing-versions'\nimport { RATING_FIELD } from './model/rating-field'\nimport { installDatasetSchemaHandler } from './server/install-dataset-schema'\nimport { installEmailStarterHandler } from './server/install-email-starter'\nimport { installEmailTemplateHandler } from './server/install-email-template'\nimport { installLayoutHandler } from './server/install-layout'\nimport { installTemplateHandler } from './server/install-template'\nimport { installThemeHandler } from './server/install-theme'\nimport { previewImageHandler } from './server/preview-image'\nimport { publishHandler } from './server/publish'\nimport { marketplaceArtifactInventory } from './server/artifact-inventory'\nimport { marketplaceTaxReturnSource } from './server/tax-return-source'\nimport { marketplaceRevenueSource } from './server/revenue-source'\nimport { marketplaceAdminReports } from './server/admin-reports'\nimport { marketplaceAdminReviews } from './server/admin-reviews'\nimport { marketplaceAdminOverview } from './server/admin-overview'\nimport { marketplaceAdminTrust } from './server/admin-trust'\nimport { reportHandler } from './server/report'\nimport { reviewsHandler } from './server/reviews'\nimport { publisherProfileSaveHandler } from './server/publisher-profile-save'\nimport { publishDatasetSchemaHandler } from './server/publish-dataset-schema'\nimport { publishEmailStarterHandler } from './server/publish-email-starter'\nimport { publishEmailTemplateHandler } from './server/publish-email-template'\nimport { publishLayoutHandler } from './server/publish-layout'\nimport { publishStarterHandler } from './server/publish-starter'\nimport { marketplaceStarterAnswers, marketplaceStarters } from './server/starters'\nimport { publishTemplateHandler } from './server/publish-template'\nimport { publishThemeHandler } from './server/publish-theme'\nimport { updateArtifactHandler } from './server/update-artifact'\n\n/**\n * Registers the marketplace plugin's console-side API routes (AGL-396):\n * marketplace publish/install of templates and plugins, and the Stripe\n * Connect + checkout flows for paid listings.\n *\n * Upload-bodied routes register here too. The note that used to sit here —\n * that they had to stay as named console routes because the dispatcher\n * \"can't grant per-route bodyParser limits\" — was a Pages Router leftover:\n * `runLegacyHandler` reads the request through the same\n * `pluginRequestFromWeb` a named App Router route would, and imposes no\n * limit of its own. publish-plugin's 8 MB bundle has been going through the\n * dispatcher the whole time.\n */\nexport function registerMarketplaceConsoleApi(): void {\n // Server side of the rating custom field (AGL-434): validators run\n // on import/write paths even when no client loaded the plugin.\n registerCustomFieldType(RATING_FIELD)\n /*\n * What a listing link unfurls as (AGL-876, handed to the platform by\n * AGL-3080).\n *\n * The card used to be built by a hand-written console route with a server\n * layout of its own, which is what kept that route out of the generic\n * plugin route — moving it would have dropped every listing's card with\n * nothing red. The shell asks this instead, so the card survives the move\n * and no console file reads `marketplaceListings` to build a head.\n *\n * One segment and one only: `/{org}/marketplace/{listingId}`. The hub, the\n * publish page and every other address under this route answer `null`,\n * which leaves the shell's own title exactly as it was.\n */\n registerPluginRouteMetadata(\n {\n route: 'marketplace',\n resolve: async (segments) => {\n if (segments.length !== 1) return null\n const { readListingForSocialCard } = await import(\n './server/listing-social-card.server'\n )\n const { listingSocialCard } = await import('./model/listing-social-card')\n return listingSocialCard(await readListingForSocialCard(segments[0]))\n },\n },\n // Named, because this registrar is called directly by the app's server\n // loader rather than from inside a plugin `register` fn, where the\n // loader's owner marker would be set.\n { pluginId: BUNDLE_ID },\n )\n /*\n * Who claims the bytes in the artifacts bucket (AGL-3080).\n *\n * The platform's two scheduled sweeps run from `/api/admin` routes that\n * used to walk `pluginVersions` and `marketplaceListings` themselves. They\n * ask here now — and an unregistered inventory REFUSES both runs rather\n * than reporting an empty bucket, which is the whole point of the\n * contract's shape.\n */\n registerPluginArtifactInventory(marketplaceArtifactInventory, {\n pluginId: BUNDLE_ID,\n })\n /*\n * Its sales on the operator's own sales tax return (AGL-3080): the tax a\n * marketplace charge adds on the platform's own account. The staff return\n * awaits this surface before it asks, and refuses to be filed without this\n * source — the marketplace declares `taxReturnSource`.\n */\n registerTaxReturnSource(marketplaceTaxReturnSource, { pluginId: BUNDLE_ID })\n // …and the commission its sales earn the operator, on the staff revenue\n // report — declared `revenueSource`, so a missing registration is named as\n // unread there rather than counted as zero.\n registerRevenueSource(marketplaceRevenueSource, { pluginId: BUNDLE_ID })\n registerPluginApiRoute('marketplace/checkout', checkoutHandler)\n registerPluginApiRoute('marketplace/pay', payHandler)\n registerPluginApiRoute('marketplace/publisher-standing', publisherStandingHandler)\n registerPluginApiRoute('marketplace/connect', connectHandler)\n registerPluginApiRoute('marketplace/install', installHandler)\n registerPluginApiRoute('marketplace/install-plugin', installPluginHandler)\n registerPluginApiRoute('marketplace/install-layout', installLayoutHandler)\n registerPluginApiRoute('marketplace/install-template', installTemplateHandler)\n // A theme install DOES change the running site (AGL-1020) — it is the site's\n // appearance — so this route also owns the ways back: `revert` and `reset`.\n registerPluginApiRoute('marketplace/install-theme', installThemeHandler)\n registerPluginApiRoute(\n 'marketplace/install-dataset-schema',\n installDatasetSchemaHandler,\n )\n registerPluginApiRoute(\n 'marketplace/install-email-starter',\n installEmailStarterHandler,\n )\n registerPluginApiRoute(\n 'marketplace/install-email-template',\n installEmailTemplateHandler,\n )\n // Updating a copied artifact is its own route (AGL-1018), not a flag on\n // install: install writes the publisher's version, this one reconciles it\n // with a copy that has diverged and refuses to overwrite silently.\n registerPluginApiRoute('marketplace/update-artifact', updateArtifactHandler)\n registerPluginApiRoute('marketplace/listing-versions', listingVersionsHandler)\n registerPluginApiRoute('marketplace/preview-image', previewImageHandler)\n registerPluginApiRoute('marketplace/publish', publishHandler)\n registerPluginApiRoute('marketplace/report', reportHandler)\n /*\n * The staff end of that button (AGL-2310), moved out of\n * `apps/console/app/api/admin/` by AGL-3080. `web:` because it is a plain\n * fetch from this plugin's own staff page, not a plugin-request handler —\n * the same shape the AI plugin's `ai/admin/*` routes use, and for the same\n * reason: a staff route names no host, so there is no subject to resolve.\n */\n registerPluginApiRoute('marketplace/admin/reports', {\n web: marketplaceAdminReports,\n })\n // The review queue (AGL-432, moved by AGL-3080). Same shape and the same\n // reason: a staff route names no host, so there is no subject to resolve.\n registerPluginApiRoute('marketplace/admin/reviews', {\n web: marketplaceAdminReviews,\n })\n // Realm trust (AGL-420, moved by AGL-3080). Super-staff only, and the\n // SIGNATURE comes from the shell — the key is the console's and stays\n // there. See `server/admin-trust.ts`.\n registerPluginApiRoute('marketplace/admin/trust', {\n web: marketplaceAdminTrust,\n })\n // The staff overview's marketplace cards (AGL-3080): purchases and the\n // refund-reversal recovery queue. Staff-gated like the queues above.\n registerPluginApiRoute('marketplace/admin/overview', {\n web: marketplaceAdminOverview,\n })\n registerPluginApiRoute('marketplace/reviews', reviewsHandler)\n registerPluginApiRoute(\n 'marketplace/publisher-profile',\n publisherProfileSaveHandler,\n )\n registerPluginApiRoute(\n 'marketplace/verification-request',\n verificationRequestHandler,\n )\n registerPluginApiRoute('marketplace/publish-layout', publishLayoutHandler)\n registerPluginApiRoute('marketplace/publish-template', publishTemplateHandler)\n // A whole site as a site starter, picked in \"Create site\" (AGL-4049).\n registerPluginApiRoute('marketplace/publish-starter', publishStarterHandler)\n // What that publish would capture and what stands in its way, for the native\n // apps, which cannot work out a site's built-in theme for themselves.\n registerPluginApiRoute('marketplace/starter-publish-facts', starterPublishFactsHandler)\n /*\n * And the search \"Choose your starter\" lists them from (AGL-4049):\n * summaries only, behind `hosts.create` and `release_site_starters`. `web:`\n * because it is a plain GET from this plugin's own widget that names a\n * workspace rather than a site; the subject is that workspace, so the\n * release gate in front asks about the right organization.\n */\n registerPluginApiRoute(\n 'marketplace/starters',\n { web: marketplaceStarters },\n { subject: (request) => ({ orgId: new URL(request.url).searchParams.get('orgId') || null }) },\n )\n /*\n * And an AI starter's answers, once one is picked (AGL-4049 phase 4): what\n * fills the AI start's questions, behind the same gates and the starter's\n * purchase. The same shape and subject as the search.\n */\n registerPluginApiRoute(\n 'marketplace/starters/answers',\n { web: marketplaceStarterAnswers },\n { subject: (request) => ({ orgId: new URL(request.url).searchParams.get('orgId') || null }) },\n )\n registerPluginApiRoute('marketplace/publish-theme', publishThemeHandler)\n registerPluginApiRoute(\n 'marketplace/publish-dataset-schema',\n publishDatasetSchemaHandler,\n )\n registerPluginApiRoute(\n 'marketplace/publish-email-starter',\n publishEmailStarterHandler,\n )\n registerPluginApiRoute(\n 'marketplace/publish-email-template',\n publishEmailTemplateHandler,\n )\n // Relocated console routes (AGL-418): URLs preserved via the dispatcher.\n registerPluginApiRoute('marketplace/publish-plugin', publishPluginHandler)\n // Marketplace purchases ride the platform Stripe webhook (AGL-418).\n registerBillingWebhookHandler(marketplaceBillingWebhookHandler)\n // A workspace lock reaches the publisher's payout account and its\n // listings (AGL-3365).\n registerMarketplaceLockdown()\n registerPluginConnectionsApi()\n}\n\ntype ConnectionRoutes = typeof import('./server/connections/routes')\n\nconst connectionRoute =\n (pick: (routes: ConnectionRoutes) => (request: Request) => Promise<Response>) =>\n async (request: Request) =>\n pick(await import('./server/connections/routes'))(request)\n\n/**\n * Declared connections (AGL-4193): the platform runs the OAuth connect, holds\n * the sealed grant and lists what it reaches for any marketplace plugin whose\n * manifest declares a connection. Each module loads with its route's first\n * request. The callback is a provider's redirect, with no bearer token and no\n * site: its workspace and member come from the signed state, so the release\n * gate asks about the right workspace. Its path is registered as a redirect\n * URI at providers and never moves.\n */\nfunction registerPluginConnectionsApi(): void {\n const routes: Array<[string, Parameters<typeof connectionRoute>[0]]> = [\n [PLUGIN_CONNECTIONS_API_ROUTES.connectStart, (routes) => routes.connectStartRoute],\n [PLUGIN_CONNECTIONS_API_ROUTES.resources, (routes) => routes.resourcesRoute],\n [PLUGIN_CONNECTIONS_API_ROUTES.choose, (routes) => routes.chooseRoute],\n [PLUGIN_CONNECTIONS_API_ROUTES.disconnect, (routes) => routes.disconnectRoute],\n [PLUGIN_CONNECTIONS_API_ROUTES.status, (routes) => routes.statusRoute],\n [PLUGIN_CONNECTIONS_API_ROUTES.credentials, (routes) => routes.credentialsRoute],\n [PLUGIN_CONNECTIONS_API_ROUTES.sync, (routes) => routes.syncNowRoute],\n ]\n for (const [path, pick] of routes) {\n const handler = connectionRoute(pick)\n registerPluginApiRoute(path, { web: (request) => handler(request) })\n }\n // The record a connection's sync last wrote, for the editor's canvas\n // (AGL-4195); a published page has it with the page.\n registerPluginApiRoute(PLUGIN_CONNECTIONS_API_ROUTES.record, {\n web: async (request) => (await import('./server/connections/record-routes')).recordRoute(request),\n })\n const callback = connectionRoute((routes) => routes.connectCallbackRoute)\n registerPluginApiRoute(\n PLUGIN_CONNECTIONS_API_ROUTES.connectCallback,\n { web: (request) => callback(request) },\n {\n subject: async (request) =>\n (await import('./server/connections/routes')).connectCallbackSubject(request),\n },\n )\n}\n\n// Type-only (AGL-3080): the plugin's entitlement keys, declared by module\n// augmentation, for every program that loads this entry point.\nexport type { marketplacePlanEntitlements } from './plan-entitlements'\n"],"names":["registerBillingWebhookHandler","registerPluginApiRoute","registerCustomFieldType","registerPluginRouteMetadata","registerPluginArtifactInventory","registerTaxReturnSource","registerRevenueSource","BUNDLE_ID","PLUGIN_CONNECTIONS_API_ROUTES","marketplaceBillingWebhookHandler","registerMarketplaceLockdown","publishPluginHandler","verificationRequestHandler","checkoutHandler","payHandler","publisherStandingHandler","starterPublishFactsHandler","connectHandler","installHandler","installPluginHandler","listingVersionsHandler","RATING_FIELD","installDatasetSchemaHandler","installEmailStarterHandler","installEmailTemplateHandler","installLayoutHandler","installTemplateHandler","installThemeHandler","previewImageHandler","publishHandler","marketplaceArtifactInventory","marketplaceTaxReturnSource","marketplaceRevenueSource","marketplaceAdminReports","marketplaceAdminReviews","marketplaceAdminOverview","marketplaceAdminTrust","reportHandler","reviewsHandler","publisherProfileSaveHandler","publishDatasetSchemaHandler","publishEmailStarterHandler","publishEmailTemplateHandler","publishLayoutHandler","publishStarterHandler","marketplaceStarterAnswers","marketplaceStarters","publishTemplateHandler","publishThemeHandler","updateArtifactHandler","registerMarketplaceConsoleApi","route","resolve","segments","length","readListingForSocialCard","listingSocialCard","pluginId","web","subject","request","orgId","URL","url","searchParams","get","registerPluginConnectionsApi","connectionRoute","pick","routes","connectStart","connectStartRoute","resources","resourcesRoute","choose","chooseRoute","disconnect","disconnectRoute","status","statusRoute","credentials","credentialsRoute","sync","syncNowRoute","path","handler","record","recordRoute","callback","connectCallbackRoute","connectCallback","connectCallbackSubject"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ /**
18
+ * An in-memory Firestore for this plugin's specs: documents by path,
19
+ * `create()` that refuses an existing document, `update()` that refuses an
20
+ * absent one, equality and range filters, ordering and limits, and
21
+ * transactions whose writes are buffered and applied at commit, one body at
22
+ * a time. Only what this plugin's server half calls. A range filter, as in
23
+ * Firestore, never matches a value of another type (`null <= 5` does not).
24
+ */
25
+ type Data = Record<string, any>;
26
+ export interface MemoryFirestore {
27
+ docs: Map<string, Data>;
28
+ collection(name: string): any;
29
+ collectionGroup(name: string): any;
30
+ runTransaction<T>(fn: (transaction: any) => Promise<T>): Promise<T>;
31
+ batch(): any;
32
+ }
33
+ export declare function createMemoryFirestore(): MemoryFirestore;
34
+ export {};
@@ -0,0 +1,250 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ /*
17
+ * Copied from the sales-channels plugin's spec helper (AGL-4193): one plugin
18
+ * never imports another, specs included. One change: `update()` replaces a
19
+ * named field whole, as Firestore does, rather than merging a map into it.
20
+ */ /**
21
+ * An in-memory Firestore for this plugin's specs: documents by path,
22
+ * `create()` that refuses an existing document, `update()` that refuses an
23
+ * absent one, equality and range filters, ordering and limits, and
24
+ * transactions whose writes are buffered and applied at commit, one body at
25
+ * a time. Only what this plugin's server half calls. A range filter, as in
26
+ * Firestore, never matches a value of another type (`null <= 5` does not).
27
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
28
+ export function createMemoryFirestore() {
29
+ const docs = new Map();
30
+ let generated = 0;
31
+ const clone = (value)=>value === undefined ? value : JSON.parse(JSON.stringify(value));
32
+ const snapshot = (path)=>{
33
+ const data = docs.get(path);
34
+ return {
35
+ id: path.split('/').pop(),
36
+ exists: data !== undefined,
37
+ data: ()=>clone(data),
38
+ get: (field)=>field.split('.').reduce((at, key)=>at == null ? void 0 : at[key], data),
39
+ ref: docRef(path)
40
+ };
41
+ };
42
+ const applyMerge = (existing, value)=>{
43
+ const next = _extends({}, existing);
44
+ for (const [key, entry] of Object.entries(value)){
45
+ if (key.includes('.')) {
46
+ const parts = key.split('.');
47
+ let at = next;
48
+ for (const part of parts.slice(0, -1)){
49
+ var _at_part;
50
+ at[part] = _extends({}, (_at_part = at[part]) != null ? _at_part : {});
51
+ at = at[part];
52
+ }
53
+ at[parts[parts.length - 1]] = entry;
54
+ } else if (entry && typeof entry === 'object' && !Array.isArray(entry) && existing[key] && typeof existing[key] === 'object') {
55
+ next[key] = applyMerge(existing[key], entry);
56
+ } else {
57
+ next[key] = entry;
58
+ }
59
+ }
60
+ return next;
61
+ };
62
+ const write = {
63
+ set (path, value, options) {
64
+ const existing = docs.get(path);
65
+ docs.set(path, clone((options == null ? void 0 : options.merge) && existing ? applyMerge(existing, value) : value));
66
+ },
67
+ update (path, value) {
68
+ const existing = docs.get(path);
69
+ if (existing === undefined) {
70
+ throw Object.assign(new Error(`NOT_FOUND: ${path}`), {
71
+ code: 5
72
+ });
73
+ }
74
+ // Firestore's `update()` replaces a named field whole, map or not; only a
75
+ // dotted path reaches inside one. (`set(…, { merge: true })` is the
76
+ // call that merges maps.)
77
+ const dotted = Object.fromEntries(Object.entries(value).filter(([key])=>key.includes('.')));
78
+ const whole = Object.fromEntries(Object.entries(value).filter(([key])=>!key.includes('.')));
79
+ docs.set(path, clone(applyMerge(_extends({}, existing, whole), dotted)));
80
+ },
81
+ create (path, value) {
82
+ if (docs.has(path)) throw Object.assign(new Error(`ALREADY_EXISTS: ${path}`), {
83
+ code: 6
84
+ });
85
+ docs.set(path, clone(value));
86
+ },
87
+ delete (path) {
88
+ docs.delete(path);
89
+ }
90
+ };
91
+ function docRef(path) {
92
+ return {
93
+ id: path.split('/').pop(),
94
+ path,
95
+ get: async ()=>snapshot(path),
96
+ set: async (value, options)=>write.set(path, value, options),
97
+ update: async (value)=>write.update(path, value),
98
+ create: async (value)=>write.create(path, value),
99
+ delete: async ()=>write.delete(path),
100
+ collection: (name)=>collectionRef(`${path}/${name}`),
101
+ /** The collection it sits in, whose `parent` is the document above, or `null` at the top. */ get parent () {
102
+ const segments = path.split('/');
103
+ const above = segments.slice(0, -2).join('/');
104
+ return {
105
+ id: segments[segments.length - 2],
106
+ path: segments.slice(0, -1).join('/'),
107
+ parent: above ? docRef(above) : null
108
+ };
109
+ }
110
+ };
111
+ }
112
+ function query(path, filters, order, max) {
113
+ const matches = (data)=>filters.every(([field, op, expected])=>{
114
+ const actual = field.split('.').reduce((at, key)=>at == null ? void 0 : at[key], data);
115
+ const comparable = actual !== null && actual !== undefined && typeof actual === typeof expected;
116
+ if ([
117
+ '<',
118
+ '<=',
119
+ '>',
120
+ '>='
121
+ ].includes(op) && !comparable) return false;
122
+ switch(op){
123
+ case '==':
124
+ return actual === expected;
125
+ case '!=':
126
+ return actual !== expected;
127
+ case '<':
128
+ return actual < expected;
129
+ case '<=':
130
+ return actual <= expected;
131
+ case '>':
132
+ return actual > expected;
133
+ case '>=':
134
+ return actual >= expected;
135
+ case 'in':
136
+ return expected.includes(actual);
137
+ case 'array-contains':
138
+ return Array.isArray(actual) && actual.includes(expected);
139
+ default:
140
+ throw new Error(`unsupported op ${op}`);
141
+ }
142
+ });
143
+ const inScope = (key)=>{
144
+ if (typeof path !== 'string') {
145
+ const segments = key.split('/');
146
+ return segments.length % 2 === 0 && segments[segments.length - 2] === path.group;
147
+ }
148
+ const prefix = `${path}/`;
149
+ return key.startsWith(prefix) && !key.slice(prefix.length).includes('/');
150
+ };
151
+ const run = ()=>{
152
+ let rows = [
153
+ ...docs.entries()
154
+ ].filter(([key])=>inScope(key)).filter(([, data])=>matches(data)).map(([key])=>snapshot(key));
155
+ for (const [field, direction] of [
156
+ ...order
157
+ ].reverse()){
158
+ rows = rows.sort((a, b)=>{
159
+ const left = a.get(field);
160
+ const right = b.get(field);
161
+ const compared = left < right ? -1 : left > right ? 1 : 0;
162
+ return direction === 'desc' ? -compared : compared;
163
+ });
164
+ }
165
+ if (max !== null) rows = rows.slice(0, max);
166
+ return {
167
+ docs: rows,
168
+ empty: rows.length === 0,
169
+ size: rows.length
170
+ };
171
+ };
172
+ return {
173
+ where: (field, op, value)=>query(path, [
174
+ ...filters,
175
+ [
176
+ field,
177
+ op,
178
+ value
179
+ ]
180
+ ], order, max),
181
+ orderBy: (field, direction = 'asc')=>query(path, filters, [
182
+ ...order,
183
+ [
184
+ field,
185
+ direction
186
+ ]
187
+ ], max),
188
+ limit: (count)=>query(path, filters, order, count),
189
+ get: async ()=>run()
190
+ };
191
+ }
192
+ function collectionRef(path) {
193
+ return _extends({
194
+ path,
195
+ doc: (id)=>docRef(`${path}/${id != null ? id : `generated-${++generated}`}`)
196
+ }, query(path, [], [], null));
197
+ }
198
+ let queue = Promise.resolve();
199
+ return {
200
+ docs,
201
+ collection: (name)=>collectionRef(name),
202
+ collectionGroup: (name)=>query({
203
+ group: name
204
+ }, [], [], null),
205
+ runTransaction (fn) {
206
+ const run = queue.then(async ()=>{
207
+ const buffered = [];
208
+ const transaction = {
209
+ get: async (ref)=>ref.get ? ref.get() : ref,
210
+ set: (ref, value, options)=>{
211
+ buffered.push(()=>write.set(ref.path, value, options));
212
+ },
213
+ update: (ref, value)=>{
214
+ buffered.push(()=>write.update(ref.path, value));
215
+ },
216
+ create: (ref, value)=>{
217
+ buffered.push(()=>write.create(ref.path, value));
218
+ },
219
+ delete: (ref)=>{
220
+ buffered.push(()=>write.delete(ref.path));
221
+ }
222
+ };
223
+ const result = await fn(transaction);
224
+ for (const apply of buffered)apply();
225
+ return result;
226
+ });
227
+ queue = run.catch(()=>undefined);
228
+ return run;
229
+ },
230
+ batch () {
231
+ const buffered = [];
232
+ return {
233
+ set: (ref, value, options)=>{
234
+ buffered.push(()=>write.set(ref.path, value, options));
235
+ },
236
+ update: (ref, value)=>{
237
+ buffered.push(()=>write.update(ref.path, value));
238
+ },
239
+ delete: (ref)=>{
240
+ buffered.push(()=>write.delete(ref.path));
241
+ },
242
+ commit: async ()=>{
243
+ for (const apply of buffered)apply();
244
+ }
245
+ };
246
+ }
247
+ };
248
+ }
249
+
250
+ //# sourceMappingURL=memory-firestore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/marketplace/src/lib/testing/memory-firestore.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Copied from the sales-channels plugin's spec helper (AGL-4193): one plugin\n * never imports another, specs included. One change: `update()` replaces a\n * named field whole, as Firestore does, rather than merging a map into it.\n */\n\n/**\n * An in-memory Firestore for this plugin's specs: documents by path,\n * `create()` that refuses an existing document, `update()` that refuses an\n * absent one, equality and range filters, ordering and limits, and\n * transactions whose writes are buffered and applied at commit, one body at\n * a time. Only what this plugin's server half calls. A range filter, as in\n * Firestore, never matches a value of another type (`null <= 5` does not).\n */\n\ntype Data = Record<string, any>\n\nexport interface MemoryFirestore {\n docs: Map<string, Data>\n collection(name: string): any\n collectionGroup(name: string): any\n runTransaction<T>(fn: (transaction: any) => Promise<T>): Promise<T>\n batch(): any\n}\n\nexport function createMemoryFirestore(): MemoryFirestore {\n const docs = new Map<string, Data>()\n let generated = 0\n\n const clone = <T>(value: T): T => (value === undefined ? value : JSON.parse(JSON.stringify(value)))\n\n const snapshot = (path: string) => {\n const data = docs.get(path)\n return {\n id: path.split('/').pop() as string,\n exists: data !== undefined,\n data: () => clone(data),\n get: (field: string) => field.split('.').reduce<any>((at, key) => at?.[key], data),\n ref: docRef(path),\n }\n }\n\n const applyMerge = (existing: Data, value: Data): Data => {\n const next: Data = { ...existing }\n for (const [key, entry] of Object.entries(value)) {\n if (key.includes('.')) {\n const parts = key.split('.')\n let at = next\n for (const part of parts.slice(0, -1)) {\n at[part] = { ...(at[part] ?? {}) }\n at = at[part]\n }\n at[parts[parts.length - 1]] = entry\n } else if (entry && typeof entry === 'object' && !Array.isArray(entry) && existing[key] && typeof existing[key] === 'object') {\n next[key] = applyMerge(existing[key], entry)\n } else {\n next[key] = entry\n }\n }\n return next\n }\n\n const write = {\n set(path: string, value: Data, options?: { merge?: boolean }) {\n const existing = docs.get(path)\n docs.set(path, clone(options?.merge && existing ? applyMerge(existing, value) : value))\n },\n update(path: string, value: Data) {\n const existing = docs.get(path)\n if (existing === undefined) {\n throw Object.assign(new Error(`NOT_FOUND: ${path}`), { code: 5 })\n }\n // Firestore's `update()` replaces a named field whole, map or not; only a\n // dotted path reaches inside one. (`set(…, { merge: true })` is the\n // call that merges maps.)\n const dotted = Object.fromEntries(Object.entries(value).filter(([key]) => key.includes('.')))\n const whole = Object.fromEntries(Object.entries(value).filter(([key]) => !key.includes('.')))\n docs.set(path, clone(applyMerge({ ...existing, ...whole }, dotted)))\n },\n create(path: string, value: Data) {\n if (docs.has(path)) throw Object.assign(new Error(`ALREADY_EXISTS: ${path}`), { code: 6 })\n docs.set(path, clone(value))\n },\n delete(path: string) {\n docs.delete(path)\n },\n }\n\n function docRef(path: string): any {\n return {\n id: path.split('/').pop() as string,\n path,\n get: async () => snapshot(path),\n set: async (value: Data, options?: { merge?: boolean }) => write.set(path, value, options),\n update: async (value: Data) => write.update(path, value),\n create: async (value: Data) => write.create(path, value),\n delete: async () => write.delete(path),\n collection: (name: string) => collectionRef(`${path}/${name}`),\n /** The collection it sits in, whose `parent` is the document above, or `null` at the top. */\n get parent() {\n const segments = path.split('/')\n const above = segments.slice(0, -2).join('/')\n return { id: segments[segments.length - 2], path: segments.slice(0, -1).join('/'), parent: above ? docRef(above) : null }\n },\n }\n }\n\n function query(\n path: string | { group: string },\n filters: Array<[string, string, unknown]>,\n order: Array<[string, 'asc' | 'desc']>,\n max: number | null,\n ): any {\n const matches = (data: Data) =>\n filters.every(([field, op, expected]) => {\n const actual = field.split('.').reduce<any>((at, key) => at?.[key], data)\n const comparable = actual !== null && actual !== undefined && typeof actual === typeof expected\n if (['<', '<=', '>', '>='].includes(op) && !comparable) return false\n switch (op) {\n case '==':\n return actual === expected\n case '!=':\n return actual !== expected\n case '<':\n return actual < (expected as any)\n case '<=':\n return actual <= (expected as any)\n case '>':\n return actual > (expected as any)\n case '>=':\n return actual >= (expected as any)\n case 'in':\n return (expected as unknown[]).includes(actual)\n case 'array-contains':\n return Array.isArray(actual) && actual.includes(expected)\n default:\n throw new Error(`unsupported op ${op}`)\n }\n })\n const inScope = (key: string) => {\n if (typeof path !== 'string') {\n const segments = key.split('/')\n return segments.length % 2 === 0 && segments[segments.length - 2] === path.group\n }\n const prefix = `${path}/`\n return key.startsWith(prefix) && !key.slice(prefix.length).includes('/')\n }\n const run = () => {\n let rows = [...docs.entries()]\n .filter(([key]) => inScope(key))\n .filter(([, data]) => matches(data))\n .map(([key]) => snapshot(key))\n for (const [field, direction] of [...order].reverse()) {\n rows = rows.sort((a, b) => {\n const left = a.get(field)\n const right = b.get(field)\n const compared = left < right ? -1 : left > right ? 1 : 0\n return direction === 'desc' ? -compared : compared\n })\n }\n if (max !== null) rows = rows.slice(0, max)\n return { docs: rows, empty: rows.length === 0, size: rows.length }\n }\n return {\n where: (field: string, op: string, value: unknown) =>\n query(path, [...filters, [field, op, value]], order, max),\n orderBy: (field: string, direction: 'asc' | 'desc' = 'asc') =>\n query(path, filters, [...order, [field, direction]], max),\n limit: (count: number) => query(path, filters, order, count),\n get: async () => run(),\n }\n }\n\n function collectionRef(path: string): any {\n return {\n path,\n doc: (id?: string) => docRef(`${path}/${id ?? `generated-${++generated}`}`),\n ...query(path, [], [], null),\n }\n }\n\n let queue: Promise<unknown> = Promise.resolve()\n\n return {\n docs,\n collection: (name: string) => collectionRef(name),\n collectionGroup: (name: string) => query({ group: name }, [], [], null),\n runTransaction<T>(fn: (transaction: any) => Promise<T>): Promise<T> {\n const run = queue.then(async () => {\n const buffered: Array<() => void> = []\n const transaction = {\n get: async (ref: any) => (ref.get ? ref.get() : ref),\n set: (ref: any, value: Data, options?: { merge?: boolean }) => {\n buffered.push(() => write.set(ref.path, value, options))\n },\n update: (ref: any, value: Data) => {\n buffered.push(() => write.update(ref.path, value))\n },\n create: (ref: any, value: Data) => {\n buffered.push(() => write.create(ref.path, value))\n },\n delete: (ref: any) => {\n buffered.push(() => write.delete(ref.path))\n },\n }\n const result = await fn(transaction)\n for (const apply of buffered) apply()\n return result\n })\n queue = run.catch(() => undefined)\n return run\n },\n batch() {\n const buffered: Array<() => void> = []\n return {\n set: (ref: any, value: Data, options?: { merge?: boolean }) => {\n buffered.push(() => write.set(ref.path, value, options))\n },\n update: (ref: any, value: Data) => {\n buffered.push(() => write.update(ref.path, value))\n },\n delete: (ref: any) => {\n buffered.push(() => write.delete(ref.path))\n },\n commit: async () => {\n for (const apply of buffered) apply()\n },\n }\n },\n }\n}\n"],"names":["createMemoryFirestore","docs","Map","generated","clone","value","undefined","JSON","parse","stringify","snapshot","path","data","get","id","split","pop","exists","field","reduce","at","key","ref","docRef","applyMerge","existing","next","entry","Object","entries","includes","parts","part","slice","length","Array","isArray","write","set","options","merge","update","assign","Error","code","dotted","fromEntries","filter","whole","create","has","delete","collection","name","collectionRef","parent","segments","above","join","query","filters","order","max","matches","every","op","expected","actual","comparable","inScope","group","prefix","startsWith","run","rows","map","direction","reverse","sort","a","b","left","right","compared","empty","size","where","orderBy","limit","count","doc","queue","Promise","resolve","collectionGroup","runTransaction","fn","then","buffered","transaction","push","result","apply","catch","batch","commit"],"mappings":"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"}