@sparkletree/core 0.1.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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -0
  3. package/dist/analytics.d.ts +75 -0
  4. package/dist/analytics.d.ts.map +1 -0
  5. package/dist/analytics.js +170 -0
  6. package/dist/analytics.js.map +1 -0
  7. package/dist/audio.d.ts +85 -0
  8. package/dist/audio.d.ts.map +1 -0
  9. package/dist/audio.js +465 -0
  10. package/dist/audio.js.map +1 -0
  11. package/dist/client.d.ts +79 -0
  12. package/dist/client.d.ts.map +1 -0
  13. package/dist/client.js +251 -0
  14. package/dist/client.js.map +1 -0
  15. package/dist/context.d.ts +104 -0
  16. package/dist/context.d.ts.map +1 -0
  17. package/dist/context.js +277 -0
  18. package/dist/context.js.map +1 -0
  19. package/dist/fragments.d.ts +108 -0
  20. package/dist/fragments.d.ts.map +1 -0
  21. package/dist/fragments.js +223 -0
  22. package/dist/fragments.js.map +1 -0
  23. package/dist/index.d.ts +31 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +30 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/protocol.d.ts +70 -0
  28. package/dist/protocol.d.ts.map +1 -0
  29. package/dist/protocol.js +97 -0
  30. package/dist/protocol.js.map +1 -0
  31. package/dist/publishableKey.d.ts +38 -0
  32. package/dist/publishableKey.d.ts.map +1 -0
  33. package/dist/publishableKey.js +69 -0
  34. package/dist/publishableKey.js.map +1 -0
  35. package/dist/safeUrl.d.ts +56 -0
  36. package/dist/safeUrl.d.ts.map +1 -0
  37. package/dist/safeUrl.js +117 -0
  38. package/dist/safeUrl.js.map +1 -0
  39. package/dist/sse.d.ts +51 -0
  40. package/dist/sse.d.ts.map +1 -0
  41. package/dist/sse.js +137 -0
  42. package/dist/sse.js.map +1 -0
  43. package/dist/state.d.ts +321 -0
  44. package/dist/state.d.ts.map +1 -0
  45. package/dist/state.js +594 -0
  46. package/dist/state.js.map +1 -0
  47. package/dist/text.d.ts +10 -0
  48. package/dist/text.d.ts.map +1 -0
  49. package/dist/text.js +29 -0
  50. package/dist/text.js.map +1 -0
  51. package/dist/theme.d.ts +52 -0
  52. package/dist/theme.d.ts.map +1 -0
  53. package/dist/theme.js +88 -0
  54. package/dist/theme.js.map +1 -0
  55. package/dist/trust.d.ts +52 -0
  56. package/dist/trust.d.ts.map +1 -0
  57. package/dist/trust.js +95 -0
  58. package/dist/trust.js.map +1 -0
  59. package/dist/variant.d.ts +117 -0
  60. package/dist/variant.d.ts.map +1 -0
  61. package/dist/variant.js +167 -0
  62. package/dist/variant.js.map +1 -0
  63. package/dist/wire.d.ts +564 -0
  64. package/dist/wire.d.ts.map +1 -0
  65. package/dist/wire.js +133 -0
  66. package/dist/wire.js.map +1 -0
  67. package/package.json +55 -0
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Fragments — the core client for Declarative Context rung 2 (spec §2.3/§4.3).
3
+ *
4
+ * The keys and fallback strings the developer writes ARE the request schema:
5
+ * there is nothing to create in a dashboard before the first render. The flow
6
+ * is fixed and deliberately boring:
7
+ *
8
+ * 1. The caller's fallbacks are the result shape, synchronously computable.
9
+ * 2. ctxhash + schemahash are computed locally (declared dims ONLY — env
10
+ * signals never enter the fragment identity, so cardinality stays "the
11
+ * number of call sites in the org's source").
12
+ * 3. One cacheable GET. Warm hit → serve those fields; anything else → the
13
+ * fallbacks stand.
14
+ * 4. On a miss with `pending: true`, ONE fire-and-forget POST /mint,
15
+ * deduplicated per session. No second GET, no polling, no SSE — twenty
16
+ * tokens do not need choreography.
17
+ *
18
+ * `fetchFragments` NEVER rejects. Any failure — network, malformed body,
19
+ * hashing, a hostile response — resolves to fallback-shaped fields with
20
+ * source "static". The developer's copy is the floor.
21
+ */
22
+ import { type DeclaredContext } from "./context.js";
23
+ import type { FieldState } from "./state.js";
24
+ import type { ContentSource, FragmentKind, FragmentWarmth } from "./wire.js";
25
+ /** Bare-string shorthand: `"Sign in"` means `{ kind: "body", fallback: "Sign in" }`. */
26
+ export type FragmentFieldSpec = string | {
27
+ kind?: FragmentKind;
28
+ fallback: string;
29
+ };
30
+ /**
31
+ * A signed mint token, or a function producing one.
32
+ *
33
+ * The token is minted by the CUSTOMER'S BACKEND (POST /fragments/mint-token
34
+ * with an org-pinned `st_` key) and is bound to one (org, ctxhash, schemahash)
35
+ * for 300 seconds. The browser only echoes it. The callback form exists
36
+ * because of that TTL: a page open longer than five minutes needs a fresh
37
+ * token at mint time, not the one that shipped with the HTML.
38
+ */
39
+ export type MintTokenSource = string | (() => string | null | undefined | Promise<string | null | undefined>);
40
+ export interface FetchFragmentsOptions {
41
+ organizationId: string;
42
+ apiBase: string;
43
+ context?: DeclaredContext;
44
+ fields: Record<string, FragmentFieldSpec>;
45
+ /** Sent on the mint POST only — never on the GET, which is a shared CDN
46
+ * object and must be byte-identical for every caller. Optional: without it
47
+ * the mint goes unsigned and the server admits it or not. */
48
+ mintToken?: MintTokenSource;
49
+ /** Where `apiBase` came from. The publishable key is an unsigned address
50
+ * anyone can hand-encode, so a key-derived apiBase earns content fetches
51
+ * but NOT the mint POST (which carries the signed token — a real spend
52
+ * credential — and the declared dims) unless the host is first-party or
53
+ * loopback (S-2). Defaults to "explicit": a caller passing apiBase
54
+ * directly has chosen it themselves. */
55
+ apiBaseProvenance?: "explicit" | "key";
56
+ /** Test seam; defaults to the platform fetch. */
57
+ fetchImpl?: typeof fetch;
58
+ }
59
+ export interface FragmentsResult {
60
+ /** One FieldState per requested key — the exact shape islands produce. */
61
+ fields: Record<string, FieldState>;
62
+ /** Locally computed declared-context hash. Third leg of the pin key. */
63
+ contextHash: string;
64
+ warmth: FragmentWarmth;
65
+ /** decideChrome over the strongest served provenance (cached counts as
66
+ * adapted). The group-level Art. 50 disclosure hangs off this. */
67
+ marked: boolean;
68
+ }
69
+ /** The normalized request schema: what /mint receives, what schemahash covers. */
70
+ export interface NormalizedFragmentField {
71
+ key: string;
72
+ kind: FragmentKind;
73
+ budget: number;
74
+ fallback: string;
75
+ }
76
+ /** Expand shorthands and derive budgets. Deterministic: same fields object →
77
+ * same schema → same schemahash. */
78
+ export declare function normalizeFieldSpecs(fields: Record<string, FragmentFieldSpec>): NormalizedFragmentField[];
79
+ /** Strongest provenance across a set of field states (static < cached < generated). */
80
+ export declare function strongestFragmentSource(fields: Iterable<FieldState>): ContentSource;
81
+ /**
82
+ * Resolve fragments for a declared context. Resolves fast; NEVER rejects;
83
+ * fallback-shaped on any failure.
84
+ */
85
+ export declare function fetchFragments(options: FetchFragmentsOptions): Promise<FragmentsResult>;
86
+ export interface CreateClientOptions {
87
+ /** `st_pk_…` from the dashboard. An address, not a credential (see
88
+ * publishableKey.ts) — explicit organizationId/apiBase win over it. */
89
+ publishableKey?: string;
90
+ organizationId?: string;
91
+ apiBase?: string;
92
+ /** Signed mint token (or a function returning one), sent on the mint POST. */
93
+ mintToken?: MintTokenSource;
94
+ fetchImpl?: typeof fetch;
95
+ }
96
+ export interface SparkletreeClient {
97
+ fragments(options: {
98
+ context?: DeclaredContext;
99
+ fields: Record<string, FragmentFieldSpec>;
100
+ }): Promise<FragmentsResult>;
101
+ }
102
+ /**
103
+ * Vanilla entry point, in core where the wire lives. Throws TypeError on a
104
+ * malformed key or missing configuration — setup errors surface at setup
105
+ * time; only the resolved `fragments()` call is the never-rejects path.
106
+ */
107
+ export declare function createClient(options: CreateClientOptions): SparkletreeClient;
108
+ //# sourceMappingURL=fragments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragments.d.ts","sourceRoot":"","sources":["../src/fragments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EAEf,MAAM,WAAW,CAAC;AAEnB,wFAAwF;AACxF,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC;AAE3E,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC1C;;iEAE6D;IAC7D,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;;;;4CAKwC;IACxC,iBAAiB,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;IACvC,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB;sEACkE;IAClE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,kFAAkF;AAClF,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD;oCACoC;AACpC,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GACxC,uBAAuB,EAAE,CAU3B;AAED,uFAAuF;AACvF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,aAAa,CAMnF;AAqFD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CA+D7F;AAID,MAAM,WAAW,mBAAmB;IAClC;2EACuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,OAAO,EAAE;QACjB,OAAO,CAAC,EAAE,eAAe,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;KAC3C,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,iBAAiB,CA+B5E"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Fragments — the core client for Declarative Context rung 2 (spec §2.3/§4.3).
3
+ *
4
+ * The keys and fallback strings the developer writes ARE the request schema:
5
+ * there is nothing to create in a dashboard before the first render. The flow
6
+ * is fixed and deliberately boring:
7
+ *
8
+ * 1. The caller's fallbacks are the result shape, synchronously computable.
9
+ * 2. ctxhash + schemahash are computed locally (declared dims ONLY — env
10
+ * signals never enter the fragment identity, so cardinality stays "the
11
+ * number of call sites in the org's source").
12
+ * 3. One cacheable GET. Warm hit → serve those fields; anything else → the
13
+ * fallbacks stand.
14
+ * 4. On a miss with `pending: true`, ONE fire-and-forget POST /mint,
15
+ * deduplicated per session. No second GET, no polling, no SSE — twenty
16
+ * tokens do not need choreography.
17
+ *
18
+ * `fetchFragments` NEVER rejects. Any failure — network, malformed body,
19
+ * hashing, a hostile response — resolves to fallback-shaped fields with
20
+ * source "static". The developer's copy is the floor.
21
+ */
22
+ import { computeFieldBudget, computeSchemaHash, declaredToDims, hashDeclaredContext, } from "./context.js";
23
+ import { decodePublishableKey } from "./publishableKey.js";
24
+ import { isFirstPartyApiBase, isSecureApiBase } from "./safeUrl.js";
25
+ import { decideChrome } from "./trust.js";
26
+ import { FRAGMENT_KINDS, FRAGMENT_WARMTHS } from "./wire.js";
27
+ const VALID_SOURCES = new Set(["generated", "cached", "static"]);
28
+ const SOURCE_RANK = { static: 0, cached: 1, generated: 2 };
29
+ /** Expand shorthands and derive budgets. Deterministic: same fields object →
30
+ * same schema → same schemahash. */
31
+ export function normalizeFieldSpecs(fields) {
32
+ return Object.entries(fields).map(([key, spec]) => {
33
+ const expanded = typeof spec === "string" ? { fallback: spec } : spec;
34
+ const kind = expanded.kind && FRAGMENT_KINDS.includes(expanded.kind)
35
+ ? expanded.kind
36
+ : "body";
37
+ const fallback = expanded.fallback ?? "";
38
+ return { key, kind, budget: computeFieldBudget(fallback, kind), fallback };
39
+ });
40
+ }
41
+ /** Strongest provenance across a set of field states (static < cached < generated). */
42
+ export function strongestFragmentSource(fields) {
43
+ let strongest = "static";
44
+ for (const field of fields) {
45
+ if (SOURCE_RANK[field.source] > SOURCE_RANK[strongest])
46
+ strongest = field.source;
47
+ }
48
+ return strongest;
49
+ }
50
+ /** FieldState for fragment copy. Fragments never type: text is set once,
51
+ * settled, with no caret — the single rewrite, not choreography. */
52
+ function fragmentField(text, source) {
53
+ return { text, source, mode: null, typing: false, settled: true };
54
+ }
55
+ function fallbackFields(schema) {
56
+ return Object.fromEntries(schema.map((f) => [f.key, fragmentField(f.fallback, "static")]));
57
+ }
58
+ /** The header the mint POST echoes the signed token on. */
59
+ const MINT_TOKEN_HEADER = "x-st-mint-token";
60
+ /**
61
+ * Resolve a mint token to a header-ready string, or "" for "send no header".
62
+ *
63
+ * Defensive on purpose: the callback reaches into the host app's auth code,
64
+ * and a token endpoint that is down, slow or throwing must cost a mint at
65
+ * worst — never a render. The server decides admission; an unsigned mint is a
66
+ * refusal it can make cheaply, and the fallback copy already shipped.
67
+ */
68
+ async function resolveMintToken(source) {
69
+ try {
70
+ const value = typeof source === "function" ? await source() : source;
71
+ return typeof value === "string" ? value.trim() : "";
72
+ }
73
+ catch {
74
+ return "";
75
+ }
76
+ }
77
+ /**
78
+ * Fire the one permitted mint for this (ctxhash, schemahash), deduplicated in
79
+ * sessionStorage. Outside a browser there is no page view to warm — skip
80
+ * entirely. In a privacy mode where sessionStorage throws, the POST still
81
+ * fires once per call; the server's queue dedup (SET NX) absorbs repeats.
82
+ */
83
+ function maybeMint(options, schema, contextHash, schemaHash) {
84
+ if (typeof window === "undefined")
85
+ return;
86
+ // S-2: a key-derived apiBase is an address anyone can hand-encode. The mint
87
+ // POST carries the signed token (a spend credential) and the declared dims,
88
+ // so it only follows an apiBase the developer chose explicitly, or one
89
+ // provably first-party/loopback. Withheld, fragments simply stay cold —
90
+ // the fallback already shipped, and nothing leaks.
91
+ if (options.apiBaseProvenance === "key" && !isFirstPartyApiBase(options.apiBase))
92
+ return;
93
+ const dedupKey = `st:frag:mint:${contextHash}:${schemaHash}`;
94
+ try {
95
+ if (window.sessionStorage.getItem(dedupKey) === "1")
96
+ return;
97
+ window.sessionStorage.setItem(dedupKey, "1");
98
+ }
99
+ catch {
100
+ // SSR shims and private modes may throw on ACCESS; dedup is best-effort.
101
+ }
102
+ const doFetch = options.fetchImpl ?? fetch;
103
+ const url = new URL("/api/embed/v1/fragments/mint", options.apiBase);
104
+ // Fire-and-forget: the response is ignored except in dev, and a failed mint
105
+ // is indistinguishable from a cold cache — the fallback already shipped.
106
+ void Promise.resolve()
107
+ .then(async () => {
108
+ const token = await resolveMintToken(options.mintToken);
109
+ return doFetch(url.toString(), {
110
+ method: "POST",
111
+ headers: {
112
+ "Content-Type": "application/json",
113
+ // Absent, not empty: a blank token is a PRESENT-but-bad token to the
114
+ // server, which refuses outright rather than falling back to Origin.
115
+ ...(token ? { [MINT_TOKEN_HEADER]: token } : {}),
116
+ },
117
+ body: JSON.stringify({
118
+ organization: options.organizationId,
119
+ // Declared dims only, short-keyed — the server re-canonicalizes and
120
+ // recomputes both hashes; ours are cache hints, never identity.
121
+ context: declaredToDims(options.context ?? {}),
122
+ schema,
123
+ }),
124
+ });
125
+ })
126
+ .catch(() => { });
127
+ }
128
+ /**
129
+ * Resolve fragments for a declared context. Resolves fast; NEVER rejects;
130
+ * fallback-shaped on any failure.
131
+ */
132
+ export async function fetchFragments(options) {
133
+ const schema = normalizeFieldSpecs(options.fields);
134
+ // Same apiBase rule as openStream/fetchContent: this path is reached
135
+ // directly by the React bindings, which never go through createClient —
136
+ // without the guard here, an http: apiBase would carry context and the
137
+ // mint token over plaintext from the flagship integration path.
138
+ if (!isSecureApiBase(options.apiBase)) {
139
+ return { fields: fallbackFields(schema), contextHash: "", warmth: "cold", marked: false };
140
+ }
141
+ let contextHash = "";
142
+ try {
143
+ const [context, schemaHash] = await Promise.all([
144
+ hashDeclaredContext(options.context ?? {}),
145
+ computeSchemaHash(schema),
146
+ ]);
147
+ contextHash = context.hash;
148
+ const url = new URL("/api/embed/v1/fragments", options.apiBase);
149
+ // Identity only — no prose, no SDK params: this URL is a shared CDN
150
+ // object and every extra param would fragment the cache.
151
+ url.searchParams.set("o", options.organizationId);
152
+ url.searchParams.set("c", contextHash);
153
+ url.searchParams.set("s", schemaHash);
154
+ const doFetch = options.fetchImpl ?? fetch;
155
+ const response = await doFetch(url.toString());
156
+ if (!response.ok) {
157
+ return { fields: fallbackFields(schema), contextHash, warmth: "cold", marked: false };
158
+ }
159
+ const body = (await response.json());
160
+ const served = body && typeof body === "object" && body.fragments && typeof body.fragments === "object"
161
+ ? body.fragments
162
+ : {};
163
+ // Only keys we asked for, only shapes we recognize; everything else —
164
+ // extras, missing keys, unknown provenance — is the fallback. A response
165
+ // is a suggestion; the schema is the contract.
166
+ const fields = {};
167
+ for (const field of schema) {
168
+ const candidate = served[field.key];
169
+ fields[field.key] =
170
+ candidate &&
171
+ typeof candidate.text === "string" &&
172
+ candidate.text !== "" &&
173
+ VALID_SOURCES.has(candidate.source)
174
+ ? fragmentField(candidate.text, candidate.source)
175
+ : fragmentField(field.fallback, "static");
176
+ }
177
+ const warmth = body?.warmth && FRAGMENT_WARMTHS.includes(body.warmth)
178
+ ? body.warmth
179
+ : "cold";
180
+ if (body?.pending === true)
181
+ maybeMint(options, schema, contextHash, schemaHash);
182
+ // Core has no viewer preference to consult; the React layer re-decides
183
+ // with `prefersStandard`. This is the provenance-honest default.
184
+ const marked = decideChrome(strongestFragmentSource(Object.values(fields)), false).marked;
185
+ return { fields, contextHash, warmth, marked };
186
+ }
187
+ catch {
188
+ return { fields: fallbackFields(schema), contextHash, warmth: "cold", marked: false };
189
+ }
190
+ }
191
+ /**
192
+ * Vanilla entry point, in core where the wire lives. Throws TypeError on a
193
+ * malformed key or missing configuration — setup errors surface at setup
194
+ * time; only the resolved `fragments()` call is the never-rejects path.
195
+ */
196
+ export function createClient(options) {
197
+ const decoded = options.publishableKey ? decodePublishableKey(options.publishableKey) : null;
198
+ const organizationId = options.organizationId ?? decoded?.organizationId;
199
+ const apiBase = options.apiBase ?? decoded?.apiBase;
200
+ if (!organizationId || !apiBase) {
201
+ throw new TypeError("SparkleTree: createClient needs a publishableKey, or organizationId + apiBase.");
202
+ }
203
+ // Setup errors surface at setup time: an apiBase that is neither https nor
204
+ // loopback http would send org configuration over a channel any middlebox
205
+ // can rewrite. Refuse here, where a throw is the package's documented
206
+ // contract for misconfiguration, rather than per-request.
207
+ if (!isSecureApiBase(apiBase)) {
208
+ throw new TypeError("SparkleTree: createClient apiBase must be https (http is allowed for localhost only).");
209
+ }
210
+ return {
211
+ fragments: (callOptions) => fetchFragments({
212
+ organizationId,
213
+ apiBase,
214
+ // An explicit apiBase is the developer's own choice; a key-derived
215
+ // one is an unsigned address and earns no mint (see maybeMint, S-2).
216
+ apiBaseProvenance: options.apiBase ? "explicit" : "key",
217
+ mintToken: options.mintToken,
218
+ fetchImpl: options.fetchImpl,
219
+ ...callOptions,
220
+ }),
221
+ };
222
+ }
223
+ //# sourceMappingURL=fragments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragments.js","sourceRoot":"","sources":["../src/fragments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GAEpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AA+D7D,MAAM,aAAa,GAAG,IAAI,GAAG,CAAgB,CAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AAChF,MAAM,WAAW,GAAkC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;AAE1F;oCACoC;AACpC,MAAM,UAAU,mBAAmB,CACjC,MAAyC;IAEzC,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE;QAChD,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACtE,MAAM,IAAI,GACR,QAAQ,CAAC,IAAI,IAAK,cAAoC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC5E,CAAC,CAAC,QAAQ,CAAC,IAAI;YACf,CAAC,CAAC,MAAM,CAAC;QACb,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;QACzC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,uBAAuB,CAAC,MAA4B;IAClE,IAAI,SAAS,GAAkB,QAAQ,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC;YAAE,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;IACnF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;oEACoE;AACpE,SAAS,aAAa,CAAC,IAAY,EAAE,MAAqB;IACxD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACpE,CAAC;AAED,SAAS,cAAc,CAAC,MAAiC;IACvD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,2DAA2D;AAC3D,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAE5C;;;;;;;GAOG;AACH,KAAK,UAAU,gBAAgB,CAAC,MAAmC;IACjE,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QACrE,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,SAAS,CAChB,OAA8B,EAC9B,MAAiC,EACjC,WAAmB,EACnB,UAAkB;IAElB,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO;IAC1C,4EAA4E;IAC5E,4EAA4E;IAC5E,uEAAuE;IACvE,wEAAwE;IACxE,mDAAmD;IACnD,IAAI,OAAO,CAAC,iBAAiB,KAAK,KAAK,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO;IACzF,MAAM,QAAQ,GAAG,gBAAgB,WAAW,IAAI,UAAU,EAAE,CAAC;IAC7D,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,GAAG;YAAE,OAAO;QAC5D,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,8BAA8B,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,4EAA4E;IAC5E,yEAAyE;IACzE,KAAK,OAAO,CAAC,OAAO,EAAE;SACnB,IAAI,CAAC,KAAK,IAAI,EAAE;QACf,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACxD,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YAC7B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,qEAAqE;gBACrE,qEAAqE;gBACrE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACjD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,YAAY,EAAE,OAAO,CAAC,cAAc;gBACpC,oEAAoE;gBACpE,gEAAgE;gBAChE,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;gBAC9C,MAAM;aACP,CAAC;SACH,CAAC,CAAC;IACL,CAAC,CAAC;SACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAA8B;IACjE,MAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,qEAAqE;IACrE,wEAAwE;IACxE,uEAAuE;IACvE,gEAAgE;IAChE,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC5F,CAAC;IACD,IAAI,WAAW,GAAG,EAAE,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC9C,mBAAmB,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;YAC1C,iBAAiB,CAAC,MAAM,CAAC;SAC1B,CAAC,CAAC;QACH,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;QAE3B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,yBAAyB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAChE,oEAAoE;QACpE,yDAAyD;QACzD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QAClD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACvC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAEtC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;QAC3C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QACxF,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAsC,CAAC;QAC1E,MAAM,MAAM,GACV,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,SAAS,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ;YACtF,CAAC,CAAC,IAAI,CAAC,SAAS;YAChB,CAAC,CAAC,EAAE,CAAC;QAET,sEAAsE;QACtE,yEAAyE;QACzE,+CAA+C;QAC/C,MAAM,MAAM,GAA+B,EAAE,CAAC;QAC9C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACpC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;gBACf,SAAS;oBACT,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;oBAClC,SAAS,CAAC,IAAI,KAAK,EAAE;oBACrB,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC;oBACjC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC;oBACjD,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,MAAM,GACV,IAAI,EAAE,MAAM,IAAK,gBAAsC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;YAC3E,CAAC,CAAC,IAAI,CAAC,MAAM;YACb,CAAC,CAAC,MAAM,CAAC;QACb,IAAI,IAAI,EAAE,OAAO,KAAK,IAAI;YAAE,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;QAEhF,uEAAuE;QACvE,iEAAiE;QACjE,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC;QAC1F,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACxF,CAAC;AACH,CAAC;AAsBD;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,OAA4B;IACvD,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7F,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,OAAO,EAAE,cAAc,CAAC;IACzE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,EAAE,OAAO,CAAC;IACpD,IAAI,CAAC,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CACjB,gFAAgF,CACjF,CAAC;IACJ,CAAC;IACD,2EAA2E;IAC3E,0EAA0E;IAC1E,sEAAsE;IACtE,0DAA0D;IAC1D,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CACjB,uFAAuF,CACxF,CAAC;IACJ,CAAC;IACD,OAAO;QACL,SAAS,EAAE,CAAC,WAAW,EAAE,EAAE,CACzB,cAAc,CAAC;YACb,cAAc;YACd,OAAO;YACP,mEAAmE;YACnE,qEAAqE;YACrE,iBAAiB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK;YACvD,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,GAAG,WAAW;SACf,CAAC;KACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @sparkletree/core — the framework-agnostic half of the SparkleTree SDK.
3
+ *
4
+ * Everything that touches the wire lives here, and ONLY here. Components
5
+ * distributed by `sparkletree add` are copied into a customer's repo and are
6
+ * therefore un-patchable by us; they must stay wire-ignorant, rendering state
7
+ * this package hands them. That split is what lets a protocol change ship as a
8
+ * version bump instead of a migration guide.
9
+ *
10
+ * Wire types are re-exported so consumers never import the generated contract
11
+ * directly — that path is an implementation detail and would make the
12
+ * generated artifacts part of the public API.
13
+ */
14
+ export type { ContentSource, CopyMode, DegradeReason, DoneMeta, FragmentField, FragmentKind, FragmentWarmth, FragmentsResponse, ThemePayload, WireEventName, } from "./wire.js";
15
+ export { FRAGMENT_KINDS, FRAGMENT_WARMTHS } from "./wire.js";
16
+ export { PROTOCOL_CURRENT, PROTOCOL_DEFAULT, PROTOCOL_HEADER, PROTOCOL_PARAM, PROTOCOL_VERSIONS, SDK_PARAM, SDK_PARAM_VALUE, VARIANT_PARAM, buildContentUrl, buildStreamUrl, negotiatedProtocol, type StreamTarget, } from "./protocol.js";
17
+ export { SseParser, readSseStream, type SseMessage } from "./sse.js";
18
+ export { isFirstPartyApiBase, isSecureApiBase, safeActionUrl } from "./safeUrl.js";
19
+ export { CONTEXT_DAYPARTS, CONTEXT_DAY_TYPES, CONTEXT_DEVICES, CONTEXT_INTENTS, CONTEXT_SURFACE_TYPES, CONTEXT_TEMP_BANDS, CONTEXT_WEATHER, FRAGMENT_KIND_FLOORS, MAX_CUSTOM_DIMS, MAX_NOTES_LENGTH, canonicalContextString, computeContextHash, computeFieldBudget, computeSchemaHash, declaredToDims, hashDeclaredContext, normalizeDims, normalizeNotes, type CanonicalDims, type DeclaredContext, type NormalizeResult, } from "./context.js";
20
+ export { COPY_FIELDS, COPY_HOLD_MS, CopyChoreographer, type ChoreographerOptions, type CopyField, type CreativeState, type FieldState, type Phase, } from "./state.js";
21
+ export { fetchContent, openStream, type ContentSnapshot, type StreamHandle, type StreamOptions, } from "./client.js";
22
+ export { TOKEN_PREFIX, applyTheme, themeStyle, tokenName, tokenSource, type ResolvedTheme, } from "./theme.js";
23
+ export { STANDARD_MODE_KEY, decideChrome, setViewerPrefersStandard, viewerPrefersStandard, type ChromeDecision, } from "./trust.js";
24
+ export { ImpressionRecorder, observeVisibility, sessionId, track, type AnalyticsContext, type EventType, type ImpressionDetail, type VisibilityOptions, } from "./analytics.js";
25
+ export { RESERVATION_TIMEOUT_MS, VariantRegistry, pageVariants, type FollowerReservation, type LeaderReservation, type VariantReservation, } from "./variant.js";
26
+ export { activePlayer, destroyActiveAudio, mountAudio, type AudioBlock, type AudioCapabilities, type AudioEvent, type AudioHandle, type AudioProvider, type AudioState, } from "./audio.js";
27
+ export { plainText } from "./text.js";
28
+ export { readableTextColor } from "./theme.js";
29
+ export { decodePublishableKey, encodePublishableKey, type PublishableKeyEnv, type PublishableKeyPayload, } from "./publishableKey.js";
30
+ export { createClient, fetchFragments, normalizeFieldSpecs, strongestFragmentSource, type CreateClientOptions, type FetchFragmentsOptions, type FragmentFieldSpec, type FragmentsResult, type MintTokenSource, type NormalizedFragmentField, type SparkletreeClient, } from "./fragments.js";
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @sparkletree/core — the framework-agnostic half of the SparkleTree SDK.
3
+ *
4
+ * Everything that touches the wire lives here, and ONLY here. Components
5
+ * distributed by `sparkletree add` are copied into a customer's repo and are
6
+ * therefore un-patchable by us; they must stay wire-ignorant, rendering state
7
+ * this package hands them. That split is what lets a protocol change ship as a
8
+ * version bump instead of a migration guide.
9
+ *
10
+ * Wire types are re-exported so consumers never import the generated contract
11
+ * directly — that path is an implementation detail and would make the
12
+ * generated artifacts part of the public API.
13
+ */
14
+ export { FRAGMENT_KINDS, FRAGMENT_WARMTHS } from "./wire.js";
15
+ export { PROTOCOL_CURRENT, PROTOCOL_DEFAULT, PROTOCOL_HEADER, PROTOCOL_PARAM, PROTOCOL_VERSIONS, SDK_PARAM, SDK_PARAM_VALUE, VARIANT_PARAM, buildContentUrl, buildStreamUrl, negotiatedProtocol, } from "./protocol.js";
16
+ export { SseParser, readSseStream } from "./sse.js";
17
+ export { isFirstPartyApiBase, isSecureApiBase, safeActionUrl } from "./safeUrl.js";
18
+ export { CONTEXT_DAYPARTS, CONTEXT_DAY_TYPES, CONTEXT_DEVICES, CONTEXT_INTENTS, CONTEXT_SURFACE_TYPES, CONTEXT_TEMP_BANDS, CONTEXT_WEATHER, FRAGMENT_KIND_FLOORS, MAX_CUSTOM_DIMS, MAX_NOTES_LENGTH, canonicalContextString, computeContextHash, computeFieldBudget, computeSchemaHash, declaredToDims, hashDeclaredContext, normalizeDims, normalizeNotes, } from "./context.js";
19
+ export { COPY_FIELDS, COPY_HOLD_MS, CopyChoreographer, } from "./state.js";
20
+ export { fetchContent, openStream, } from "./client.js";
21
+ export { TOKEN_PREFIX, applyTheme, themeStyle, tokenName, tokenSource, } from "./theme.js";
22
+ export { STANDARD_MODE_KEY, decideChrome, setViewerPrefersStandard, viewerPrefersStandard, } from "./trust.js";
23
+ export { ImpressionRecorder, observeVisibility, sessionId, track, } from "./analytics.js";
24
+ export { RESERVATION_TIMEOUT_MS, VariantRegistry, pageVariants, } from "./variant.js";
25
+ export { activePlayer, destroyActiveAudio, mountAudio, } from "./audio.js";
26
+ export { plainText } from "./text.js";
27
+ export { readableTextColor } from "./theme.js";
28
+ export { decodePublishableKey, encodePublishableKey, } from "./publishableKey.js";
29
+ export { createClient, fetchFragments, normalizeFieldSpecs, strongestFragmentSource, } from "./fragments.js";
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAeH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7D,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,EACd,kBAAkB,GAEnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAmB,MAAM,UAAU,CAAC;AAErE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEnF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,cAAc,GAIf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,iBAAiB,GAMlB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,YAAY,EACZ,UAAU,GAIX,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,UAAU,EACV,SAAS,EACT,WAAW,GAEZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,wBAAwB,EACxB,qBAAqB,GAEtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,KAAK,GAKN,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,YAAY,GAIb,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,UAAU,GAOX,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GAGrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,uBAAuB,GAQxB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Protocol surface: what the SDK asks for, and what it does when the server
3
+ * cannot give it.
4
+ *
5
+ * Everything here is generated from `shared/sparkletree/wire/contract.ts`, so
6
+ * the constants below cannot drift from the Go edge or the Next twin. What
7
+ * this file adds is the CLIENT half of the handshake, which the contract
8
+ * describes but does not implement.
9
+ */
10
+ import { PROTOCOL_CURRENT, PROTOCOL_DEFAULT, PROTOCOL_HEADER, PROTOCOL_PARAM, PROTOCOL_RESPONSE_HEADER, PROTOCOL_VERSIONS, SDK_PARAM, SDK_PARAM_VALUE, VARIANT_PARAM } from "./wire.js";
11
+ export { PROTOCOL_CURRENT, PROTOCOL_DEFAULT, PROTOCOL_HEADER, PROTOCOL_PARAM, PROTOCOL_RESPONSE_HEADER, PROTOCOL_VERSIONS, SDK_PARAM, SDK_PARAM_VALUE, VARIANT_PARAM, };
12
+ /** Everything needed to address one island stream. */
13
+ export interface StreamTarget {
14
+ /** Base URL of the embed API, e.g. `https://api.sparkletree.io`. */
15
+ apiBase: string;
16
+ organizationId: string;
17
+ campaignId?: string;
18
+ surfaceId?: string;
19
+ island: "hero" | "cta";
20
+ /**
21
+ * Variant pinning (plan v1.1 §3.3). The provider resolves the variant ONCE
22
+ * per page view and pins it here for every later call. Without it, ε-greedy
23
+ * runs per request and a single page shows a mixed-variant creative — hero
24
+ * from one arm, CTA from another — which is not an experiment, it is noise.
25
+ */
26
+ variantId?: string;
27
+ /** Context snapshot (time, geo, weather, device). Serialised as JSON. */
28
+ context?: Record<string, unknown>;
29
+ /** Conversation session id for copy continuity. Individual surfaces only. */
30
+ sessionId?: string;
31
+ /** Extra params passed through verbatim (preview tokens, etc.). */
32
+ extra?: Record<string, string | undefined>;
33
+ }
34
+ /**
35
+ * Build the stream URL.
36
+ *
37
+ * `sdk=1` is not optional and not a feature flag: it tells the server to
38
+ * suppress its own server-side impression for this request. The SDK renders
39
+ * inside the customer's page, so it is the only party that knows whether the
40
+ * creative was ever actually on screen — and a server-side impression on top
41
+ * of the client's own would double-count every view, and would keep counting
42
+ * from a CDN-cached SSR response that no human ever saw.
43
+ */
44
+ export declare function buildStreamUrl(target: StreamTarget, protocol?: number): string;
45
+ /**
46
+ * Build the `/content` URL used for first paint. Same pinning rules as the
47
+ * stream — but deliberately NOT the same `sdk=1` rule.
48
+ *
49
+ * `sdk=1` is a promise: "the SDK will record this impression itself". The
50
+ * stream path keeps that promise — `useIsland` owns a visibility-gated
51
+ * recorder. The content path CANNOT: its consumers (CopyCard, ProductCard,
52
+ * the cookbook's content-only recipes) have no observer and no recorder, so
53
+ * sending `sdk=1` here told the server to stop counting while nobody else
54
+ * started — zero impressions for every content-only integration. Omitting it
55
+ * leaves the server owning the `/content` impression, exactly as it does for
56
+ * every non-SDK consumer of the endpoint.
57
+ */
58
+ export declare function buildContentUrl(target: StreamTarget, protocol?: number): string;
59
+ /**
60
+ * Read the negotiated version off a response.
61
+ *
62
+ * An absent header means an older deployment that predates negotiation, which
63
+ * by contract is protocol 1 — not an error, and specifically not a reason to
64
+ * refuse the stream. Treating silence as failure here would break every
65
+ * customer whose traffic happens to land on an edge revision mid-rollout.
66
+ */
67
+ export declare function negotiatedProtocol(response: {
68
+ headers: Headers;
69
+ }): number;
70
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,wBAAwB,EACxB,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,aAAa,EACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,wBAAwB,EACxB,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,aAAa,GACd,CAAC;AAEF,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;IACvB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC5C;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,GAAE,MAAyB,GAAG,MAAM,CAoBhG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,GAAE,MAAyB,GAAG,MAAM,CAkBjG;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAKzE"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Protocol surface: what the SDK asks for, and what it does when the server
3
+ * cannot give it.
4
+ *
5
+ * Everything here is generated from `shared/sparkletree/wire/contract.ts`, so
6
+ * the constants below cannot drift from the Go edge or the Next twin. What
7
+ * this file adds is the CLIENT half of the handshake, which the contract
8
+ * describes but does not implement.
9
+ */
10
+ import { PROTOCOL_CURRENT, PROTOCOL_DEFAULT, PROTOCOL_HEADER, PROTOCOL_PARAM, PROTOCOL_RESPONSE_HEADER, PROTOCOL_VERSIONS, SDK_PARAM, SDK_PARAM_VALUE, VARIANT_PARAM, } from "./wire.js";
11
+ export { PROTOCOL_CURRENT, PROTOCOL_DEFAULT, PROTOCOL_HEADER, PROTOCOL_PARAM, PROTOCOL_RESPONSE_HEADER, PROTOCOL_VERSIONS, SDK_PARAM, SDK_PARAM_VALUE, VARIANT_PARAM, };
12
+ /**
13
+ * Build the stream URL.
14
+ *
15
+ * `sdk=1` is not optional and not a feature flag: it tells the server to
16
+ * suppress its own server-side impression for this request. The SDK renders
17
+ * inside the customer's page, so it is the only party that knows whether the
18
+ * creative was ever actually on screen — and a server-side impression on top
19
+ * of the client's own would double-count every view, and would keep counting
20
+ * from a CDN-cached SSR response that no human ever saw.
21
+ */
22
+ export function buildStreamUrl(target, protocol = PROTOCOL_CURRENT) {
23
+ const url = new URL("/api/embed/v1/islands/stream", target.apiBase);
24
+ const params = url.searchParams;
25
+ params.set("organization", target.organizationId);
26
+ if (target.surfaceId)
27
+ params.set("surface", target.surfaceId);
28
+ else if (target.campaignId)
29
+ params.set("campaign", target.campaignId);
30
+ params.set("island", target.island);
31
+ if (target.context)
32
+ params.set("context", JSON.stringify(target.context));
33
+ if (target.variantId)
34
+ params.set(VARIANT_PARAM, target.variantId);
35
+ if (target.sessionId)
36
+ params.set("session", target.sessionId);
37
+ params.set(SDK_PARAM, SDK_PARAM_VALUE);
38
+ // Sent as a param as well as a header: EventSource cannot set headers, and
39
+ // a consumer that swaps our fetch transport for one must still negotiate.
40
+ params.set(PROTOCOL_PARAM, String(protocol));
41
+ for (const [key, value] of Object.entries(target.extra ?? {})) {
42
+ if (value !== undefined)
43
+ params.set(key, value);
44
+ }
45
+ return url.toString();
46
+ }
47
+ /**
48
+ * Build the `/content` URL used for first paint. Same pinning rules as the
49
+ * stream — but deliberately NOT the same `sdk=1` rule.
50
+ *
51
+ * `sdk=1` is a promise: "the SDK will record this impression itself". The
52
+ * stream path keeps that promise — `useIsland` owns a visibility-gated
53
+ * recorder. The content path CANNOT: its consumers (CopyCard, ProductCard,
54
+ * the cookbook's content-only recipes) have no observer and no recorder, so
55
+ * sending `sdk=1` here told the server to stop counting while nobody else
56
+ * started — zero impressions for every content-only integration. Omitting it
57
+ * leaves the server owning the `/content` impression, exactly as it does for
58
+ * every non-SDK consumer of the endpoint.
59
+ */
60
+ export function buildContentUrl(target, protocol = PROTOCOL_CURRENT) {
61
+ const url = new URL("/api/embed/v1/content", target.apiBase);
62
+ const params = url.searchParams;
63
+ // Same param names the stream uses — the Go handler (contentRequest in
64
+ // mosaic-edge-serve/internal/handler/content.go) reads organization/
65
+ // campaign/surface; the *Id spellings were never read by any server.
66
+ params.set("organization", target.organizationId);
67
+ if (target.surfaceId)
68
+ params.set("surface", target.surfaceId);
69
+ if (target.campaignId)
70
+ params.set("campaign", target.campaignId);
71
+ if (target.context)
72
+ params.set("context", JSON.stringify(target.context));
73
+ if (target.variantId)
74
+ params.set(VARIANT_PARAM, target.variantId);
75
+ params.set(PROTOCOL_PARAM, String(protocol));
76
+ for (const [key, value] of Object.entries(target.extra ?? {})) {
77
+ if (value !== undefined)
78
+ params.set(key, value);
79
+ }
80
+ return url.toString();
81
+ }
82
+ /**
83
+ * Read the negotiated version off a response.
84
+ *
85
+ * An absent header means an older deployment that predates negotiation, which
86
+ * by contract is protocol 1 — not an error, and specifically not a reason to
87
+ * refuse the stream. Treating silence as failure here would break every
88
+ * customer whose traffic happens to land on an edge revision mid-rollout.
89
+ */
90
+ export function negotiatedProtocol(response) {
91
+ const raw = response.headers.get(PROTOCOL_RESPONSE_HEADER);
92
+ if (!raw)
93
+ return PROTOCOL_DEFAULT;
94
+ const parsed = Number.parseInt(raw, 10);
95
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : PROTOCOL_DEFAULT;
96
+ }
97
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}