astroidjs 0.12.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -42
- package/bin/astroid.mjs +25 -25
- package/dist/analytics/index.d.ts +3 -3
- package/dist/analytics/index.js +9 -9
- package/dist/astro/csp.d.ts +5 -5
- package/dist/astro/csp.js +6 -6
- package/dist/astro/index.js +1 -1
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +5 -5
- package/dist/commerce/adapters.d.ts +6 -6
- package/dist/commerce/adapters.js +9 -9
- package/dist/commerce/checkout-scaffold.d.ts +5 -5
- package/dist/commerce/checkout-scaffold.js +9 -9
- package/dist/commerce/checkout.d.ts +12 -12
- package/dist/commerce/checkout.js +7 -7
- package/dist/commerce/loader.d.ts +2 -2
- package/dist/commerce/loader.js +3 -3
- package/dist/commerce/mirror.d.ts +4 -4
- package/dist/commerce/mirror.js +9 -9
- package/dist/commerce/roles.d.ts +10 -10
- package/dist/commerce/roles.js +13 -13
- package/dist/commerce/secrets.d.ts +9 -9
- package/dist/commerce/secrets.js +9 -9
- package/dist/commerce/sync.d.ts +7 -7
- package/dist/commerce/sync.js +5 -5
- package/dist/components/sections.d.ts +9 -9
- package/dist/components/sections.js +12 -12
- package/dist/config.d.ts +62 -62
- package/dist/config.js +18 -18
- package/dist/email/inquiry.d.ts +2 -2
- package/dist/email/inquiry.js +1 -1
- package/dist/email/send.d.ts +4 -4
- package/dist/email/send.js +7 -7
- package/dist/email/templates.js +3 -3
- package/dist/email/theme.d.ts +1 -1
- package/dist/email/theme.js +4 -4
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -1
- package/dist/index.js +1 -1
- package/dist/map/pmtiles.d.ts +5 -5
- package/dist/map/pmtiles.js +5 -5
- package/dist/map/scaffold.d.ts +2 -2
- package/dist/map/scaffold.js +4 -4
- package/dist/map/style.d.ts +4 -4
- package/dist/map/style.js +1 -1
- package/dist/portal/config.d.ts +2 -2
- package/dist/portal/config.js +3 -3
- package/dist/portal/guard.d.ts +4 -4
- package/dist/portal/guard.js +4 -4
- package/dist/portal/nav.js +2 -2
- package/dist/portal/scaffold.d.ts +4 -4
- package/dist/portal/scaffold.js +6 -6
- package/dist/portal/session.d.ts +2 -2
- package/dist/portal/session.js +5 -5
- package/dist/portfolio/scaffold.d.ts +1 -1
- package/dist/portfolio/scaffold.js +4 -4
- package/dist/project/actions.d.ts +1 -1
- package/dist/project/actions.js +6 -6
- package/dist/project/generate.d.ts +4 -4
- package/dist/project/generate.js +15 -15
- package/dist/project/index.js +1 -1
- package/dist/project/scaffold.d.ts +2 -2
- package/dist/project/scaffold.js +11 -11
- package/dist/pwa/generate.d.ts +11 -11
- package/dist/pwa/generate.js +12 -12
- package/dist/queues/consumer.d.ts +3 -3
- package/dist/queues/consumer.js +2 -2
- package/dist/queues/messages.d.ts +4 -4
- package/dist/queues/messages.js +2 -2
- package/dist/queues/scaffold.d.ts +4 -4
- package/dist/queues/scaffold.js +8 -8
- package/dist/queues/webhook.d.ts +5 -5
- package/dist/queues/webhook.js +3 -3
- package/dist/realtime/scaffold.d.ts +4 -4
- package/dist/realtime/scaffold.js +8 -8
- package/dist/schema/collections.d.ts +6 -6
- package/dist/schema/collections.js +23 -23
- package/dist/schema/framework.d.ts +1 -1
- package/dist/schema/framework.js +2 -2
- package/dist/schema/generate.js +2 -2
- package/dist/schema/index.js +1 -1
- package/dist/secrets.d.ts +6 -6
- package/dist/secrets.js +6 -6
- package/dist/security/csp-origins.d.ts +1 -1
- package/dist/security/csp-origins.js +3 -3
- package/dist/security/rate-rules.d.ts +2 -2
- package/dist/security/rate-rules.js +8 -8
- package/dist/seo/resolve.d.ts +5 -5
- package/dist/seo/resolve.js +2 -2
- package/dist/seo/routes.d.ts +5 -5
- package/dist/seo/routes.js +3 -3
- package/dist/seo/structured-data.d.ts +6 -6
- package/dist/seo/structured-data.js +7 -7
- package/dist/status.d.ts +5 -5
- package/dist/status.js +7 -7
- package/dist/tenancy/index.d.ts +3 -3
- package/dist/tenancy/index.js +6 -6
- package/dist/worker/generate.d.ts +2 -2
- package/dist/worker/generate.js +19 -19
- package/dist/worker/index.js +1 -1
- package/dist/worker/routes.js +1 -1
- package/dist/workflow/advance.d.ts +3 -3
- package/dist/workflow/advance.js +6 -6
- package/dist/workflow/config.d.ts +4 -4
- package/dist/workflow/config.js +4 -4
- package/dist/workflow/generate.d.ts +2 -2
- package/dist/workflow/generate.js +4 -4
- package/package.json +3 -4
- package/src/components/Collection.tsx +5 -5
- package/src/components/Editable.astro +9 -9
- package/src/components/JustifiedGallery.astro +8 -8
- package/src/components/MediaSlot.astro +12 -12
- package/src/components/PortalShell.astro +4 -4
- package/src/components/RegisterSW.astro +3 -3
- package/src/components/Section.astro +8 -8
- package/src/components/Sections.astro +6 -6
- package/src/components/Seo.astro +3 -3
- package/src/components/StageBar.astro +3 -3
- package/src/components/StructuredData.astro +2 -2
- package/src/components/justify.ts +9 -9
- package/src/components/media-meta.ts +10 -10
- package/src/components/sections/AboutIntro.astro +1 -1
- package/src/components/sections/Contact.astro +1 -1
- package/src/components/sections/Cta.astro +1 -1
- package/src/components/sections/Faq.astro +1 -1
- package/src/components/sections/FeatureGrid.astro +2 -2
- package/src/components/sections/Hero.astro +1 -1
- package/src/components/sections/PricingTiers.astro +1 -1
- package/src/components/sections/ProductGrid.astro +1 -1
- package/src/components/sections/SplitImage.astro +1 -1
- package/src/components/sections/Steps.astro +1 -1
- package/src/components/sections/Testimonial.astro +1 -1
- package/src/components/sections.ts +17 -17
package/dist/astro/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2026 BowenLabs. Astroid is MIT licensed.
|
|
2
2
|
//
|
|
3
|
-
// `astroidjs/astro
|
|
3
|
+
// `astroidjs/astro`—the BUILD-TIME surface, imported from `astro.config.mjs`.
|
|
4
4
|
// Kept off the main entry on purpose: it reaches for `node:crypto` and
|
|
5
5
|
// `solid-js/web`, neither of which belongs in the Worker bundle the generated
|
|
6
6
|
// `worker.ts` produces.
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AstroidConfig } from "../config.js";
|
|
2
2
|
/**
|
|
3
|
-
* The editor Better Auth instance's table prefix
|
|
3
|
+
* The editor Better Auth instance's table prefix—`louise_user`,
|
|
4
4
|
* `louise_session`, … The unprefixed names are left free for a second (portal)
|
|
5
5
|
* instance. Consumed by the generated `editorsRoute` and mirrored by the
|
|
6
6
|
* scaffolded `src/auth.ts` (`getLouiseAuth({ tablePrefix })`) + its migration.
|
|
@@ -12,7 +12,7 @@ export declare const ASTROID_EDITOR_TABLE_PREFIX = "louise_";
|
|
|
12
12
|
* reject a portal that would collide with it.
|
|
13
13
|
*/
|
|
14
14
|
export declare const ASTROID_EDITOR_COOKIE_PREFIX = "better-auth";
|
|
15
|
-
/** The editor's Better Auth table name for a given model (
|
|
15
|
+
/** The editor's Better Auth table name for a given model (for example, `louise_user`). */
|
|
16
16
|
export declare function astroidEditorTable(model: string): string;
|
|
17
17
|
/**
|
|
18
18
|
* Reject a portal whose isolation would collide with the editor instance on the
|
package/dist/auth/index.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
// Editor-auth convention + the two-instance isolation guard.
|
|
4
4
|
//
|
|
5
5
|
// Astroid runs up to TWO Better Auth instances on one origin: the EDITOR (the
|
|
6
|
-
// studio
|
|
7
|
-
// second PORTAL instance (customers/members/a shop account
|
|
6
|
+
// studio—magic-link + passkey, a DB-managed admin allowlist) and, optionally, a
|
|
7
|
+
// second PORTAL instance (customers/members/a shop account—see `portal/`). The
|
|
8
8
|
// editor owns Better Auth's default mount (`/api/auth`) and cookie because the
|
|
9
9
|
// Louise editor client hardcodes them; its tables are namespaced with the
|
|
10
10
|
// `louise_` prefix so a second instance can take the unprefixed `user`/`session`
|
|
11
|
-
// tables without collision. The portal is the one that MOVES
|
|
11
|
+
// tables without collision. The portal is the one that MOVES—a distinct mount,
|
|
12
12
|
// cookie prefix, and (by default) table prefix.
|
|
13
13
|
//
|
|
14
14
|
// The failure this guards against is subtle and intermittent: two instances that
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { AstroidConfigError } from "../errors.js";
|
|
19
19
|
import { astroidPortal } from "../portal/config.js";
|
|
20
20
|
/**
|
|
21
|
-
* The editor Better Auth instance's table prefix
|
|
21
|
+
* The editor Better Auth instance's table prefix—`louise_user`,
|
|
22
22
|
* `louise_session`, … The unprefixed names are left free for a second (portal)
|
|
23
23
|
* instance. Consumed by the generated `editorsRoute` and mirrored by the
|
|
24
24
|
* scaffolded `src/auth.ts` (`getLouiseAuth({ tablePrefix })`) + its migration.
|
|
@@ -30,7 +30,7 @@ export const ASTROID_EDITOR_TABLE_PREFIX = "louise_";
|
|
|
30
30
|
* reject a portal that would collide with it.
|
|
31
31
|
*/
|
|
32
32
|
export const ASTROID_EDITOR_COOKIE_PREFIX = "better-auth";
|
|
33
|
-
/** The editor's Better Auth table name for a given model (
|
|
33
|
+
/** The editor's Better Auth table name for a given model (for example, `louise_user`). */
|
|
34
34
|
export function astroidEditorTable(model) {
|
|
35
35
|
return `${ASTROID_EDITOR_TABLE_PREFIX}${model}`;
|
|
36
36
|
}
|
|
@@ -62,7 +62,7 @@ export interface FourthwallProductLike {
|
|
|
62
62
|
* Is this item sold at `locationId` at all?
|
|
63
63
|
*
|
|
64
64
|
* Exported because a location-scoped sync needs to SKIP items the merchant
|
|
65
|
-
* doesn't carry, and `squareToCatalogItem` can't do that for you
|
|
65
|
+
* doesn't carry, and `squareToCatalogItem` can't do that for you—it returns
|
|
66
66
|
* one item, and "don't store this row" isn't a `CatalogItem`. Without the guard
|
|
67
67
|
* an unstocked item mirrors as a $0 card with no variants, which looks like a
|
|
68
68
|
* pricing bug rather than a catalog decision.
|
|
@@ -79,7 +79,7 @@ export declare function squareItemSoldAt(item: SquareItemLike, locationId: strin
|
|
|
79
79
|
*
|
|
80
80
|
* `price` is the LOWEST variation price. A Square item is a family ("Bag of
|
|
81
81
|
* beans" with 12oz and 2lb variations), so a single headline number has to mean
|
|
82
|
-
* "from"
|
|
82
|
+
* "from"—taking the first variation's price instead would change with Square's
|
|
83
83
|
* ordering and quietly misprice the card.
|
|
84
84
|
*
|
|
85
85
|
* ## Scoping to one merchant
|
|
@@ -90,22 +90,22 @@ export declare function squareItemSoldAt(item: SquareItemLike, locationId: strin
|
|
|
90
90
|
*
|
|
91
91
|
* The headline number has to be scoped for the same reason the variants are.
|
|
92
92
|
* "From $8" computed over the whole catalog, on a page where the $8 size isn't
|
|
93
|
-
* stocked, advertises a price this merchant will never honour
|
|
93
|
+
* stocked, advertises a price this merchant will never honour—and because the
|
|
94
94
|
* dropped variation is usually the cheap one, the error runs in the direction a
|
|
95
95
|
* customer notices at the till.
|
|
96
96
|
*
|
|
97
97
|
* Unscoped behaviour is unchanged: no `locationId` means base prices and every
|
|
98
98
|
* variation, which is correct for a single-location account.
|
|
99
99
|
*
|
|
100
|
-
* An item sold nowhere at `locationId` yields no variants and a price of 0
|
|
101
|
-
*
|
|
100
|
+
* An item sold nowhere at `locationId` yields no variants and a price of 0—filter
|
|
101
|
+
* with {@link squareItemSoldAt} before calling rather than storing that.
|
|
102
102
|
*/
|
|
103
103
|
export declare function squareToCatalogItem(item: SquareItemLike, options?: SquareAdapterOptions): CatalogItem;
|
|
104
104
|
/**
|
|
105
105
|
* Fourthwall product → `CatalogItem`. Same "lowest variant wins" rule as Square,
|
|
106
106
|
* for the same reason.
|
|
107
107
|
*
|
|
108
|
-
* Fourthwall already prices in major units, so there's no conversion
|
|
108
|
+
* Fourthwall already prices in major units, so there's no conversion—mirroring
|
|
109
109
|
* `lowestPrice` in `louise-toolkit/commerce/fourthwall`.
|
|
110
110
|
*/
|
|
111
111
|
export declare function fourthwallToCatalogItem(product: FourthwallProductLike): CatalogItem;
|
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
//
|
|
5
5
|
// This is the file the whole module exists for. themidwestartist.com's loader
|
|
6
6
|
// says it outright: coracle runs the same helper over Square, "only the
|
|
7
|
-
// content/repo reads differ
|
|
7
|
+
// content/repo reads differ—issue: repo drift." Two sites, one intent, two
|
|
8
8
|
// hand-written translations that drifted apart. The translation is mechanical,
|
|
9
9
|
// so it belongs here once.
|
|
10
10
|
//
|
|
11
11
|
// Each provider's client already returns a normalized-for-that-provider shape
|
|
12
12
|
// (`SquareCatalogItem`, `FwProduct`); these functions take that last step to the
|
|
13
|
-
// shape the mirror stores. Deliberately pure
|
|
13
|
+
// shape the mirror stores. Deliberately pure—they take the provider's objects,
|
|
14
14
|
// not credentials or an `env`, so they're trivially testable and the caller
|
|
15
15
|
// keeps control of how the fetch happens (cached, paged, rate-limited).
|
|
16
16
|
/**
|
|
17
17
|
* Is this object sold at `locationId`?
|
|
18
18
|
*
|
|
19
19
|
* Mirrors `presentAt` in `louise-toolkit/commerce/square`, but tolerant of the
|
|
20
|
-
* fields being absent. The two lists are NOT symmetric
|
|
20
|
+
* fields being absent. The two lists are NOT symmetric—`presentAtLocationIds`
|
|
21
21
|
* is a whitelist consulted when `presentAtAllLocations` is false,
|
|
22
22
|
* `absentAtLocationIds` a blacklist consulted when it is true. Reading them the
|
|
23
23
|
* other way round shows a merchant products they do not carry.
|
|
@@ -40,7 +40,7 @@ const toMajor = (cents) => Math.round(cents) / 100;
|
|
|
40
40
|
* Is this item sold at `locationId` at all?
|
|
41
41
|
*
|
|
42
42
|
* Exported because a location-scoped sync needs to SKIP items the merchant
|
|
43
|
-
* doesn't carry, and `squareToCatalogItem` can't do that for you
|
|
43
|
+
* doesn't carry, and `squareToCatalogItem` can't do that for you—it returns
|
|
44
44
|
* one item, and "don't store this row" isn't a `CatalogItem`. Without the guard
|
|
45
45
|
* an unstocked item mirrors as a $0 card with no variants, which looks like a
|
|
46
46
|
* pricing bug rather than a catalog decision.
|
|
@@ -61,7 +61,7 @@ export function squareItemSoldAt(item, locationId) {
|
|
|
61
61
|
*
|
|
62
62
|
* `price` is the LOWEST variation price. A Square item is a family ("Bag of
|
|
63
63
|
* beans" with 12oz and 2lb variations), so a single headline number has to mean
|
|
64
|
-
* "from"
|
|
64
|
+
* "from"—taking the first variation's price instead would change with Square's
|
|
65
65
|
* ordering and quietly misprice the card.
|
|
66
66
|
*
|
|
67
67
|
* ## Scoping to one merchant
|
|
@@ -72,15 +72,15 @@ export function squareItemSoldAt(item, locationId) {
|
|
|
72
72
|
*
|
|
73
73
|
* The headline number has to be scoped for the same reason the variants are.
|
|
74
74
|
* "From $8" computed over the whole catalog, on a page where the $8 size isn't
|
|
75
|
-
* stocked, advertises a price this merchant will never honour
|
|
75
|
+
* stocked, advertises a price this merchant will never honour—and because the
|
|
76
76
|
* dropped variation is usually the cheap one, the error runs in the direction a
|
|
77
77
|
* customer notices at the till.
|
|
78
78
|
*
|
|
79
79
|
* Unscoped behaviour is unchanged: no `locationId` means base prices and every
|
|
80
80
|
* variation, which is correct for a single-location account.
|
|
81
81
|
*
|
|
82
|
-
* An item sold nowhere at `locationId` yields no variants and a price of 0
|
|
83
|
-
*
|
|
82
|
+
* An item sold nowhere at `locationId` yields no variants and a price of 0—filter
|
|
83
|
+
* with {@link squareItemSoldAt} before calling rather than storing that.
|
|
84
84
|
*/
|
|
85
85
|
export function squareToCatalogItem(item, options = {}) {
|
|
86
86
|
const locationId = options.locationId;
|
|
@@ -117,7 +117,7 @@ export function squareToCatalogItem(item, options = {}) {
|
|
|
117
117
|
* Fourthwall product → `CatalogItem`. Same "lowest variant wins" rule as Square,
|
|
118
118
|
* for the same reason.
|
|
119
119
|
*
|
|
120
|
-
* Fourthwall already prices in major units, so there's no conversion
|
|
120
|
+
* Fourthwall already prices in major units, so there's no conversion—mirroring
|
|
121
121
|
* `lowestPrice` in `louise-toolkit/commerce/fourthwall`.
|
|
122
122
|
*/
|
|
123
123
|
export function fourthwallToCatalogItem(product) {
|
|
@@ -2,7 +2,7 @@ import type { AstroidConfig } from "../config.js";
|
|
|
2
2
|
/** Does this project take card payments in-page? Square storefront only. */
|
|
3
3
|
export declare function usesCardCheckout(config: AstroidConfig): boolean;
|
|
4
4
|
/**
|
|
5
|
-
* `src/pages/api/checkout.ts
|
|
5
|
+
* `src/pages/api/checkout.ts`—the server-authoritative payment route.
|
|
6
6
|
*
|
|
7
7
|
* Scaffold-once: a real store adds shipping, tax, an order record, a receipt
|
|
8
8
|
* email. What Astroid fixes is the sequence, because every step of it is a place
|
|
@@ -12,7 +12,7 @@ export declare function usesCardCheckout(config: AstroidConfig): boolean;
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function generateAstroidCheckoutRoute(config: AstroidConfig): string | null;
|
|
14
14
|
/**
|
|
15
|
-
* `src/components/SquareCard.astro
|
|
15
|
+
* `src/components/SquareCard.astro`—the card input.
|
|
16
16
|
*
|
|
17
17
|
* Square's Web Payments SDK renders the field in an iframe from their CDN and
|
|
18
18
|
* hands back a single-use token, so the raw card number never touches the Worker
|
|
@@ -29,13 +29,13 @@ export declare function generateAstroidSquareCard(config: AstroidConfig): string
|
|
|
29
29
|
* application id is shipped to the browser by design, and the environment is a
|
|
30
30
|
* choice, not a credential. Putting them in `credentials` would also fold them
|
|
31
31
|
* into the dormancy gate, which is about whether the module can safely CALL
|
|
32
|
-
* Square
|
|
32
|
+
* Square—a different question from whether the card field can render.
|
|
33
33
|
*
|
|
34
34
|
* The two vars are gated SEPARATELY, and that split is load-bearing.
|
|
35
35
|
* `SQUARE_ENVIRONMENT` selects the API HOST for every Square call, so it belongs
|
|
36
36
|
* to any project that talks to Square at all; `SQUARE_APP_ID` only mounts the
|
|
37
|
-
* browser card field. Gating both on card checkout
|
|
38
|
-
* `invoicing: "square"` became expressible
|
|
37
|
+
* browser card field. Gating both on card checkout—as this did until
|
|
38
|
+
* `invoicing: "square"` became expressible—left a site that runs Square for
|
|
39
39
|
* invoicing alone with no `SQUARE_ENVIRONMENT`, and `SquareConfig.environment`
|
|
40
40
|
* defaults to "sandbox". Every production invoice would have been created
|
|
41
41
|
* against the sandbox: no error, no warning, just money that never arrives.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2026 BowenLabs. Astroid is MIT licensed.
|
|
2
2
|
//
|
|
3
|
-
// The checkout SEAM
|
|
3
|
+
// The checkout SEAM—the piece that made `archetype: "storefront"` a storefront
|
|
4
4
|
// that couldn't take a card.
|
|
5
5
|
//
|
|
6
6
|
// Everything around this already existed: `verifyCheckout` re-prices server-side,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// missing was the route in the middle, so none of it was reachable.
|
|
11
11
|
//
|
|
12
12
|
// SCOPE, deliberately narrow. This generates the server-authoritative PAYMENT
|
|
13
|
-
// path and a card input
|
|
13
|
+
// path and a card input—not a cart, not a checkout page, not shipping or tax.
|
|
14
14
|
// Where a cart lives (localStorage, D1, a portal session), what it holds, and how
|
|
15
15
|
// it renders are project decisions Astroid has no business making, and a
|
|
16
16
|
// half-opinionated cart is worse than none. What is NOT a project decision is the
|
|
@@ -26,7 +26,7 @@ export function usesCardCheckout(config) {
|
|
|
26
26
|
return astroidCommerceRoles(config.commerce).storefront === "square";
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* `src/pages/api/checkout.ts
|
|
29
|
+
* `src/pages/api/checkout.ts`—the server-authoritative payment route.
|
|
30
30
|
*
|
|
31
31
|
* Scaffold-once: a real store adds shipping, tax, an order record, a receipt
|
|
32
32
|
* email. What Astroid fixes is the sequence, because every step of it is a place
|
|
@@ -319,7 +319,7 @@ export function generateAstroidCheckoutRoute(config) {
|
|
|
319
319
|
.join("\n");
|
|
320
320
|
}
|
|
321
321
|
/**
|
|
322
|
-
* `src/components/SquareCard.astro
|
|
322
|
+
* `src/components/SquareCard.astro`—the card input.
|
|
323
323
|
*
|
|
324
324
|
* Square's Web Payments SDK renders the field in an iframe from their CDN and
|
|
325
325
|
* hands back a single-use token, so the raw card number never touches the Worker
|
|
@@ -417,7 +417,7 @@ export function generateAstroidSquareCard(config) {
|
|
|
417
417
|
.filter((line) => line !== null)
|
|
418
418
|
.join("\n");
|
|
419
419
|
}
|
|
420
|
-
/** Does this project talk to Square in ANY role
|
|
420
|
+
/** Does this project talk to Square in ANY role—storefront, invoicing, or
|
|
421
421
|
* otherwise? Distinct from {@link usesCardCheckout}, which asks the narrower
|
|
422
422
|
* question of whether the in-page card field renders. */
|
|
423
423
|
function usesSquare(config) {
|
|
@@ -430,13 +430,13 @@ function usesSquare(config) {
|
|
|
430
430
|
* application id is shipped to the browser by design, and the environment is a
|
|
431
431
|
* choice, not a credential. Putting them in `credentials` would also fold them
|
|
432
432
|
* into the dormancy gate, which is about whether the module can safely CALL
|
|
433
|
-
* Square
|
|
433
|
+
* Square—a different question from whether the card field can render.
|
|
434
434
|
*
|
|
435
435
|
* The two vars are gated SEPARATELY, and that split is load-bearing.
|
|
436
436
|
* `SQUARE_ENVIRONMENT` selects the API HOST for every Square call, so it belongs
|
|
437
437
|
* to any project that talks to Square at all; `SQUARE_APP_ID` only mounts the
|
|
438
|
-
* browser card field. Gating both on card checkout
|
|
439
|
-
* `invoicing: "square"` became expressible
|
|
438
|
+
* browser card field. Gating both on card checkout—as this did until
|
|
439
|
+
* `invoicing: "square"` became expressible—left a site that runs Square for
|
|
440
440
|
* invoicing alone with no `SQUARE_ENVIRONMENT`, and `SquareConfig.environment`
|
|
441
441
|
* defaults to "sandbox". Every production invoice would have been created
|
|
442
442
|
* against the sandbox: no error, no warning, just money that never arrives.
|
|
@@ -459,7 +459,7 @@ export function astroidCheckoutVars(config) {
|
|
|
459
459
|
* substitutes into `src/env.d.ts`. Empty without card checkout.
|
|
460
460
|
*/
|
|
461
461
|
export function generateAstroidCheckoutEnv(config) {
|
|
462
|
-
// Mirrors the gating in `astroidCheckoutVars
|
|
462
|
+
// Mirrors the gating in `astroidCheckoutVars`—the app id is card-checkout
|
|
463
463
|
// only, the environment belongs to any project that calls Square at all.
|
|
464
464
|
const lines = [];
|
|
465
465
|
if (usesCardCheckout(config)) {
|
|
@@ -28,13 +28,13 @@ export interface VerifiedLine {
|
|
|
28
28
|
* worth a notify-me. Collapsing them tells someone to remove an item the shop
|
|
29
29
|
* will restock on Tuesday.
|
|
30
30
|
*
|
|
31
|
-
* A lookup can only produce `"out-of-stock"` by saying so
|
|
32
|
-
* {@link ScopedPriceLookup}
|
|
31
|
+
* A lookup can only produce `"out-of-stock"` by saying so—see
|
|
32
|
+
* {@link ScopedPriceLookup}—because a bare `Map` has no way to distinguish
|
|
33
33
|
* them and guessing would put the wrong sentence on the screen.
|
|
34
34
|
*/
|
|
35
35
|
export type CheckoutRefusal = "empty" | "unavailable" | "out-of-stock" | "price-changed" | "invalid";
|
|
36
36
|
/**
|
|
37
|
-
* One way the cart disagrees with the live catalog
|
|
37
|
+
* One way the cart disagrees with the live catalog—the toolkit's
|
|
38
38
|
* `CartIssue`, less the add-on case (checkout lines carry no add-ons yet).
|
|
39
39
|
* Hand the list to `repairCart` from `louise-toolkit/commerce` to fix the cart
|
|
40
40
|
* in one step.
|
|
@@ -52,7 +52,7 @@ export type CheckoutVerification = {
|
|
|
52
52
|
reason: CheckoutRefusal;
|
|
53
53
|
message: string;
|
|
54
54
|
/**
|
|
55
|
-
* Every problem, in cart order, with what the catalog says now
|
|
55
|
+
* Every problem, in cart order, with what the catalog says now—empty
|
|
56
56
|
* for `"empty"` and `"invalid"`, which are about the request, not the
|
|
57
57
|
* catalog.
|
|
58
58
|
*/
|
|
@@ -62,7 +62,7 @@ export type CheckoutVerification = {
|
|
|
62
62
|
* map omits is treated as no longer purchasable. */
|
|
63
63
|
export type PriceLookup = (variantIds: string[]) => Promise<Map<string, number>>;
|
|
64
64
|
/** Where the sale is happening. Optional, and providers without a location
|
|
65
|
-
* dimension ignore it
|
|
65
|
+
* dimension ignore it—a single-merchant Square account or Fourthwall store
|
|
66
66
|
* passes nothing and behaves exactly as before. */
|
|
67
67
|
export interface CheckoutScope {
|
|
68
68
|
/** Provider location id (Square) or equivalent merchant key. */
|
|
@@ -86,13 +86,13 @@ export interface ScopedPrices {
|
|
|
86
86
|
* A price lookup that knows WHERE the sale is happening.
|
|
87
87
|
*
|
|
88
88
|
* This is the multi-merchant checkout guard. One shared catalog sold through
|
|
89
|
-
* several merchants carries a different price per location
|
|
90
|
-
* commission is absorbed in its own override
|
|
89
|
+
* several merchants carries a different price per location—each shop's
|
|
90
|
+
* commission is absorbed in its own override—so re-pricing a cart against
|
|
91
91
|
* base prices lets a customer pay the cheapest merchant's price at the dearest
|
|
92
92
|
* merchant's storefront. That is not a rounding error; it is the same class of
|
|
93
93
|
* bug as trusting the client's `unitPriceCents`, just one level further back.
|
|
94
94
|
*
|
|
95
|
-
* `scope` is optional so a {@link PriceLookup} is still assignable here
|
|
95
|
+
* `scope` is optional so a {@link PriceLookup} is still assignable here—an
|
|
96
96
|
* existing single-location lookup simply ignores the extra argument, which is
|
|
97
97
|
* exactly what a function of lower arity does in JavaScript.
|
|
98
98
|
*
|
|
@@ -131,7 +131,7 @@ export declare function verifyCheckout(lines: unknown, lookup: ScopedPriceLookup
|
|
|
131
131
|
/**
|
|
132
132
|
* A deterministic idempotency key for one buyer's checkout attempt.
|
|
133
133
|
*
|
|
134
|
-
* Providers dedupe on this, so the same key must mean the same charge
|
|
134
|
+
* Providers dedupe on this, so the same key must mean the same charge—which
|
|
135
135
|
* cuts both ways, and the second direction is the one that costs money. It is
|
|
136
136
|
* derived from the verified cart *and* `identity`, not from a random value or a
|
|
137
137
|
* timestamp: a customer double-clicking Pay sends the same key twice and is
|
|
@@ -141,18 +141,18 @@ export declare function verifyCheckout(lines: unknown, lookup: ScopedPriceLookup
|
|
|
141
141
|
* **`identity` is required, and it is what makes the key safe.** Without it the
|
|
142
142
|
* key was a pure function of the cart contents, so two DIFFERENT customers
|
|
143
143
|
* buying the same thing for the same price produced byte-identical keys. Stripe
|
|
144
|
-
* and Square scope idempotency keys per account and retain them for
|
|
144
|
+
* and Square scope idempotency keys per account and retain them for about 24 hours, so the
|
|
145
145
|
* provider replayed the first customer's PaymentIntent instead of creating the
|
|
146
146
|
* second's: the second buyer was never charged, no second order existed, and the
|
|
147
147
|
* site reported success. On a single-SKU storefront that is ordinary traffic,
|
|
148
148
|
* not an edge case.
|
|
149
149
|
*
|
|
150
150
|
* Pass something stable across a retry of THIS attempt and distinct between
|
|
151
|
-
* buyers
|
|
151
|
+
* buyers—a cart id, a checkout-session id, or a portal user id. Do not pass a
|
|
152
152
|
* value that varies per request (a fresh uuid defeats the dedupe and a
|
|
153
153
|
* double-click charges twice), and do not pass a constant.
|
|
154
154
|
*
|
|
155
|
-
* `scope` remains the OPERATION
|
|
155
|
+
* `scope` remains the OPERATION—`"order"` vs `"refund"`—so the two can never
|
|
156
156
|
* collide for one buyer. It is not an identity and never was.
|
|
157
157
|
*/
|
|
158
158
|
export declare function checkoutIdempotencyKey(verified: {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Server-authoritative checkout.
|
|
4
4
|
//
|
|
5
5
|
// A cart arrives from the browser, so every number in it is a claim, not a fact.
|
|
6
|
-
// The rule this encodes
|
|
6
|
+
// The rule this encodes—taken from coracle.coffee's working checkout—is that
|
|
7
7
|
// the client's price is a **staleness check**, never an input to the charge:
|
|
8
8
|
// look the price up server-side, and if it disagrees with what the customer was
|
|
9
9
|
// shown, refuse rather than silently charging a different amount. Refusing is
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// The comparison itself is the toolkit's `cartIssues`, which reports EVERY
|
|
17
17
|
// stale line rather than the first: a refusal that names one problem at a time
|
|
18
18
|
// is how a customer ends up fixing a line, retrying, and being refused over the
|
|
19
|
-
// next. What this adds is the opinion
|
|
19
|
+
// next. What this adds is the opinion—policing the untrusted body, and the
|
|
20
20
|
// sentence a customer sees.
|
|
21
21
|
import { cartIssues } from "louise-toolkit/commerce";
|
|
22
22
|
import { AstroidUsageError } from "../errors.js";
|
|
@@ -91,7 +91,7 @@ lookup, options = {}) {
|
|
|
91
91
|
}
|
|
92
92
|
const { prices, outOfStock } = normalizeLookup(await lookup([...new Set(parsed.map((l) => l.variantId))], options.scope));
|
|
93
93
|
// No `liveModifierIds`, so the add-on check is skipped and every issue is a
|
|
94
|
-
// variant one
|
|
94
|
+
// variant one—which is what makes the narrowing to CheckoutIssue true.
|
|
95
95
|
const issues = cartIssues(parsed, { prices, outOfStock });
|
|
96
96
|
const [first] = issues;
|
|
97
97
|
if (first)
|
|
@@ -109,7 +109,7 @@ lookup, options = {}) {
|
|
|
109
109
|
/**
|
|
110
110
|
* A deterministic idempotency key for one buyer's checkout attempt.
|
|
111
111
|
*
|
|
112
|
-
* Providers dedupe on this, so the same key must mean the same charge
|
|
112
|
+
* Providers dedupe on this, so the same key must mean the same charge—which
|
|
113
113
|
* cuts both ways, and the second direction is the one that costs money. It is
|
|
114
114
|
* derived from the verified cart *and* `identity`, not from a random value or a
|
|
115
115
|
* timestamp: a customer double-clicking Pay sends the same key twice and is
|
|
@@ -119,18 +119,18 @@ lookup, options = {}) {
|
|
|
119
119
|
* **`identity` is required, and it is what makes the key safe.** Without it the
|
|
120
120
|
* key was a pure function of the cart contents, so two DIFFERENT customers
|
|
121
121
|
* buying the same thing for the same price produced byte-identical keys. Stripe
|
|
122
|
-
* and Square scope idempotency keys per account and retain them for
|
|
122
|
+
* and Square scope idempotency keys per account and retain them for about 24 hours, so the
|
|
123
123
|
* provider replayed the first customer's PaymentIntent instead of creating the
|
|
124
124
|
* second's: the second buyer was never charged, no second order existed, and the
|
|
125
125
|
* site reported success. On a single-SKU storefront that is ordinary traffic,
|
|
126
126
|
* not an edge case.
|
|
127
127
|
*
|
|
128
128
|
* Pass something stable across a retry of THIS attempt and distinct between
|
|
129
|
-
* buyers
|
|
129
|
+
* buyers—a cart id, a checkout-session id, or a portal user id. Do not pass a
|
|
130
130
|
* value that varies per request (a fresh uuid defeats the dedupe and a
|
|
131
131
|
* double-click charges twice), and do not pass a constant.
|
|
132
132
|
*
|
|
133
|
-
* `scope` remains the OPERATION
|
|
133
|
+
* `scope` remains the OPERATION—`"order"` vs `"refund"`—so the two can never
|
|
134
134
|
* collide for one buyer. It is not an identity and never was.
|
|
135
135
|
*/
|
|
136
136
|
export async function checkoutIdempotencyKey(verified, scope, identity) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CatalogItem } from "./sync.js";
|
|
2
2
|
/** A product as the site renders it: the mirror row, decoded. */
|
|
3
3
|
export interface CatalogProduct extends CatalogItem {
|
|
4
|
-
/** Public URL segment
|
|
4
|
+
/** Public URL segment—owner-owned, stable across provider renames. */
|
|
5
5
|
slug: string;
|
|
6
6
|
status: "draft" | "published";
|
|
7
7
|
sortOrder: number;
|
|
@@ -55,7 +55,7 @@ export declare function readCatalogItem(slug: string, options: CatalogReadOption
|
|
|
55
55
|
* );
|
|
56
56
|
* ```
|
|
57
57
|
*
|
|
58
|
-
* Identical for every provider
|
|
58
|
+
* Identical for every provider—which is the whole point.
|
|
59
59
|
*/
|
|
60
60
|
export declare function astroidCatalogLoaderConfig(options: CatalogReadOptions & {
|
|
61
61
|
name?: string;
|
package/dist/commerce/loader.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// The catalog read, and the Live Content Collection loader over it.
|
|
4
4
|
//
|
|
5
5
|
// `defineCatalogLoader` (@louise-toolkit/astro) already owns the Astro-facing
|
|
6
|
-
// plumbing. What each site then hand-wrote was the layer underneath
|
|
7
|
-
// catalog out of D1"
|
|
6
|
+
// plumbing. What each site then hand-wrote was the layer underneath—"read my
|
|
7
|
+
// catalog out of D1"—and because that layer was per-site, so was the drift.
|
|
8
8
|
// It doesn't need to be: once the mirror table's shape is fixed (see mirror.ts),
|
|
9
9
|
// reading it is the same query whatever provider filled it in.
|
|
10
10
|
//
|
|
@@ -73,7 +73,7 @@ export async function readCatalogItem(slug, options) {
|
|
|
73
73
|
* );
|
|
74
74
|
* ```
|
|
75
75
|
*
|
|
76
|
-
* Identical for every provider
|
|
76
|
+
* Identical for every provider—which is the whole point.
|
|
77
77
|
*/
|
|
78
78
|
export function astroidCatalogLoaderConfig(options) {
|
|
79
79
|
return {
|
|
@@ -25,8 +25,8 @@ export interface CatalogMirrorConfig {
|
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Columns Astroid always PULLS, overwriting each sync. Fixed rather than
|
|
28
|
-
* configurable because they're the intersection of what every provider returns
|
|
29
|
-
*
|
|
28
|
+
* configurable because they're the intersection of what every provider returns—a
|
|
29
|
+
* project that wants a provider-specific field puts it in `owned` and fills it
|
|
30
30
|
* itself, which also stops the sync from clobbering it.
|
|
31
31
|
*/
|
|
32
32
|
export declare const PULLED_COLUMNS: readonly ["name", "price", "images", "variants", "externalSlug", "syncedAt"];
|
|
@@ -44,7 +44,7 @@ export declare function astroidCatalogMirror(config: AstroidConfig): Required<Pi
|
|
|
44
44
|
/**
|
|
45
45
|
* Drizzle source for the catalog table.
|
|
46
46
|
*
|
|
47
|
-
* `externalId` is unique
|
|
47
|
+
* `externalId` is unique—it's the sync's idempotency key, so a webhook and the
|
|
48
48
|
* cron re-sync racing on the same product can only ever collide into one row.
|
|
49
49
|
*/
|
|
50
50
|
export declare function generateCatalogTable(config: AstroidConfig): string | null;
|
|
@@ -57,7 +57,7 @@ export declare function generateCatalogTable(config: AstroidConfig): string | nu
|
|
|
57
57
|
*
|
|
58
58
|
* It has to exist at all because nothing else creates this table. `--commerce`
|
|
59
59
|
* put `products` in `src/schema.ts` and the queue seam told you to sync into it,
|
|
60
|
-
* but no migration anywhere in the toolkit created it
|
|
60
|
+
* but no migration anywhere in the toolkit created it—so the first catalog
|
|
61
61
|
* sync hit a missing table, and (because `astroidCatalogSync` swallows per-item
|
|
62
62
|
* errors) reported success while writing nothing. The documented fallback,
|
|
63
63
|
* `drizzle-kit generate`, could not help: the template ships a hand-authored
|
package/dist/commerce/mirror.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// The catalog mirror: an external provider is the source of truth, D1 is the
|
|
4
4
|
// editable overlay on top of it.
|
|
5
5
|
//
|
|
6
|
-
// Every consuming site landed on the same split
|
|
6
|
+
// Every consuming site landed on the same split—a set of fields PULLED from
|
|
7
7
|
// the provider and overwritten on every sync, and a disjoint set the owner edits
|
|
8
8
|
// which must survive every sync. Get that boundary wrong in either direction and
|
|
9
9
|
// you either clobber the owner's copy on the next cron tick, or serve a price
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
// What the sites did NOT agree on is how much to store, and it turns out to be
|
|
13
13
|
// one primitive with two settings rather than two designs:
|
|
14
14
|
//
|
|
15
|
-
// mirror
|
|
15
|
+
// mirror: pulled + owned columns both live in D1 (themidwestartist.com).
|
|
16
16
|
// Reads are one local query. The catalog can be stale between syncs.
|
|
17
|
-
// overlay
|
|
17
|
+
// overlay: only the owned columns live in D1, keyed by the provider's id.
|
|
18
18
|
// The catalog is read live from the provider and joined at read
|
|
19
19
|
// time: never stale, but every read costs a provider round-trip
|
|
20
20
|
// (cache accordingly).
|
|
21
|
-
// live
|
|
21
|
+
// live: Astroid manages NO catalog table at all: the catalog is read live
|
|
22
22
|
// from the provider (cached), and any owner-side overlay table is
|
|
23
23
|
// the SITE's own (coracle.coffee's `product_display_meta`, declared
|
|
24
24
|
// in schema.site.ts and joined in the site's loader). Use when the
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
// nor migration. One generator serves all three and a project switches by one word.
|
|
29
29
|
/**
|
|
30
30
|
* Columns Astroid always PULLS, overwriting each sync. Fixed rather than
|
|
31
|
-
* configurable because they're the intersection of what every provider returns
|
|
32
|
-
*
|
|
31
|
+
* configurable because they're the intersection of what every provider returns—a
|
|
32
|
+
* project that wants a provider-specific field puts it in `owned` and fills it
|
|
33
33
|
* itself, which also stops the sync from clobbering it.
|
|
34
34
|
*/
|
|
35
35
|
export const PULLED_COLUMNS = [
|
|
@@ -66,7 +66,7 @@ export function astroidCatalogMirror(config) {
|
|
|
66
66
|
return {
|
|
67
67
|
mode: mirror.mode ?? "mirror",
|
|
68
68
|
table: mirror.table ?? "products",
|
|
69
|
-
// Built-ins first so a project can override one (
|
|
69
|
+
// Built-ins first so a project can override one (for example, widen `status`)
|
|
70
70
|
// without restating the rest.
|
|
71
71
|
owned: { ...BUILT_IN_OWNED, ...mirror.owned },
|
|
72
72
|
};
|
|
@@ -99,7 +99,7 @@ function ownedColumnSource(key, col) {
|
|
|
99
99
|
/**
|
|
100
100
|
* Drizzle source for the catalog table.
|
|
101
101
|
*
|
|
102
|
-
* `externalId` is unique
|
|
102
|
+
* `externalId` is unique—it's the sync's idempotency key, so a webhook and the
|
|
103
103
|
* cron re-sync racing on the same product can only ever collide into one row.
|
|
104
104
|
*/
|
|
105
105
|
export function generateCatalogTable(config) {
|
|
@@ -172,7 +172,7 @@ function ownedColumnSql(key, col) {
|
|
|
172
172
|
*
|
|
173
173
|
* It has to exist at all because nothing else creates this table. `--commerce`
|
|
174
174
|
* put `products` in `src/schema.ts` and the queue seam told you to sync into it,
|
|
175
|
-
* but no migration anywhere in the toolkit created it
|
|
175
|
+
* but no migration anywhere in the toolkit created it—so the first catalog
|
|
176
176
|
* sync hit a missing table, and (because `astroidCatalogSync` swallows per-item
|
|
177
177
|
* errors) reported success while writing nothing. The documented fallback,
|
|
178
178
|
* `drizzle-kit generate`, could not help: the template ships a hand-authored
|
package/dist/commerce/roles.d.ts
CHANGED
|
@@ -3,14 +3,14 @@ import type { CommerceConfig, CommerceProvider } from "../config.js";
|
|
|
3
3
|
export type CommerceRole = "storefront" | "invoicing" | "pos";
|
|
4
4
|
/**
|
|
5
5
|
* Which roles each provider can serve, derived from the surface its
|
|
6
|
-
* `louise-toolkit/commerce/*` client actually exposes
|
|
6
|
+
* `louise-toolkit/commerce/*` client actually exposes—not from what the
|
|
7
7
|
* vendor's full API could theoretically do.
|
|
8
8
|
*
|
|
9
9
|
* square catalog + orders + payments, `createInvoice`/`publishInvoice`,
|
|
10
10
|
* AND locations + per-location price overrides + inventory counts
|
|
11
11
|
* stripe invoices + payment intents; NO catalog
|
|
12
|
-
* fourthwall catalog + cart; NO invoicing, and NO locations or inventory
|
|
13
|
-
|
|
12
|
+
* fourthwall catalog + cart; NO invoicing, and NO locations or inventory—*
|
|
13
|
+
its Platform API is create-only for products, so it cannot
|
|
14
14
|
* model stock held at a place
|
|
15
15
|
*
|
|
16
16
|
* Square alone can serve `pos`, and that is a fact about the clients rather than
|
|
@@ -27,8 +27,8 @@ export interface ResolvedCommerceRoles {
|
|
|
27
27
|
/**
|
|
28
28
|
* Resolve a `commerce` block into role assignments.
|
|
29
29
|
*
|
|
30
|
-
* The `provider` shorthand assigns to the provider's *natural* role
|
|
31
|
-
* can serve
|
|
30
|
+
* The `provider` shorthand assigns to the provider's *natural* role—the one it
|
|
31
|
+
* can serve—so `{ provider: "square" }` is a storefront and
|
|
32
32
|
* `{ provider: "stripe" }` is invoicing. Guessing "storefront" for both would
|
|
33
33
|
* produce a storefront with no catalog API behind it.
|
|
34
34
|
*/
|
|
@@ -36,17 +36,17 @@ export declare function astroidCommerceRoles(commerce: CommerceConfig | undefine
|
|
|
36
36
|
/** Every distinct provider this project talks to, in a stable order. */
|
|
37
37
|
export declare function astroidCommerceProviders(commerce: CommerceConfig | undefined): CommerceProvider[];
|
|
38
38
|
/**
|
|
39
|
-
* True when this project sells in person
|
|
39
|
+
* True when this project sells in person—the switch for locations,
|
|
40
40
|
* per-location pricing and inventory.
|
|
41
41
|
*/
|
|
42
42
|
export declare const hasPos: (commerce: CommerceConfig | undefined) => boolean;
|
|
43
43
|
/**
|
|
44
|
-
* True when Square is used with more than one Location,
|
|
44
|
+
* True when Square is used with more than one Location, that is, the location id
|
|
45
45
|
* comes from the request rather than the environment.
|
|
46
46
|
*
|
|
47
47
|
* Deliberately independent of which ROLE Square fills: a project could run
|
|
48
|
-
* multi-location invoicing without a `pos` storefront, and the consequence
|
|
49
|
-
*
|
|
48
|
+
* multi-location invoicing without a `pos` storefront, and the consequence—no
|
|
49
|
+
* ambient `SQUARE_LOCATION_ID`—is the same either way.
|
|
50
50
|
*/
|
|
51
51
|
export declare const hasMultiLocation: (commerce: CommerceConfig | undefined) => boolean;
|
|
52
52
|
/** True when this project sells anything at all. */
|
|
@@ -54,7 +54,7 @@ export declare const hasStorefront: (commerce: CommerceConfig | undefined) => bo
|
|
|
54
54
|
/**
|
|
55
55
|
* Reject a role assignment the provider's client cannot serve. Called from
|
|
56
56
|
* `defineAstroid`, so `invoicing: "fourthwall"` fails at config load with a
|
|
57
|
-
* message naming the alternatives
|
|
57
|
+
* message naming the alternatives—rather than at runtime, on the first
|
|
58
58
|
* invoice, as a missing function.
|
|
59
59
|
*/
|
|
60
60
|
export declare function assertCommerceRoles(commerce: CommerceConfig | undefined): void;
|