@ziprack/sdk 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.
@@ -0,0 +1,62 @@
1
+ import { type Link } from '../core/link';
2
+ import type { AckResult, JsonObject } from '../core/types';
3
+ export type WhereOperator = '=' | '!=' | '<' | '<=' | '>' | '>=' | 'in';
4
+ export type WhereClause = [path: string, operator: WhereOperator, value: unknown];
5
+ export interface ListQuery {
6
+ /** Filters on paths declared in the collection's `indexed` list. */
7
+ where?: WhereClause[];
8
+ orderBy?: string;
9
+ direction?: 'asc' | 'desc';
10
+ /** Max 100. */
11
+ limit?: number;
12
+ cursor?: string | null;
13
+ }
14
+ export interface RecordRow<T extends object = JsonObject> {
15
+ id: string;
16
+ data: T;
17
+ owner_id: number;
18
+ created_at: string;
19
+ updated_at: string;
20
+ }
21
+ export interface ListResult<T extends object = JsonObject> {
22
+ records: RecordRow<T>[];
23
+ nextCursor: string | null;
24
+ }
25
+ export declare class Collection<T extends object = JsonObject> {
26
+ private readonly link;
27
+ readonly name: string;
28
+ constructor(link: Link, name: string);
29
+ create(data: T): Promise<AckResult<{
30
+ record: RecordRow<T>;
31
+ }>>;
32
+ get(id: string): Promise<AckResult<{
33
+ record: RecordRow<T>;
34
+ }>>;
35
+ /** Merge by default; pass { merge: false } to replace the whole document. */
36
+ update(id: string, data: Partial<T>, options?: {
37
+ merge?: boolean;
38
+ }): Promise<AckResult<{
39
+ record: RecordRow<T>;
40
+ }>>;
41
+ delete(id: string): Promise<AckResult<{
42
+ id: string;
43
+ }>>;
44
+ list(query?: ListQuery): Promise<AckResult<ListResult<T>>>;
45
+ count(query?: Pick<ListQuery, 'where'>): Promise<AckResult<{
46
+ count: number;
47
+ }>>;
48
+ private send;
49
+ }
50
+ /**
51
+ * db@1 — CRUD records in collections the manifest declares, each with a JSON
52
+ * Schema and a scope (attempt | user | room | applet).
53
+ */
54
+ export declare class DbApi {
55
+ private readonly link;
56
+ constructor(link: Link);
57
+ collection<T extends object = JsonObject>(name: string): Collection<T>;
58
+ collections(): Array<{
59
+ name: string;
60
+ scope: string;
61
+ }>;
62
+ }
@@ -0,0 +1,15 @@
1
+ import { RackClient } from './core/rack';
2
+ export * from './core/types';
3
+ export { PROTOCOL_NAMESPACE, PROTOCOL_VERSION, FORMAT } from './core/protocol';
4
+ export { RackClient } from './core/rack';
5
+ export { HostBridge } from './core/bridge';
6
+ export type { AnswerOptions, StatementInput } from './activity';
7
+ export type { Collection, ListQuery, ListResult, RecordRow, WhereClause, WhereOperator } from './db';
8
+ export type { StoredFile, FileStatus } from './storage';
9
+ export type { Chat, ChatReply, Usage } from './ai';
10
+ export type { Channel, RoomEventName, RoomEvents } from './broadcast';
11
+ export type { MockManifest, AiMockHandler } from './core/mock/MockRack';
12
+ /** The singleton every applet talks through. */
13
+ export declare const Rack: RackClient;
14
+ /** A separate client (tests, or unusual multi-frame setups). */
15
+ export declare function createRack(): RackClient;
package/dist/index.js ADDED
@@ -0,0 +1,517 @@
1
+ import { n as f, c as h, i as g, a as u, M as l, b as w, L as b } from "./store-DSV5q7C7.js";
2
+ import { F as K, P as V, d as W } from "./store-DSV5q7C7.js";
3
+ class v {
4
+ constructor(t) {
5
+ this.link = t;
6
+ }
7
+ /** The manifest's declared activities for this version. */
8
+ activities() {
9
+ return this.link.launch()?.activity?.activities ?? [];
10
+ }
11
+ activity(t) {
12
+ return this.activities().find((e) => e.id === t) ?? null;
13
+ }
14
+ statement(t) {
15
+ return this.link.send("activity:statement", {
16
+ ...t,
17
+ occurred_at: t.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
18
+ });
19
+ }
20
+ /** `answered` statement with the value in result.response — the only field reporting reads. */
21
+ answer(t, e, s = {}) {
22
+ return this.statement({
23
+ verb: "answered",
24
+ activity: { id: t, type: s.type ?? this.activity(t)?.type },
25
+ result: { response: e },
26
+ context: s.context
27
+ });
28
+ }
29
+ /** `progressed` statement with activity.type = 'step'. */
30
+ progress(t, e) {
31
+ return this.statement({ verb: "progressed", activity: { id: t, type: "step" }, context: e });
32
+ }
33
+ }
34
+ class y {
35
+ constructor(t, e) {
36
+ this.link = t, this.promptId = e;
37
+ }
38
+ /**
39
+ * Send a participant message. onDelta receives text as it streams; the
40
+ * resolved result carries the full text.
41
+ */
42
+ async send(t, e) {
43
+ let s = "";
44
+ const n = await this.link.send("ai:chat", { prompt: this.promptId, message: t }, {
45
+ timeoutMs: 6e4,
46
+ onPartial: (i) => {
47
+ const a = typeof i.delta == "string" ? i.delta : "";
48
+ s += a, e?.(a, s);
49
+ }
50
+ });
51
+ return n.ok ? {
52
+ ok: !0,
53
+ data: {
54
+ message_id: String(n.data?.message_id ?? ""),
55
+ text: n.data?.text ?? s,
56
+ usage: n.data?.usage ?? { input_tokens: 0, output_tokens: 0 }
57
+ }
58
+ } : n;
59
+ }
60
+ reset() {
61
+ return this.link.send("ai:chat.reset", { prompt: this.promptId });
62
+ }
63
+ }
64
+ class M {
65
+ constructor(t) {
66
+ this.link = t;
67
+ }
68
+ prompts() {
69
+ return this.link.launch()?.ai?.prompts ?? [];
70
+ }
71
+ /** Analysis prompt: structured JSON conforming to the declared output_schema. */
72
+ ask(t, e = {}) {
73
+ return this.link.send("ai:ask", { prompt: t, vars: e }, { timeoutMs: 6e4 });
74
+ }
75
+ /** Chat prompt: conversation history is held by the Rack. */
76
+ chat(t) {
77
+ return new y(this.link, t);
78
+ }
79
+ }
80
+ class L {
81
+ constructor(t) {
82
+ this.link = t, this.local = {};
83
+ }
84
+ /** The attempt as launched, with local updates applied. */
85
+ current() {
86
+ const t = this.link.launch()?.attempt;
87
+ return t ? { ...t, ...this.local } : null;
88
+ }
89
+ get status() {
90
+ return this.current()?.status ?? null;
91
+ }
92
+ get id() {
93
+ return this.current()?.id ?? null;
94
+ }
95
+ /** Resume state exactly as last saved. */
96
+ state() {
97
+ return this.current()?.state ?? null;
98
+ }
99
+ segment() {
100
+ return this.current()?.segment ?? null;
101
+ }
102
+ /** Save resume state (max 64 KB). Send after every transition; the shell coalesces bursts. */
103
+ setState(t) {
104
+ return this.local.state = t, this.link.send("attempt:state", { state: t });
105
+ }
106
+ /** Set segment dimensions (max 20 keys, string values). */
107
+ setSegment(t) {
108
+ return this.local.segment = t, this.link.send("attempt:segment", { segment: t });
109
+ }
110
+ /** Mark the attempt completed. Idempotent. */
111
+ async complete(t) {
112
+ const e = await this.link.send("attempt:complete", { summary: t ?? null });
113
+ return e.ok && (this.local.status = "completed"), e;
114
+ }
115
+ }
116
+ class A {
117
+ constructor(t) {
118
+ this.link = t;
119
+ }
120
+ user() {
121
+ return this.link.launch()?.auth?.user ?? null;
122
+ }
123
+ /** A released profile attribute, or the fallback when withheld. */
124
+ attribute(t, e = null) {
125
+ const s = this.user();
126
+ return !s || !(t in s) ? e : s[t];
127
+ }
128
+ }
129
+ const R = "$room";
130
+ class E {
131
+ constructor(t, e) {
132
+ this.link = t, this.name = e, this.listeners = /* @__PURE__ */ new Map(), this.unsubscribe = null;
133
+ }
134
+ /** @internal */
135
+ attach() {
136
+ this.unsubscribe ??= this.link.onEvent((t) => {
137
+ t.channel === this.name && (this.listeners.get(t.event)?.forEach((e) => e(t.payload, t.from)), this.listeners.get("*")?.forEach((e) => e({ event: t.event, payload: t.payload }, t.from)));
138
+ });
139
+ }
140
+ /** Listen for an event on this channel ('*' for all). Returns an unsubscribe function. */
141
+ listen(t, e) {
142
+ const s = this.listeners.get(t) ?? /* @__PURE__ */ new Set();
143
+ return s.add(e), this.listeners.set(t, s), () => {
144
+ s.delete(e);
145
+ };
146
+ }
147
+ /** Publish to everyone in the room. Facilitator-only events are enforced by the Rack. */
148
+ publish(t, e = {}) {
149
+ return this.link.send("broadcast:publish", { channel: this.name, event: t, payload: e });
150
+ }
151
+ async leave() {
152
+ return this.unsubscribe?.(), this.unsubscribe = null, this.listeners.clear(), this.link.send("broadcast:leave", { channel: this.name });
153
+ }
154
+ }
155
+ class S {
156
+ constructor(t) {
157
+ this.link = t, this.channels = /* @__PURE__ */ new Map(), this.roomListeners = /* @__PURE__ */ new Map(), this.localRole = null, this.localMembers = null, this.localState = null, this.detach = null, this.state = {
158
+ /** Server-arbitrated shared state. */
159
+ get: async (e) => {
160
+ const s = await this.link.send("broadcast:state.get", e ? { keys: e } : {});
161
+ return s.ok && s.data && (this.localState = { ...this.localState ?? {}, ...s.data.state }), s;
162
+ },
163
+ /** Last write wins at the key; the Rack stamps the version. */
164
+ set: (e, s) => (this.localState = { ...this.localState ?? this.launch()?.state ?? {}, [e]: s }, this.link.send("broadcast:state.set", { key: e, value: s })),
165
+ /** Locally known state (launch snapshot plus pushed updates). */
166
+ snapshot: () => this.localState ?? this.launch()?.state ?? {}
167
+ };
168
+ }
169
+ get room() {
170
+ return this.launch()?.room ?? null;
171
+ }
172
+ get role() {
173
+ return this.localRole ?? this.launch()?.role ?? null;
174
+ }
175
+ get isFacilitator() {
176
+ return this.role === "facilitator";
177
+ }
178
+ members() {
179
+ return this.localMembers ?? this.launch()?.members ?? [];
180
+ }
181
+ /** Join a named channel within the room (default "main"). */
182
+ async join(t = "main") {
183
+ this.ensureRoomListener();
184
+ let e = this.channels.get(t);
185
+ return e || (e = new E(this.link, t), this.channels.set(t, e)), e.attach(), await this.link.send("broadcast:join", { channel: t }), e;
186
+ }
187
+ /** Who is in the room, by role. */
188
+ async presence() {
189
+ const t = await this.link.send("broadcast:presence", {});
190
+ return t.ok && t.data && (this.localMembers = t.data.members), t;
191
+ }
192
+ /** Claim the facilitator role (opt_in rooms). */
193
+ claim() {
194
+ return this.link.send("broadcast:claim", {});
195
+ }
196
+ /** Hand the facilitator role to another member. */
197
+ transfer(t) {
198
+ return this.link.send("broadcast:transfer", { to: t });
199
+ }
200
+ /** Room-level events: presence, state, role, status. */
201
+ on(t, e) {
202
+ this.ensureRoomListener();
203
+ const s = this.roomListeners.get(t) ?? /* @__PURE__ */ new Set();
204
+ return s.add(e), this.roomListeners.set(t, s), () => {
205
+ s.delete(e);
206
+ };
207
+ }
208
+ launch() {
209
+ return this.link.launch()?.broadcast ?? null;
210
+ }
211
+ ensureRoomListener() {
212
+ this.detach ??= this.link.onEvent((t) => {
213
+ if (t.channel !== R)
214
+ return;
215
+ const e = t.payload;
216
+ t.event === "presence" && Array.isArray(e.members) && (this.localMembers = e.members), t.event === "state" && typeof e.key == "string" && (this.localState = { ...this.localState ?? this.launch()?.state ?? {}, [e.key]: e.value }), t.event === "role" && e.participant_id === this.link.launch()?.actor.id && (this.localRole = e.role), this.roomListeners.get(t.event)?.forEach((s) => s(e));
217
+ });
218
+ }
219
+ }
220
+ function d(r) {
221
+ return { ok: !1, error: "undeclared_capability", message: `The manifest does not declare the [${r}] capability.` };
222
+ }
223
+ class T {
224
+ constructor(t, e) {
225
+ this.link = t, this.name = e;
226
+ }
227
+ create(t) {
228
+ return this.send("db:create", { data: t });
229
+ }
230
+ get(t) {
231
+ return this.send("db:get", { id: t });
232
+ }
233
+ /** Merge by default; pass { merge: false } to replace the whole document. */
234
+ update(t, e, s = {}) {
235
+ return this.send("db:update", { id: t, data: e, merge: s.merge ?? !0 });
236
+ }
237
+ delete(t) {
238
+ return this.send("db:delete", { id: t });
239
+ }
240
+ list(t = {}) {
241
+ return this.send("db:list", t);
242
+ }
243
+ count(t = {}) {
244
+ return this.send("db:count", t);
245
+ }
246
+ send(t, e) {
247
+ return this.link.launch() && !this.link.declares("db") ? Promise.resolve(d("db")) : this.link.send(t, { collection: this.name, ...e });
248
+ }
249
+ }
250
+ class D {
251
+ constructor(t) {
252
+ this.link = t;
253
+ }
254
+ collection(t) {
255
+ return new T(this.link, t);
256
+ }
257
+ collections() {
258
+ return this.link.launch()?.db?.collections ?? [];
259
+ }
260
+ }
261
+ class _ {
262
+ constructor(t) {
263
+ this.link = t;
264
+ }
265
+ get(t) {
266
+ return this.link.launch()?.media?.[t] ?? null;
267
+ }
268
+ /** Player URL for an <iframe src>. Null when the id is not declared. */
269
+ embedUrl(t) {
270
+ return this.get(t)?.embedUrl ?? null;
271
+ }
272
+ all() {
273
+ return this.link.launch()?.media ?? {};
274
+ }
275
+ }
276
+ class O {
277
+ constructor(t) {
278
+ this.link = t;
279
+ }
280
+ uploads() {
281
+ return this.link.launch()?.storage?.uploads ?? [];
282
+ }
283
+ /** Upload into a declared upload slot. Resolves once stored (status may still be pending scan). */
284
+ put(t, e, s = {}) {
285
+ const n = e instanceof File ? e.name : "blob";
286
+ return this.link.send("storage:put", { upload: t, file: e, name: n, mime: e.type, bytes: e.size, meta: s }, { timeoutMs: 12e4 });
287
+ }
288
+ /** Short-lived URL for a clean file. Never an object key. */
289
+ url(t) {
290
+ return this.link.send("storage:url", { id: t });
291
+ }
292
+ list(t) {
293
+ return this.link.send("storage:list", t ? { upload: t } : {});
294
+ }
295
+ delete(t) {
296
+ return this.link.send("storage:delete", { id: t });
297
+ }
298
+ }
299
+ class P {
300
+ constructor(t) {
301
+ this.options = t, this.kind = "host", this.pending = /* @__PURE__ */ new Map(), this.eventListeners = /* @__PURE__ */ new Set(), this.launchResolvers = [], this.launchData = null, this.listener = (e) => this.onMessage(e), this.target = t.target ?? window.parent, this.isHost = t.isHost ?? ((e) => e === window.parent), this.listenOn = t.listenOn ?? window, this.listenOn.addEventListener("message", this.listener);
302
+ }
303
+ announceReady() {
304
+ this.fire("rack:ready", {});
305
+ }
306
+ waitForLaunch(t) {
307
+ return this.launchData ? Promise.resolve(this.launchData) : new Promise((e) => {
308
+ const s = setTimeout(() => {
309
+ this.launchResolvers = this.launchResolvers.filter((i) => i !== n), e(null);
310
+ }, t), n = (i) => {
311
+ clearTimeout(s), e(i);
312
+ };
313
+ this.launchResolvers.push(n);
314
+ });
315
+ }
316
+ send(t, e, s = {}) {
317
+ const n = f(), i = s.timeoutMs ?? this.options.ackTimeoutMs;
318
+ return new Promise((a) => {
319
+ const o = {
320
+ resolve: a,
321
+ timer: setTimeout(() => this.expire(n), i),
322
+ timeoutMs: i,
323
+ onPartial: s.onPartial
324
+ };
325
+ this.pending.set(n, o), this.post(h(t, e, n));
326
+ });
327
+ }
328
+ fire(t, e = {}) {
329
+ this.post(h(t, e));
330
+ }
331
+ onEvent(t) {
332
+ return this.eventListeners.add(t), () => {
333
+ this.eventListeners.delete(t);
334
+ };
335
+ }
336
+ dispose() {
337
+ this.listenOn.removeEventListener("message", this.listener);
338
+ for (const [t, e] of this.pending)
339
+ clearTimeout(e.timer), e.resolve({ ok: !1, error: "disposed" }), this.pending.delete(t);
340
+ }
341
+ expire(t) {
342
+ const e = this.pending.get(t);
343
+ e && (this.pending.delete(t), e.resolve({ ok: !1, error: "timeout" }));
344
+ }
345
+ post(t) {
346
+ this.target.postMessage(t, "*");
347
+ }
348
+ onMessage(t) {
349
+ if (!this.isHost(t.source) || !g(t.data))
350
+ return;
351
+ const e = t.data;
352
+ if (e.type === "rack:launch") {
353
+ this.launchData = e.payload;
354
+ const s = this.launchResolvers;
355
+ this.launchResolvers = [], s.forEach((n) => n(this.launchData));
356
+ return;
357
+ }
358
+ if (e.type === "rack:event") {
359
+ const s = e.payload;
360
+ this.eventListeners.forEach((n) => n(s));
361
+ return;
362
+ }
363
+ e.type === "rack:ack" && this.onAck(e.payload);
364
+ }
365
+ onAck(t) {
366
+ const e = this.pending.get(t.requestId);
367
+ if (!e)
368
+ return;
369
+ if (t.partial && !t.done) {
370
+ const { requestId: F, ok: U, partial: $, ...k } = t;
371
+ e.onPartial?.(k), clearTimeout(e.timer), e.timer = setTimeout(() => this.expire(t.requestId), e.timeoutMs);
372
+ return;
373
+ }
374
+ clearTimeout(e.timer), this.pending.delete(t.requestId);
375
+ const { requestId: s, ok: n, data: i, error: a, message: o, details: p, partial: C, done: j, ...c } = t;
376
+ e.resolve({ ok: n, data: i ?? (Object.keys(c).length ? c : void 0), error: a, message: o, details: p });
377
+ }
378
+ }
379
+ const q = 3e3, I = 5e3;
380
+ class m {
381
+ constructor() {
382
+ this.transport = null, this.initPromise = null, this.launchData = null, this.queue = [], this.launchListeners = /* @__PURE__ */ new Set(), this.eventListeners = /* @__PURE__ */ new Set(), this.pendingAiMocks = [];
383
+ const t = {
384
+ send: (e, s, n) => this.send(e, s, n),
385
+ fire: (e, s) => this.fire(e, s),
386
+ launch: () => this.launchData,
387
+ declares: (e) => this.declares(e),
388
+ onEvent: (e) => this.on("event", e),
389
+ mode: () => this.mode
390
+ };
391
+ this.auth = new A(t), this.attempt = new L(t), this.activity = new v(t), this.db = new D(t), this.storage = new O(t), this.ai = new M(t), this.broadcast = new S(t), this.media = new _(t), this.mock = {
392
+ ai: (e, s) => {
393
+ const n = this.mockRack();
394
+ n ? n.mockAi(e, s) : this.pendingAiMocks.push([e, s]);
395
+ },
396
+ resetAttempt: () => this.mockRack()?.resetAttempt(),
397
+ rack: () => this.mockRack()
398
+ };
399
+ }
400
+ /**
401
+ * Handshake with the Rack. Resolves with launch data once the Rack answers,
402
+ * or with mock launch data when running standalone. Safe to call repeatedly.
403
+ */
404
+ init(t = {}) {
405
+ return this.initPromise ??= this.performInit(t), this.initPromise;
406
+ }
407
+ get launched() {
408
+ return this.launchData !== null;
409
+ }
410
+ get mode() {
411
+ return this.transport?.kind ?? "pending";
412
+ }
413
+ getLaunchData() {
414
+ return this.launchData;
415
+ }
416
+ /** Whether the manifest declared a capability (any version). */
417
+ declares(t) {
418
+ return (this.launchData?.capabilities ?? []).some((e) => e.split("@")[0] === t);
419
+ }
420
+ on(t, e) {
421
+ if (t === "launch") {
422
+ const n = e;
423
+ return this.launchListeners.add(n), this.launchData && n(this.launchData), () => {
424
+ this.launchListeners.delete(n);
425
+ };
426
+ }
427
+ const s = e;
428
+ return this.eventListeners.add(s), () => {
429
+ this.eventListeners.delete(s);
430
+ };
431
+ }
432
+ /** Ask the Rack to leave the applet. Needs no capability. */
433
+ eject() {
434
+ this.fire("rack:eject", {}), this.transport?.kind === "mock" && console.info("[ziprack mock] eject: the Rack would navigate away now.");
435
+ }
436
+ /** Low-level: send any message and await its ack. Capability calls go through the typed APIs. */
437
+ send(t, e, s) {
438
+ return this.launchData && !t.startsWith("rack:") && !this.declares(u(t)) ? Promise.resolve(d(u(t))) : this.transport ? this.transport.send(t, e, s) : new Promise((n) => {
439
+ this.queue.push({ type: t, payload: e, options: s, resolve: n });
440
+ });
441
+ }
442
+ fire(t, e = {}) {
443
+ if (this.transport) {
444
+ this.transport.fire(t, e);
445
+ return;
446
+ }
447
+ this.send(t, e);
448
+ }
449
+ /** Tear down (tests). */
450
+ dispose() {
451
+ this.transport?.dispose(), this.transport = null, this.initPromise = null, this.launchData = null;
452
+ }
453
+ async performInit(t) {
454
+ const e = t.ackTimeoutMs ?? I, s = t.launchTimeoutMs ?? q;
455
+ if (t.transport) {
456
+ const o = t.launch ?? (t.transport instanceof l ? t.transport.rack.launchData() : null);
457
+ if (!o)
458
+ throw new Error("init({ transport }) needs `launch` data unless the transport is a MockTransport.");
459
+ return this.activate(t.transport, o);
460
+ }
461
+ if (!(typeof window < "u" && window.parent !== window))
462
+ return this.activateMock(t, "not embedded in a Rack");
463
+ const i = new P({ ackTimeoutMs: e });
464
+ i.announceReady();
465
+ const a = await i.waitForLaunch(s);
466
+ return a ? this.activate(i, a) : (i.dispose(), this.activateMock(t, `no rack:launch within ${s}ms`));
467
+ }
468
+ async activateMock(t, e) {
469
+ console.info(`[ziprack] running in mock mode (${e})`);
470
+ const s = await x(t.manifestUrl ?? "./manifest.json", t.slug), n = new w(s, new b(), {
471
+ log: (i, a) => console.info(`[ziprack mock] ${i}`, a)
472
+ });
473
+ for (const [i, a] of this.pendingAiMocks)
474
+ n.mockAi(i, a);
475
+ return this.pendingAiMocks = [], this.activate(new l(n), n.launchData(t.slug));
476
+ }
477
+ activate(t, e) {
478
+ return this.transport = t, this.launchData = e, t.onEvent((s) => this.eventListeners.forEach((n) => n(s))), this.launchListeners.forEach((s) => s(e)), this.flushQueue(), e;
479
+ }
480
+ flushQueue() {
481
+ if (this.transport)
482
+ for (; this.queue.length > 0; ) {
483
+ const e = this.queue.shift();
484
+ this.send(e.type, e.payload, e.options).then(e.resolve);
485
+ }
486
+ }
487
+ mockRack() {
488
+ return this.transport instanceof l ? this.transport.rack : null;
489
+ }
490
+ }
491
+ async function x(r, t) {
492
+ if (typeof fetch != "function")
493
+ return null;
494
+ try {
495
+ const e = await fetch(r, { cache: "no-store" });
496
+ if (!e.ok)
497
+ throw new Error(String(e.status));
498
+ const s = await e.json();
499
+ return t && s.slug !== t && console.warn(`[ziprack mock] manifest slug [${s.slug}] does not match init({ slug: '${t}' }).`), s;
500
+ } catch (e) {
501
+ return console.warn(`[ziprack mock] could not load ${r}; mock mode will accept every capability.`, e), null;
502
+ }
503
+ }
504
+ const H = new m();
505
+ function N() {
506
+ return new m();
507
+ }
508
+ export {
509
+ K as FORMAT,
510
+ P as HostBridge,
511
+ V as PROTOCOL_NAMESPACE,
512
+ W as PROTOCOL_VERSION,
513
+ H as Rack,
514
+ m as RackClient,
515
+ N as createRack
516
+ };
517
+ //# sourceMappingURL=index.js.map