@kotao/storefront 0.2.4 → 0.2.6
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 +50 -2
- package/dist/bridge-ZKbKqgFd.d.ts +239 -0
- package/dist/cart-documents-BLavRDiu.d.ts +89 -0
- package/dist/cart-documents.d.ts +1 -2
- package/dist/cart-documents.js +1 -1
- package/dist/{chunk-M7BPQ54D.js → chunk-2MRB6SMP.js} +4 -3
- package/dist/chunk-2MRB6SMP.js.map +1 -0
- package/dist/chunk-CKGI3Y7L.js +19 -0
- package/dist/chunk-CKGI3Y7L.js.map +1 -0
- package/dist/{chunk-4TEFGD42.js → chunk-EG34HLSX.js} +209 -162
- package/dist/chunk-EG34HLSX.js.map +1 -0
- package/dist/chunk-O6YZEY7X.js +1382 -0
- package/dist/chunk-O6YZEY7X.js.map +1 -0
- package/dist/{chunk-7MTCGXIG.js → chunk-R4N565GX.js} +8 -4
- package/dist/chunk-R4N565GX.js.map +1 -0
- package/dist/{chunk-XMTWFJCZ.js → chunk-RFM27BKZ.js} +31 -7
- package/dist/chunk-RFM27BKZ.js.map +1 -0
- package/dist/{chunk-MYDKIJRH.js → chunk-SVMYFYIA.js} +2 -2
- package/dist/{chunk-MYDKIJRH.js.map → chunk-SVMYFYIA.js.map} +1 -1
- package/dist/{chunk-H3D7BAOL.js → chunk-VOTBNOWH.js} +21 -3
- package/dist/chunk-VOTBNOWH.js.map +1 -0
- package/dist/{chunk-PXVDVUFX.js → chunk-W74FGUZH.js} +10 -3
- package/dist/chunk-W74FGUZH.js.map +1 -0
- package/dist/{chunk-2IWNUDSZ.js → chunk-WNXI3MPM.js} +2 -2
- package/dist/chunk-WNXI3MPM.js.map +1 -0
- package/dist/chunk-XXNCFWXT.js +2118 -0
- package/dist/chunk-XXNCFWXT.js.map +1 -0
- package/dist/{client-bsiNPHBi.d.ts → client-CwOPPpFF.d.ts} +11 -1
- package/dist/{createCartHandler-C4RrPwSG.d.ts → createCartHandler-7DdKB-GF.d.ts} +1 -1
- package/dist/custom-css-Bl7Ur3-H.d.ts +6 -0
- package/dist/editor.d.ts +57 -104
- package/dist/editor.js +270 -1
- package/dist/editor.js.map +1 -1
- package/dist/events-react.d.ts +1 -1
- package/dist/events-react.js +1 -1
- package/dist/events.d.ts +3 -3
- package/dist/events.js +1 -1
- package/dist/{fetch-M3Y-fQrW.d.ts → fetch-Bq_cc8_G.d.ts} +5 -0
- package/dist/hydrogen-Bu7k0kE4.d.ts +259 -0
- package/dist/index.d.ts +74 -51
- package/dist/index.js +19 -15
- package/dist/index.js.map +1 -1
- package/dist/react-router.d.ts +30 -9
- package/dist/react-router.js +16 -7
- package/dist/react-router.js.map +1 -1
- package/dist/react.d.ts +79 -11
- package/dist/react.js +279 -10
- package/dist/react.js.map +1 -1
- package/dist/{routing-sEonP93J.d.ts → routing-Bz3Cg0BW.d.ts} +36 -6
- package/dist/seo.d.ts +7 -4
- package/dist/seo.js +2 -2
- package/dist/settings.d.ts +14 -4
- package/dist/settings.js +2 -2
- package/dist/{shop-BJSvtmnV.d.ts → shop-CnrnSAJw.d.ts} +33 -6
- package/dist/{store-CtCWHI8H.d.ts → store-DO08fzJi.d.ts} +1 -1
- package/dist/storefront-api-types.d.ts +12 -0
- package/dist/{types-BDhHWZsP.d.ts → types-BkY0yET-.d.ts} +3 -3
- package/dist/{types-bcbQzx87.d.ts → types-DZX8ScsJ.d.ts} +2 -0
- package/package.json +4 -4
- package/dist/cart-documents-CwwRTvm8.d.ts +0 -21
- package/dist/chunk-2IWNUDSZ.js.map +0 -1
- package/dist/chunk-4TEFGD42.js.map +0 -1
- package/dist/chunk-7MTCGXIG.js.map +0 -1
- package/dist/chunk-H3D7BAOL.js.map +0 -1
- package/dist/chunk-M7BPQ54D.js.map +0 -1
- package/dist/chunk-PXVDVUFX.js.map +0 -1
- package/dist/chunk-PXZ737N3.js +0 -439
- package/dist/chunk-PXZ737N3.js.map +0 -1
- package/dist/chunk-XMTWFJCZ.js.map +0 -1
package/README.md
CHANGED
|
@@ -14,14 +14,62 @@ frozen intra-request clock).
|
|
|
14
14
|
| `CacheShort` / `CacheLong` / `CacheNone` | `CacheShort` / `CacheLong` / `CacheNone` / `CacheCustom` | plus `StorefrontDefaultCache` (fresh 1s / serve ~1 day) |
|
|
15
15
|
| `createHydrogenContext` | `createKotaoContext` | storefront + geo + cache + locale + session seam |
|
|
16
16
|
| Oxygen `request.cf` | `context.geo` | backed by signed `x-kotao-*` headers; `null` if unsigned/tampered |
|
|
17
|
-
| (Oxygen-managed) | `@kotao/storefront/react-router` |
|
|
17
|
+
| (Oxygen-managed) | `@kotao/storefront/react-router` | RR8 `getKotaoLoadContext` |
|
|
18
18
|
|
|
19
19
|
The one real migration diff is `request.cf` → `context.geo`.
|
|
20
20
|
|
|
21
21
|
## Entry points
|
|
22
22
|
|
|
23
23
|
- `@kotao/storefront` — framework-agnostic core (no React Router import).
|
|
24
|
-
- `@kotao/storefront/
|
|
24
|
+
- `@kotao/storefront/editor` — Liquid settings bridge plus the authenticated, bounded Hydrogen
|
|
25
|
+
component-instance protocol and preview store.
|
|
26
|
+
- `@kotao/storefront/react` — Hydrogen-shaped React components and editor-only component
|
|
27
|
+
boundaries/registry helpers.
|
|
28
|
+
- `@kotao/storefront/react-router` — the React Router 8 binding (`getKotaoLoadContext`).
|
|
29
|
+
|
|
30
|
+
## Hydrogen editor preview
|
|
31
|
+
|
|
32
|
+
`createHydrogenEditorPreviewRuntime` projects manifest-authorized operations into an in-memory
|
|
33
|
+
instance tree. The source manifest and Git base remain authoritative; this store never writes source
|
|
34
|
+
or becomes public configuration. Each message is bound to the exact admin/preview origin, expected
|
|
35
|
+
window, session, base SHA, manifest hash, channel nonce, short-lived preview token, protocol version,
|
|
36
|
+
message ID, and monotonic sequence. Payloads fail closed above 128 KiB/depth 32, and at most 100
|
|
37
|
+
authenticated messages are buffered before Ready.
|
|
38
|
+
|
|
39
|
+
React themes mount `HydrogenEditorProvider` only in authenticated editor previews, mark extracted
|
|
40
|
+
instances with `HydrogenEditorBoundary`, and use `HydrogenEditorSlot` for declared insertion
|
|
41
|
+
boundaries. Per-instance subscriptions let prop/style changes reconcile only the affected subtree;
|
|
42
|
+
route, loader, Suspense, and HMR reconciliation retains draft operations and reports whether the
|
|
43
|
+
selection is active or out of route. Ordinary public storefront responses must not mount these
|
|
44
|
+
overlays or receive editor credentials.
|
|
45
|
+
|
|
46
|
+
Preview servers turn the opaque token into browser-safe runtime configuration with
|
|
47
|
+
`createHydrogenEditorPreviewBootstrap`. The `expected` binding must come from the trusted edit
|
|
48
|
+
session, never from request parameters:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
const editorBootstrap = await createHydrogenEditorPreviewBootstrap({
|
|
52
|
+
token: requestToken,
|
|
53
|
+
secret: env.HYDROGEN_EDITOR_PREVIEW_GRANT_SECRET,
|
|
54
|
+
expected: trustedEditSession.previewBinding,
|
|
55
|
+
now: Date.now(),
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
An invalid, missing, expired, or incorrectly bound token returns `null`. Only a non-null result may
|
|
60
|
+
be serialized into an editor-preview response; the signing secret is never part of that result.
|
|
61
|
+
Public responses omit both the bootstrap and the editor entry point. In the browser, dynamically
|
|
62
|
+
import `@kotao/storefront/editor` only when the server supplied a bootstrap, then call
|
|
63
|
+
`createHydrogenEditorPreviewRuntimeFromBootstrap` with `currentOrigin: location.origin`. The
|
|
64
|
+
factory refuses to start unless the current preview origin exactly matches the signed binding and
|
|
65
|
+
targets every runtime message at the signed Workspaces origin.
|
|
66
|
+
|
|
67
|
+
On editor-only preview hosts, the Gateway's Hydrogen canvas controller measures those stable DOM
|
|
68
|
+
boundaries and emits same-document interaction intents for move, inline content, bounded layout,
|
|
69
|
+
and insertion requests. `HydrogenEditorProvider` is the only consumer: it translates each intent
|
|
70
|
+
through `dispatchCanvasIntent`, validates it against the live manifest/slot/capability contract,
|
|
71
|
+
and only then applies and forwards the preview operation over the authenticated bridge. The DOM
|
|
72
|
+
controller has no source-write path and cannot bypass unsupported or read-only boundaries.
|
|
25
73
|
|
|
26
74
|
## Signed geo contract
|
|
27
75
|
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { T as ThemeSettingsStore, R as ResolvedSettings, a as ResolvedSection, b as ResolvedBlock } from './store-DO08fzJi.js';
|
|
2
|
+
|
|
3
|
+
interface StorefrontEditorMessageTarget {
|
|
4
|
+
postMessage(message: unknown, targetOrigin: string): void;
|
|
5
|
+
}
|
|
6
|
+
interface StorefrontEditorMessageEvent {
|
|
7
|
+
readonly origin: string;
|
|
8
|
+
readonly data: unknown;
|
|
9
|
+
readonly source?: StorefrontEditorMessageTarget | null;
|
|
10
|
+
}
|
|
11
|
+
interface StorefrontEditorMessageSource {
|
|
12
|
+
addEventListener(type: 'message', listener: (event: StorefrontEditorMessageEvent) => void): void;
|
|
13
|
+
removeEventListener(type: 'message', listener: (event: StorefrontEditorMessageEvent) => void): void;
|
|
14
|
+
}
|
|
15
|
+
interface StorefrontEditorPointerEvent {
|
|
16
|
+
readonly target?: unknown;
|
|
17
|
+
readonly relatedTarget?: unknown;
|
|
18
|
+
preventDefault?(): void;
|
|
19
|
+
stopPropagation?(): void;
|
|
20
|
+
}
|
|
21
|
+
interface StorefrontEditorRect {
|
|
22
|
+
readonly top: number;
|
|
23
|
+
readonly right: number;
|
|
24
|
+
readonly bottom: number;
|
|
25
|
+
readonly left: number;
|
|
26
|
+
readonly width: number;
|
|
27
|
+
readonly height: number;
|
|
28
|
+
}
|
|
29
|
+
interface StorefrontEditorDomElement {
|
|
30
|
+
id: string;
|
|
31
|
+
innerHTML?: string;
|
|
32
|
+
textContent?: string | null;
|
|
33
|
+
closest(selector: string): StorefrontEditorDomElement | null;
|
|
34
|
+
contains(candidate: unknown): boolean;
|
|
35
|
+
getAttribute?(name: string): string | null;
|
|
36
|
+
getBoundingClientRect?(): StorefrontEditorRect;
|
|
37
|
+
addEventListener?(type: 'click', listener: (event: StorefrontEditorPointerEvent) => void): void;
|
|
38
|
+
removeEventListener?(type: 'click', listener: (event: StorefrontEditorPointerEvent) => void): void;
|
|
39
|
+
setAttribute(name: string, value: string): void;
|
|
40
|
+
removeAttribute(name: string): void;
|
|
41
|
+
remove?(): void;
|
|
42
|
+
}
|
|
43
|
+
interface StorefrontEditorStyleElement {
|
|
44
|
+
id: string;
|
|
45
|
+
textContent: string | null;
|
|
46
|
+
remove(): void;
|
|
47
|
+
}
|
|
48
|
+
interface StorefrontEditorDocument {
|
|
49
|
+
readonly documentElement: Pick<StorefrontEditorDomElement, 'setAttribute' | 'removeAttribute'>;
|
|
50
|
+
readonly head?: {
|
|
51
|
+
appendChild(element: StorefrontEditorStyleElement): void;
|
|
52
|
+
};
|
|
53
|
+
readonly body?: {
|
|
54
|
+
appendChild(element: StorefrontEditorDomElement): void;
|
|
55
|
+
};
|
|
56
|
+
readonly defaultView?: {
|
|
57
|
+
readonly innerWidth: number;
|
|
58
|
+
readonly innerHeight: number;
|
|
59
|
+
addEventListener?(type: 'scroll' | 'resize', listener: () => void, capture?: boolean): void;
|
|
60
|
+
removeEventListener?(type: 'scroll' | 'resize', listener: () => void, capture?: boolean): void;
|
|
61
|
+
};
|
|
62
|
+
createElement(tagName: 'style'): StorefrontEditorStyleElement;
|
|
63
|
+
createElement(tagName: 'div'): StorefrontEditorDomElement;
|
|
64
|
+
getElementById(id: string): StorefrontEditorDomElement | StorefrontEditorStyleElement | null;
|
|
65
|
+
querySelectorAll?(selector: string): readonly StorefrontEditorDomElement[];
|
|
66
|
+
addEventListener(type: 'pointerover' | 'pointerout' | 'click', listener: (event: StorefrontEditorPointerEvent) => void, capture?: boolean): void;
|
|
67
|
+
removeEventListener(type: 'pointerover' | 'pointerout' | 'click', listener: (event: StorefrontEditorPointerEvent) => void, capture?: boolean): void;
|
|
68
|
+
}
|
|
69
|
+
interface StorefrontEditorBridge {
|
|
70
|
+
ready(): void;
|
|
71
|
+
hoverSection(sectionId: string | null): void;
|
|
72
|
+
selectSection(sectionId: string): void;
|
|
73
|
+
selectBlock(sectionId: string, blockId: string): void;
|
|
74
|
+
dispose(): void;
|
|
75
|
+
}
|
|
76
|
+
interface StorefrontEditorSettingOption {
|
|
77
|
+
readonly value: string;
|
|
78
|
+
readonly label: string;
|
|
79
|
+
}
|
|
80
|
+
interface StorefrontEditorThemeStyle {
|
|
81
|
+
readonly name: string;
|
|
82
|
+
readonly settings: ResolvedSettings;
|
|
83
|
+
}
|
|
84
|
+
interface StorefrontEditorSettingInput {
|
|
85
|
+
readonly type: string;
|
|
86
|
+
readonly name: string;
|
|
87
|
+
readonly label: string;
|
|
88
|
+
readonly group?: string;
|
|
89
|
+
readonly defaultValue?: unknown;
|
|
90
|
+
readonly placeholder?: string;
|
|
91
|
+
readonly helpText?: string;
|
|
92
|
+
readonly options?: readonly StorefrontEditorSettingOption[];
|
|
93
|
+
readonly min?: number;
|
|
94
|
+
readonly max?: number;
|
|
95
|
+
readonly step?: number;
|
|
96
|
+
readonly unit?: string;
|
|
97
|
+
}
|
|
98
|
+
interface StorefrontEditorBlockSchema {
|
|
99
|
+
readonly type: string;
|
|
100
|
+
readonly label: string;
|
|
101
|
+
readonly settings: readonly StorefrontEditorSettingInput[];
|
|
102
|
+
readonly limit?: number;
|
|
103
|
+
}
|
|
104
|
+
interface StorefrontEditorSectionPresetBlock {
|
|
105
|
+
readonly type: string;
|
|
106
|
+
readonly settings?: ResolvedSettings;
|
|
107
|
+
}
|
|
108
|
+
interface StorefrontEditorSectionPreset {
|
|
109
|
+
readonly name: string;
|
|
110
|
+
readonly settings?: ResolvedSettings;
|
|
111
|
+
readonly blocks?: readonly StorefrontEditorSectionPresetBlock[];
|
|
112
|
+
}
|
|
113
|
+
interface StorefrontEditorSectionSchema {
|
|
114
|
+
readonly type: string;
|
|
115
|
+
readonly label: string;
|
|
116
|
+
readonly settings: readonly StorefrontEditorSettingInput[];
|
|
117
|
+
readonly blocks?: readonly StorefrontEditorBlockSchema[];
|
|
118
|
+
readonly maxBlocks?: number;
|
|
119
|
+
readonly presets?: readonly StorefrontEditorSectionPreset[];
|
|
120
|
+
}
|
|
121
|
+
type StorefrontEditorSelectionScope = {
|
|
122
|
+
readonly kind: 'template';
|
|
123
|
+
readonly handle: string;
|
|
124
|
+
} | {
|
|
125
|
+
readonly kind: 'sectionGroup';
|
|
126
|
+
readonly handle: string;
|
|
127
|
+
};
|
|
128
|
+
interface StorefrontEditorSelection {
|
|
129
|
+
readonly sectionId: string;
|
|
130
|
+
readonly blockId?: string;
|
|
131
|
+
readonly block?: ResolvedBlock;
|
|
132
|
+
readonly scope?: StorefrontEditorSelectionScope;
|
|
133
|
+
readonly section?: ResolvedSection;
|
|
134
|
+
readonly sections?: readonly ResolvedSection[];
|
|
135
|
+
readonly schema?: StorefrontEditorSectionSchema;
|
|
136
|
+
readonly schemas?: Readonly<Record<string, StorefrontEditorSectionSchema>>;
|
|
137
|
+
}
|
|
138
|
+
type StorefrontEditorCanvasSectionAction = 'section.addBefore' | 'section.addAfter' | 'section.duplicate' | 'section.toggleVisibility' | 'section.moveUp' | 'section.moveDown' | 'section.remove';
|
|
139
|
+
type StorefrontEditorCanvasBlockAction = 'block.duplicate' | 'block.toggleVisibility' | 'block.moveUp' | 'block.moveDown' | 'block.remove';
|
|
140
|
+
type StorefrontEditorCanvasAction = {
|
|
141
|
+
readonly action: StorefrontEditorCanvasSectionAction;
|
|
142
|
+
readonly sectionId: string;
|
|
143
|
+
readonly scope?: StorefrontEditorSelectionScope;
|
|
144
|
+
} | {
|
|
145
|
+
readonly action: StorefrontEditorCanvasBlockAction;
|
|
146
|
+
readonly sectionId: string;
|
|
147
|
+
readonly blockId: string;
|
|
148
|
+
readonly scope?: StorefrontEditorSelectionScope;
|
|
149
|
+
};
|
|
150
|
+
interface StorefrontEditorValuesDocument {
|
|
151
|
+
readonly shopId: string;
|
|
152
|
+
readonly sections: readonly ResolvedSection[];
|
|
153
|
+
}
|
|
154
|
+
interface StorefrontEditorReady {
|
|
155
|
+
readonly sections: readonly ResolvedSection[];
|
|
156
|
+
readonly global?: ResolvedSettings;
|
|
157
|
+
readonly schemas?: Readonly<Record<string, StorefrontEditorSectionSchema>>;
|
|
158
|
+
readonly globalInputs?: readonly StorefrontEditorSettingInput[];
|
|
159
|
+
readonly themeStyles?: readonly StorefrontEditorThemeStyle[];
|
|
160
|
+
readonly templates?: Readonly<Record<string, StorefrontEditorValuesDocument>>;
|
|
161
|
+
readonly sectionGroups?: Readonly<Record<string, StorefrontEditorValuesDocument>>;
|
|
162
|
+
}
|
|
163
|
+
interface StorefrontEditorHostBridge {
|
|
164
|
+
requestReady(): void;
|
|
165
|
+
hoverSection(sectionId: string | null): void;
|
|
166
|
+
activateSection(sectionId: string | null, blockId?: string): void;
|
|
167
|
+
patchSection(sectionId: string, settings: ResolvedSettings): void;
|
|
168
|
+
patchGlobal(settings: ResolvedSettings): void;
|
|
169
|
+
insertSection(section: ResolvedSection, index?: number): void;
|
|
170
|
+
removeSection(sectionId: string): void;
|
|
171
|
+
reorderSection(sectionId: string, index: number): void;
|
|
172
|
+
patchBlock(sectionId: string, blockId: string, settings: ResolvedSettings): void;
|
|
173
|
+
insertBlock(sectionId: string, block: ResolvedBlock, index?: number): void;
|
|
174
|
+
removeBlock(sectionId: string, blockId: string): void;
|
|
175
|
+
reorderBlock(sectionId: string, blockId: string, index: number): void;
|
|
176
|
+
replaceTemplate(handle: string, document: StorefrontEditorValuesDocument): void;
|
|
177
|
+
replaceSectionGroup(handle: string, document: StorefrontEditorValuesDocument): void;
|
|
178
|
+
replaceAppExtensions(extensions: readonly StorefrontEditorAppExtensionPreview[]): void;
|
|
179
|
+
dispose(): void;
|
|
180
|
+
}
|
|
181
|
+
interface StorefrontEditorAppExtensionPreview {
|
|
182
|
+
readonly instanceId: string;
|
|
183
|
+
readonly kind: 'app_embed' | 'app_section' | 'app_block';
|
|
184
|
+
readonly appId: string;
|
|
185
|
+
readonly appName: string;
|
|
186
|
+
readonly extensionId: string;
|
|
187
|
+
readonly extensionName: string;
|
|
188
|
+
readonly version: string;
|
|
189
|
+
readonly entrypointUrl: string;
|
|
190
|
+
readonly stylesheetUrls: readonly string[];
|
|
191
|
+
readonly capabilities: readonly string[];
|
|
192
|
+
readonly allowedOrigins: readonly string[];
|
|
193
|
+
readonly settings: ResolvedSettings;
|
|
194
|
+
readonly embedLocation?: 'head' | 'body_start' | 'body_end';
|
|
195
|
+
readonly target?: {
|
|
196
|
+
readonly kind: 'template' | 'section_group';
|
|
197
|
+
readonly handle: string;
|
|
198
|
+
};
|
|
199
|
+
readonly templateHandle?: string;
|
|
200
|
+
readonly sectionInstanceId?: string;
|
|
201
|
+
readonly position: number;
|
|
202
|
+
}
|
|
203
|
+
interface CreateStorefrontEditorBridgeArgs {
|
|
204
|
+
readonly adminOrigin: string;
|
|
205
|
+
readonly shopId: string;
|
|
206
|
+
readonly store: ThemeSettingsStore;
|
|
207
|
+
readonly schemas?: Readonly<Record<string, StorefrontEditorSectionSchema>>;
|
|
208
|
+
readonly globalInputs?: readonly StorefrontEditorSettingInput[];
|
|
209
|
+
readonly themeStyles?: readonly StorefrontEditorThemeStyle[];
|
|
210
|
+
readonly templates?: Readonly<Record<string, StorefrontEditorValuesDocument>>;
|
|
211
|
+
readonly sectionGroups?: Readonly<Record<string, StorefrontEditorValuesDocument>>;
|
|
212
|
+
readonly transport: StorefrontEditorMessageSource;
|
|
213
|
+
readonly target: StorefrontEditorMessageTarget;
|
|
214
|
+
readonly document?: StorefrontEditorDocument;
|
|
215
|
+
}
|
|
216
|
+
interface CreateStorefrontEditorHostBridgeArgs {
|
|
217
|
+
readonly onSelectSection: (selection: StorefrontEditorSelection) => void;
|
|
218
|
+
readonly onCanvasAction?: (action: StorefrontEditorCanvasAction) => void;
|
|
219
|
+
readonly onHoverSection?: (sectionId: string | null) => void;
|
|
220
|
+
readonly onReady?: (ready: StorefrontEditorReady) => void;
|
|
221
|
+
readonly previewOrigin: string;
|
|
222
|
+
readonly resolveTarget?: () => StorefrontEditorMessageTarget | null;
|
|
223
|
+
readonly shopId: string;
|
|
224
|
+
readonly transport: StorefrontEditorMessageSource;
|
|
225
|
+
readonly target: StorefrontEditorMessageTarget;
|
|
226
|
+
}
|
|
227
|
+
interface StorefrontEditorCanvasPosition {
|
|
228
|
+
readonly left: number;
|
|
229
|
+
readonly top: number;
|
|
230
|
+
readonly placement: 'above' | 'below';
|
|
231
|
+
}
|
|
232
|
+
declare function positionStorefrontEditorCanvasToolbar(anchor: StorefrontEditorRect, toolbar: Pick<StorefrontEditorRect, 'width' | 'height'>, viewport: {
|
|
233
|
+
readonly width: number;
|
|
234
|
+
readonly height: number;
|
|
235
|
+
}): StorefrontEditorCanvasPosition;
|
|
236
|
+
declare function createStorefrontEditorBridge({ adminOrigin, document: editorDocument, globalInputs, themeStyles, schemas, sectionGroups, shopId, store, target, templates, transport, }: CreateStorefrontEditorBridgeArgs): StorefrontEditorBridge;
|
|
237
|
+
declare function createStorefrontEditorHostBridge({ onCanvasAction, onHoverSection, onReady, onSelectSection, previewOrigin, resolveTarget, shopId, target, transport, }: CreateStorefrontEditorHostBridgeArgs): StorefrontEditorHostBridge;
|
|
238
|
+
|
|
239
|
+
export { type CreateStorefrontEditorBridgeArgs as C, type StorefrontEditorMessageSource as S, type StorefrontEditorMessageTarget as a, type CreateStorefrontEditorHostBridgeArgs as b, type StorefrontEditorAppExtensionPreview as c, type StorefrontEditorBlockSchema as d, type StorefrontEditorBridge as e, type StorefrontEditorCanvasAction as f, type StorefrontEditorCanvasBlockAction as g, type StorefrontEditorCanvasPosition as h, type StorefrontEditorCanvasSectionAction as i, type StorefrontEditorDocument as j, type StorefrontEditorHostBridge as k, type StorefrontEditorMessageEvent as l, type StorefrontEditorReady as m, type StorefrontEditorRect as n, type StorefrontEditorSectionPreset as o, type StorefrontEditorSectionPresetBlock as p, type StorefrontEditorSectionSchema as q, type StorefrontEditorSelection as r, type StorefrontEditorSelectionScope as s, type StorefrontEditorSettingInput as t, type StorefrontEditorSettingOption as u, type StorefrontEditorThemeStyle as v, type StorefrontEditorValuesDocument as w, createStorefrontEditorBridge as x, createStorefrontEditorHostBridge as y, positionStorefrontEditorCanvasToolbar as z };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** Public Smart Cart seam types for custom React storefronts.
|
|
2
|
+
*
|
|
3
|
+
* The Smart Cart implementation is bundled into `@kotao/storefront`; external themes must never
|
|
4
|
+
* need the private `@kotao/smart-cart` workspace package merely to consume the published type
|
|
5
|
+
* declarations. Keep this structural contract aligned with the bundled runtime seam.
|
|
6
|
+
*/
|
|
7
|
+
interface SmartCartMoney {
|
|
8
|
+
readonly amount: number;
|
|
9
|
+
readonly currency: string;
|
|
10
|
+
}
|
|
11
|
+
interface SmartCartLineOption {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly value: string;
|
|
14
|
+
}
|
|
15
|
+
interface SmartCartLineDiscount {
|
|
16
|
+
readonly code: string;
|
|
17
|
+
readonly amount: SmartCartMoney;
|
|
18
|
+
readonly quantity?: number;
|
|
19
|
+
}
|
|
20
|
+
interface SmartCartLine {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly title: string;
|
|
23
|
+
readonly variantTitle: string | null;
|
|
24
|
+
readonly variantId?: string | null;
|
|
25
|
+
readonly quantity: number;
|
|
26
|
+
readonly imageUrl: string | null;
|
|
27
|
+
readonly linePrice: SmartCartMoney;
|
|
28
|
+
readonly productHandle?: string | null;
|
|
29
|
+
readonly compareAtLinePrice?: SmartCartMoney;
|
|
30
|
+
readonly options?: readonly SmartCartLineOption[];
|
|
31
|
+
readonly properties?: readonly SmartCartLineOption[];
|
|
32
|
+
readonly attributes?: Record<string, string>;
|
|
33
|
+
readonly discountAllocations?: readonly SmartCartLineDiscount[];
|
|
34
|
+
readonly originalLinePrice?: SmartCartMoney;
|
|
35
|
+
}
|
|
36
|
+
interface SmartCartState {
|
|
37
|
+
readonly lines: readonly SmartCartLine[];
|
|
38
|
+
readonly subtotal: SmartCartMoney;
|
|
39
|
+
readonly checkoutUrl: string;
|
|
40
|
+
readonly currency: string;
|
|
41
|
+
readonly discountTotal?: SmartCartMoney;
|
|
42
|
+
readonly appliedCodes?: readonly string[];
|
|
43
|
+
readonly discountAllocations?: readonly {
|
|
44
|
+
readonly code: string;
|
|
45
|
+
readonly amount: SmartCartMoney;
|
|
46
|
+
}[];
|
|
47
|
+
}
|
|
48
|
+
interface CartAdapter {
|
|
49
|
+
getCart(): Promise<SmartCartState>;
|
|
50
|
+
addLine(merchandiseId: string, quantity: number, attributes?: Record<string, string>): Promise<SmartCartState>;
|
|
51
|
+
updateLine(lineId: string, quantity: number): Promise<SmartCartState>;
|
|
52
|
+
removeLine(lineId: string): Promise<SmartCartState>;
|
|
53
|
+
updateDiscountCodes(codes: readonly string[]): Promise<SmartCartState>;
|
|
54
|
+
}
|
|
55
|
+
interface SmartCartBranding {
|
|
56
|
+
readonly accent?: string;
|
|
57
|
+
readonly accentText?: string;
|
|
58
|
+
readonly surface?: string;
|
|
59
|
+
readonly text?: string;
|
|
60
|
+
readonly fontFamily?: string;
|
|
61
|
+
readonly radius?: string;
|
|
62
|
+
}
|
|
63
|
+
interface SmartCartMountConfig {
|
|
64
|
+
readonly selectors?: readonly string[];
|
|
65
|
+
readonly branding?: SmartCartBranding;
|
|
66
|
+
readonly widgets?: Record<string, {
|
|
67
|
+
enabled?: boolean;
|
|
68
|
+
} & Record<string, unknown>>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* All fully-resolved cart GraphQL document strings from the react seam adapter.
|
|
73
|
+
* Exported for schema-validation tests (apps/storefront-api/test/cart-graphql-documents.test.ts)
|
|
74
|
+
* that submit each document to a real graphql-yoga instance and assert zero validation errors,
|
|
75
|
+
* catching invalid field selections (e.g. subfields on a scalar) at test time rather than runtime.
|
|
76
|
+
*/
|
|
77
|
+
declare const REACT_SEAM_CART_DOCUMENTS: readonly string[];
|
|
78
|
+
/**
|
|
79
|
+
* A CartAdapter that drives the storefront-api cart over the same-origin /api/storefront GraphQL proxy
|
|
80
|
+
* (the proxy injects the read token + resolves the shop server-side). The theme supplies the cart id
|
|
81
|
+
* (from its loader's cart cookie/session) and renders <CartDrawerOverlay adapter={this} />.
|
|
82
|
+
*/
|
|
83
|
+
declare function createStorefrontApiCartAdapter(opts: {
|
|
84
|
+
readonly cartId: string;
|
|
85
|
+
readonly apiPath?: string;
|
|
86
|
+
readonly fetchImpl?: typeof fetch;
|
|
87
|
+
}): CartAdapter;
|
|
88
|
+
|
|
89
|
+
export { type CartAdapter as C, REACT_SEAM_CART_DOCUMENTS as R, type SmartCartMountConfig as S, type SmartCartBranding as a, type SmartCartLine as b, type SmartCartLineDiscount as c, type SmartCartLineOption as d, type SmartCartMoney as e, type SmartCartState as f, createStorefrontApiCartAdapter as g };
|
package/dist/cart-documents.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export { R as REACT_SEAM_CART_DOCUMENTS } from './cart-documents-
|
|
2
|
-
import '@kotao/smart-cart';
|
|
1
|
+
export { R as REACT_SEAM_CART_DOCUMENTS } from './cart-documents-BLavRDiu.js';
|
package/dist/cart-documents.js
CHANGED
|
@@ -8,6 +8,7 @@ async function fetchThemeSettings(options = {}) {
|
|
|
8
8
|
throw new Error(`theme-settings endpoint must be a same-origin path, got '${endpoint}'`);
|
|
9
9
|
}
|
|
10
10
|
const doFetch = options.fetch ?? fetch;
|
|
11
|
+
const requestEndpoint = options.templateHandle === void 0 ? endpoint : `${endpoint}${endpoint.includes("?") ? "&" : "?"}template=${encodeURIComponent(options.templateHandle)}`;
|
|
11
12
|
const headers = { ...options.shopContextHeaders ?? {} };
|
|
12
13
|
if (options.auth !== void 0) {
|
|
13
14
|
headers[options.auth.tokenHeader ?? "x-kotao-storefront-token"] = options.auth.token;
|
|
@@ -16,11 +17,11 @@ async function fetchThemeSettings(options = {}) {
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
const init = Object.keys(headers).length > 0 ? { headers } : void 0;
|
|
19
|
-
const res = await doFetch(
|
|
20
|
+
const res = await doFetch(requestEndpoint, init);
|
|
20
21
|
if (!res.ok) throw new Error(`theme settings fetch failed: HTTP ${res.status}`);
|
|
21
22
|
return await res.json();
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export { fetchThemeSettings };
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
26
|
-
//# sourceMappingURL=chunk-
|
|
26
|
+
//# sourceMappingURL=chunk-2MRB6SMP.js.map
|
|
27
|
+
//# sourceMappingURL=chunk-2MRB6SMP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/settings/fetch.ts"],"names":[],"mappings":";AAKA,IAAM,gBAAA,GAAmB,cAAA;AACzB,IAAM,cAAA,GAAiB,aAAA;AACvB,IAAM,gBAAA,GAAmB,0BAAA;AAkDzB,eAAsB,kBAAA,CACpB,OAAA,GAAqC,EAAC,EACR;AAC9B,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,gBAAA;AACrC,EAAA,IACE,CAAC,gBAAA,CAAiB,IAAA,CAAK,QAAQ,CAAA,IAC/B,EAAE,OAAA,CAAQ,gBAAA,KAAqB,IAAA,IAAQ,cAAA,CAAe,IAAA,CAAK,QAAQ,CAAA,CAAA,EACnE;AACA,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yDAAA,EAA4D,QAAQ,CAAA,CAAA,CAAG,CAAA;AAAA,EACzF;AACA,EAAA,MAAM,OAAA,GAAU,QAAQ,KAAA,IAAS,KAAA;AACjC,EAAA,MAAM,kBACJ,OAAA,CAAQ,cAAA,KAAmB,SACvB,QAAA,GACA,CAAA,EAAG,QAAQ,CAAA,EAAG,QAAA,CAAS,QAAA,CAAS,GAAG,IAAI,GAAA,GAAM,GAAG,YAAY,kBAAA,CAAmB,OAAA,CAAQ,cAAc,CAAC,CAAA,CAAA;AAC5G,EAAA,MAAM,UAAkC,EAAE,GAAI,OAAA,CAAQ,kBAAA,IAAsB,EAAC,EAAG;AAChF,EAAA,IAAI,OAAA,CAAQ,SAAS,MAAA,EAAW;AAC9B,IAAA,OAAA,CAAQ,QAAQ,IAAA,CAAK,WAAA,IAAe,0BAA0B,CAAA,GAAI,QAAQ,IAAA,CAAK,KAAA;AAC/E,IAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,MAAA,KAAW,MAAA,IAAa,OAAA,CAAQ,KAAK,MAAA,CAAO,IAAA,EAAK,CAAE,MAAA,GAAS,CAAA,EAAG;AAC9E,MAAA,OAAA,CAAQ,iBAAiB,CAAA,GAAI,OAAA,CAAQ,IAAA,CAAK,MAAA;AAAA,IAC5C;AAAA,EACF;AACA,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,CAAK,OAAO,EAAE,MAAA,GAAS,CAAA,GAAI,EAAE,OAAA,EAAQ,GAAI,MAAA;AAC7D,EAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,eAAA,EAAiB,IAAI,CAAA;AAC/C,EAAA,IAAI,CAAC,IAAI,EAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAC9E,EAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AACzB","file":"chunk-2MRB6SMP.js","sourcesContent":["import type { SectionInstance, ValuesDocument } from '@kotao/storefront-contracts/theme'\n\nimport type { StorefrontAuthHeader } from '../storefront-client/client'\n\n/** A single leading slash, not protocol-relative (`//`/`\\`) — keeps the fetch same-origin (no exfil). */\nconst SAME_ORIGIN_PATH = /^\\/(?![/\\\\])/\nconst HTTPS_ENDPOINT = /^https:\\/\\//\nconst DEFAULT_ENDPOINT = '/api/storefront/settings'\n\n/**\n * The stored settings a theme hydrates from (#93): the layout document's ordered section instances +\n * the global theme tokens. Pass to {@link resolveThemeSettings} together with the theme's bundled\n * section schemas + presets to produce the merged {@link ThemeSettingsSnapshot}.\n */\nexport interface StoredThemeSettings {\n readonly shopId: string\n readonly sections: readonly SectionInstance[]\n readonly global: Record<string, unknown>\n readonly templates?: Readonly<Partial<Record<string, ValuesDocument>>>\n readonly sectionGroups?: Readonly<Partial<Record<string, ValuesDocument>>>\n}\n\nexport interface FetchThemeSettingsOptions {\n /** Injectable for tests; defaults to the global `fetch`. */\n readonly fetch?: typeof fetch\n /** Same-origin settings endpoint (default `/api/storefront/settings`). */\n readonly endpoint?: string\n /**\n * Restrict the response to one rendered template plus the base commerce templates and layout\n * groups needed for a complete page. Omit for the legacy/full editor document.\n */\n readonly templateHandle?: string\n /**\n * Explicit local-preview escape hatch for server-side theme workers that call the Kotao API directly.\n * Production themes should keep the default same-origin path.\n */\n readonly allowCrossOrigin?: boolean\n /** Optional server-side auth headers for local previews. Never pass browser-visible tokens here. */\n readonly auth?: {\n readonly token: string\n readonly tokenHeader?: StorefrontAuthHeader\n readonly siteId?: string\n }\n /**\n * Gateway-signed shop-context headers (`x-kotao-shop` + `x-kotao-shop-signature`) to forward to the\n * upstream, mirroring the storefront GraphQL client. Required for the SSR worker path: a Worker\n * subrequest to its own zone bypasses the Gateway, so the shop context has to be re-attached\n * explicitly and the request sent cross-origin to the API. `context.loadThemeSettings()` wires this\n * automatically from the inbound request; pass it by hand only when calling `fetchThemeSettings` raw.\n */\n readonly shopContextHeaders?: Readonly<Record<string, string>>\n}\n\n/**\n * Fetch the shop's stored settings document via the same-origin `/api/storefront/settings` carve-out.\n * The shop is resolved server-side from the Gateway-signed context — the theme sends no id and no token.\n */\nexport async function fetchThemeSettings(\n options: FetchThemeSettingsOptions = {},\n): Promise<StoredThemeSettings> {\n const endpoint = options.endpoint ?? DEFAULT_ENDPOINT\n if (\n !SAME_ORIGIN_PATH.test(endpoint) &&\n !(options.allowCrossOrigin === true && HTTPS_ENDPOINT.test(endpoint))\n ) {\n throw new Error(`theme-settings endpoint must be a same-origin path, got '${endpoint}'`)\n }\n const doFetch = options.fetch ?? fetch\n const requestEndpoint =\n options.templateHandle === undefined\n ? endpoint\n : `${endpoint}${endpoint.includes('?') ? '&' : '?'}template=${encodeURIComponent(options.templateHandle)}`\n const headers: Record<string, string> = { ...(options.shopContextHeaders ?? {}) }\n if (options.auth !== undefined) {\n headers[options.auth.tokenHeader ?? 'x-kotao-storefront-token'] = options.auth.token\n if (options.auth.siteId !== undefined && options.auth.siteId.trim().length > 0) {\n headers['x-kotao-site-id'] = options.auth.siteId\n }\n }\n const init = Object.keys(headers).length > 0 ? { headers } : undefined\n const res = await doFetch(requestEndpoint, init)\n if (!res.ok) throw new Error(`theme settings fetch failed: HTTP ${res.status}`)\n return (await res.json()) as StoredThemeSettings\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/geo/base64url.ts
|
|
2
|
+
var toBase64Url = (bytes) => {
|
|
3
|
+
let bin = "";
|
|
4
|
+
for (const b of bytes) bin += String.fromCharCode(b);
|
|
5
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
6
|
+
};
|
|
7
|
+
var fromBase64Url = (s) => {
|
|
8
|
+
const b64 = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
9
|
+
const bin = atob(b64);
|
|
10
|
+
const out = new Uint8Array(bin.length);
|
|
11
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
12
|
+
return out;
|
|
13
|
+
};
|
|
14
|
+
var encodeUtf8Base64Url = (text) => toBase64Url(new TextEncoder().encode(text));
|
|
15
|
+
var decodeBase64UrlUtf8 = (s) => new TextDecoder().decode(fromBase64Url(s));
|
|
16
|
+
|
|
17
|
+
export { decodeBase64UrlUtf8, encodeUtf8Base64Url, fromBase64Url, toBase64Url };
|
|
18
|
+
//# sourceMappingURL=chunk-CKGI3Y7L.js.map
|
|
19
|
+
//# sourceMappingURL=chunk-CKGI3Y7L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/geo/base64url.ts"],"names":[],"mappings":";AAAA,IAAM,WAAA,GAAc,CAAC,KAAA,KAA8B;AACjD,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,EAAO,GAAA,IAAO,MAAA,CAAO,aAAa,CAAC,CAAA;AACnD,EAAA,OAAO,IAAA,CAAK,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC5E;AAEA,IAAM,aAAA,GAAgB,CAAC,CAAA,KAA0B;AAC/C,EAAA,MAAM,GAAA,GAAM,EAAE,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAM,GAAG,CAAA;AAClD,EAAA,MAAM,GAAA,GAAM,KAAK,GAAG,CAAA;AACpB,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AACrC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,CAAA,EAAA,EAAK,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA,CAAI,UAAA,CAAW,CAAC,CAAA;AAC9D,EAAA,OAAO,GAAA;AACT;AAEA,IAAM,mBAAA,GAAsB,CAAC,IAAA,KAAyB,WAAA,CAAY,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,IAAI,CAAC;AAChG,IAAM,mBAAA,GAAsB,CAAC,CAAA,KAAsB,IAAI,aAAY,CAAE,MAAA,CAAO,aAAA,CAAc,CAAC,CAAC","file":"chunk-CKGI3Y7L.js","sourcesContent":["const toBase64Url = (bytes: Uint8Array): string => {\n let bin = ''\n for (const b of bytes) bin += String.fromCharCode(b)\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nconst fromBase64Url = (s: string): Uint8Array => {\n const b64 = s.replace(/-/g, '+').replace(/_/g, '/')\n const bin = atob(b64)\n const out = new Uint8Array(bin.length)\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\nconst encodeUtf8Base64Url = (text: string): string => toBase64Url(new TextEncoder().encode(text))\nconst decodeBase64UrlUtf8 = (s: string): string => new TextDecoder().decode(fromBase64Url(s))\n\nexport { decodeBase64UrlUtf8, encodeUtf8Base64Url, fromBase64Url, toBase64Url }\n"]}
|