@horae.io/passport-core 1.0.0 → 1.0.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/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ HoraeSDK: () => HoraeSDK,
33
34
  createClient: () => createClient,
34
35
  createClientWithAuth: () => createClientWithAuth,
35
36
  createCustomStrategy: () => createCustomStrategy,
@@ -162,6 +163,18 @@ function createPassportApi(api) {
162
163
  async claimShopifyPassport(data) {
163
164
  await api.post("/api/passport/shopify-claim", data);
164
165
  },
166
+ /** Scale owner registration (serial/email based, no wallet) */
167
+ async registerScaleOwner(payload) {
168
+ const res = await api.post("/api/passport/scale/register", payload);
169
+ return unwrapData(res);
170
+ },
171
+ /** Scale signed viewer (HMAC signature) */
172
+ async getScaleViewer(tokenId, sig) {
173
+ const res = await api.get(`/api/passport/scale/view/${tokenId}`, {
174
+ params: { sig }
175
+ });
176
+ return unwrapData(res);
177
+ },
165
178
  /** Current user profile */
166
179
  async getMe() {
167
180
  const res = await api.get("/users/me");
@@ -200,6 +213,15 @@ function prepareContainer(options, apiBase, token) {
200
213
  if (options.initialTab) {
201
214
  containerEl.dataset.initialTab = options.initialTab;
202
215
  }
216
+ if (options.mode) {
217
+ containerEl.dataset.horaeMode = options.mode;
218
+ }
219
+ if (options.viewerUrl) {
220
+ containerEl.dataset.horaeViewerUrl = options.viewerUrl;
221
+ }
222
+ if (options.scaleRegistration) {
223
+ containerEl.dataset.horaeScaleRegistration = options.scaleRegistration;
224
+ }
203
225
  if (token) {
204
226
  containerEl.dataset.horaeToken = token;
205
227
  }
@@ -229,7 +251,12 @@ async function mountApp(options, apiBase, token) {
229
251
  const host = options.uiHost || "https://app.horae.io";
230
252
  await loadUIBundle(host);
231
253
  window.dispatchEvent(new CustomEvent("horae:sdk:mount", {
232
- detail: { container: options.container }
254
+ detail: {
255
+ container: options.container,
256
+ mode: options.mode,
257
+ viewerUrl: options.viewerUrl,
258
+ scaleRegistration: options.scaleRegistration
259
+ }
233
260
  }));
234
261
  }
235
262
  async function renderPassportList(options, apiBase, token) {
@@ -244,55 +271,109 @@ async function renderPassport(options, apiBase, token) {
244
271
  const host = options.uiHost || "https://app.horae.io";
245
272
  await loadUIBundle(host);
246
273
  window.dispatchEvent(new CustomEvent("horae:sdk:mount", {
247
- detail: { container: options.container, passportId: options.passportId }
274
+ detail: {
275
+ container: options.container,
276
+ passportId: options.passportId,
277
+ mode: options.mode,
278
+ viewerUrl: options.viewerUrl,
279
+ scaleRegistration: options.scaleRegistration
280
+ }
248
281
  }));
249
282
  }
250
283
 
251
284
  // src/index.ts
252
285
  function createPassportSDK(config) {
286
+ const mode = config.mode ?? "heritage";
287
+ const authStrategy = config.authStrategy ?? (mode === "scale" ? "custom" : "jwt");
253
288
  const events = createEventBus();
254
289
  let auth;
255
- switch (config.authStrategy) {
256
- case "jwt": {
257
- const jwt = createJwtStrategy({
258
- token: config.token ?? void 0,
259
- storageKey: config.tokenStorageKey ?? void 0
260
- });
261
- auth = jwt;
262
- break;
263
- }
264
- case "custom": {
265
- if (!config.getToken) throw new Error("PassportSDK: getToken required for authStrategy 'custom'");
266
- auth = createCustomStrategy(config.getToken);
267
- break;
290
+ if (mode === "scale") {
291
+ auth = createCustomStrategy(async () => config.token ?? null);
292
+ } else {
293
+ switch (authStrategy) {
294
+ case "jwt": {
295
+ const jwt = createJwtStrategy({
296
+ token: config.token ?? void 0,
297
+ storageKey: config.tokenStorageKey ?? void 0
298
+ });
299
+ auth = jwt;
300
+ break;
301
+ }
302
+ case "custom": {
303
+ if (!config.getToken) throw new Error("PassportSDK: getToken required for authStrategy 'custom'");
304
+ auth = createCustomStrategy(config.getToken);
305
+ break;
306
+ }
307
+ case "shopify":
308
+ auth = createJwtStrategy({
309
+ token: config.token ?? void 0,
310
+ storageKey: config.tokenStorageKey ?? "shopify_access_token"
311
+ });
312
+ break;
313
+ case "privy":
314
+ if (!config.getToken) throw new Error("PassportSDK: getToken required for authStrategy 'privy' (pass Privy getAccessToken)");
315
+ auth = createCustomStrategy(config.getToken);
316
+ break;
317
+ default:
318
+ throw new Error(`PassportSDK: unknown authStrategy ${String(authStrategy)}`);
268
319
  }
269
- case "shopify":
270
- auth = createJwtStrategy({
271
- token: config.token ?? void 0,
272
- storageKey: config.tokenStorageKey ?? "shopify_access_token"
273
- });
274
- break;
275
- case "privy":
276
- if (!config.getToken) throw new Error("PassportSDK: getToken required for authStrategy 'privy' (pass Privy getAccessToken)");
277
- auth = createCustomStrategy(config.getToken);
278
- break;
279
- default:
280
- throw new Error(`PassportSDK: unknown authStrategy ${String(config.authStrategy)}`);
281
320
  }
282
321
  const client = createClient({ apiBase: config.apiBase, getToken: () => auth.getToken() });
283
322
  const api = createPassportApi(client);
323
+ const fallbackScaleRegistration = config.serial || config.brandId ? {
324
+ serialNumber: config.serial,
325
+ manufacturerId: config.brandId
326
+ } : void 0;
327
+ const scaleRegistrationPayload = config.scaleRegistration ?? fallbackScaleRegistration;
328
+ const scaleRegistration = scaleRegistrationPayload ? JSON.stringify(scaleRegistrationPayload) : void 0;
284
329
  return {
285
330
  api,
286
331
  events,
287
332
  auth,
288
- config: Object.freeze({ ...config }),
289
- mount: (options) => mountApp(options, config.apiBase, config.token || null),
290
- renderPassportList: (options) => renderPassportList(options, config.apiBase, config.token || null),
291
- renderPassport: (options) => renderPassport(options, config.apiBase, config.token || null)
333
+ config: Object.freeze({ ...config, mode }),
334
+ mount: (options) => mountApp(
335
+ {
336
+ ...options,
337
+ mode,
338
+ viewerUrl: config.viewerUrl,
339
+ scaleRegistration
340
+ },
341
+ config.apiBase,
342
+ config.token || null
343
+ ),
344
+ renderPassportList: (options) => renderPassportList(
345
+ {
346
+ ...options,
347
+ mode,
348
+ viewerUrl: config.viewerUrl,
349
+ scaleRegistration
350
+ },
351
+ config.apiBase,
352
+ config.token || null
353
+ ),
354
+ renderPassport: (options) => renderPassport(
355
+ {
356
+ ...options,
357
+ mode,
358
+ viewerUrl: config.viewerUrl,
359
+ scaleRegistration
360
+ },
361
+ config.apiBase,
362
+ config.token || null
363
+ )
292
364
  };
293
365
  }
366
+ var HoraeSDK = {
367
+ init(config) {
368
+ return createPassportSDK(config);
369
+ }
370
+ };
371
+ if (typeof window !== "undefined") {
372
+ window.HoraeSDK = HoraeSDK;
373
+ }
294
374
  // Annotate the CommonJS export names for ESM import in node:
295
375
  0 && (module.exports = {
376
+ HoraeSDK,
296
377
  createClient,
297
378
  createClientWithAuth,
298
379
  createCustomStrategy,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/events.ts","../src/auth/strategies/jwt.ts","../src/auth/strategies/custom.ts","../src/client.ts","../src/api.ts","../src/ui.ts"],"sourcesContent":["/**\n * @horae/passport-core\n * Reusable Passport SDK — auth strategies, Horae API client, events.\n * Token-based auth only; no cross-domain cookies.\n */\n\nexport type { PassportSDKConfig, AuthStrategy, PassportListItem, PassportDetail, User } from \"./types.js\";\nexport { createEventBus } from \"./events.js\";\nexport type { SDKEvent, EventMap, EventBus } from \"./events.js\";\nexport { createJwtStrategy, createCustomStrategy } from \"./auth/index.js\";\nexport type { AuthStrategyBase } from \"./auth/index.js\";\nexport { createClient, createClientWithAuth } from \"./client.js\";\nexport type { CreateClientOptions } from \"./client.js\";\nexport { createPassportApi } from \"./api.js\";\nexport * from \"./ui.js\";\n\nimport type { PassportSDKConfig } from \"./types.js\";\nimport { createEventBus } from \"./events.js\";\nimport { createJwtStrategy } from \"./auth/strategies/jwt.js\";\nimport { createCustomStrategy } from \"./auth/strategies/custom.js\";\nimport { createClient } from \"./client.js\";\nimport { createPassportApi } from \"./api.js\";\nimport type { AuthStrategyBase } from \"./auth/index.js\";\nimport { mountApp, renderPassportList, renderPassport } from \"./ui.js\";\nimport type { RenderOptions, RenderPassportOptions } from \"./ui.js\";\n\nexport interface PassportSDK {\n /** Horae API client (axios) */\n readonly api: ReturnType<typeof createPassportApi>;\n /** Event bus for auth:ready, auth:error, passport:claimed, etc. */\n readonly events: ReturnType<typeof createEventBus>;\n /** Auth strategy instance (for setToken/clearToken when available) */\n readonly auth: AuthStrategyBase;\n /** Config */\n readonly config: Readonly<PassportSDKConfig>;\n /** Mount the generic SDK App in headless mode */\n mount(options: RenderOptions): Promise<void>;\n /** Render the Passport List view */\n renderPassportList(options: RenderOptions): Promise<void>;\n /** Render a Single Passport Detail view */\n renderPassport(options: RenderPassportOptions): Promise<void>;\n}\n\n/**\n * Create the Passport SDK instance.\n * - authStrategy \"jwt\": pass token in config or call setToken on auth after getting JWT from your backend.\n * - authStrategy \"custom\": pass getToken in config.\n * - authStrategy \"shopify\": use @horae/passport-shopify to get JWT from bridge, then use jwt or custom.\n */\nexport function createPassportSDK(config: PassportSDKConfig): PassportSDK {\n const events = createEventBus();\n let auth: AuthStrategyBase;\n\n switch (config.authStrategy) {\n case \"jwt\": {\n const jwt = createJwtStrategy({\n token: config.token ?? undefined,\n storageKey: config.tokenStorageKey ?? undefined,\n });\n auth = jwt;\n break;\n }\n case \"custom\": {\n if (!config.getToken) throw new Error(\"PassportSDK: getToken required for authStrategy 'custom'\");\n auth = createCustomStrategy(config.getToken);\n break;\n }\n case \"shopify\":\n // Shopify: use JWT strategy; token is set by @horae/passport-shopify bridge\n auth = createJwtStrategy({\n token: config.token ?? undefined,\n storageKey: config.tokenStorageKey ?? \"shopify_access_token\",\n });\n break;\n case \"privy\":\n // Privy: use custom strategy with getToken from host (e.g. getAccessToken from @privy-io/react-auth)\n if (!config.getToken) throw new Error(\"PassportSDK: getToken required for authStrategy 'privy' (pass Privy getAccessToken)\");\n auth = createCustomStrategy(config.getToken);\n break;\n default:\n throw new Error(`PassportSDK: unknown authStrategy ${String((config as { authStrategy?: string }).authStrategy)}`);\n }\n\n const client = createClient({ apiBase: config.apiBase, getToken: () => auth.getToken() });\n const api = createPassportApi(client);\n\n return {\n api,\n events,\n auth,\n config: Object.freeze({ ...config }),\n mount: (options) => mountApp(options, config.apiBase, config.token || null),\n renderPassportList: (options) => renderPassportList(options, config.apiBase, config.token || null),\n renderPassport: (options) => renderPassport(options, config.apiBase, config.token || null),\n };\n}\n","/**\n * @horae/passport-core — event emitter for auth and passport events\n */\n\nexport type SDKEvent =\n | \"auth:ready\"\n | \"auth:error\"\n | \"passport:claimed\"\n | \"passport:loaded\"\n | \"passport:list:loaded\"\n | \"token:expired\";\n\nexport type EventMap = {\n \"auth:ready\": void;\n \"auth:error\": { message: string; code?: string };\n \"passport:claimed\": { tokenId: string };\n \"passport:loaded\": { tokenId: string };\n \"passport:list:loaded\": { count: number };\n \"token:expired\": void;\n};\n\ntype Listener<T> = (payload: T) => void;\n\nexport function createEventBus() {\n const listeners = new Map<SDKEvent, Set<Listener<unknown>>>();\n\n function on<E extends SDKEvent>(event: E, fn: Listener<EventMap[E]>) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(fn as Listener<unknown>);\n return () => listeners.get(event)?.delete(fn as Listener<unknown>);\n }\n\n function emit<E extends SDKEvent>(event: E, payload?: EventMap[E]) {\n listeners.get(event)?.forEach((fn) => (fn as Listener<EventMap[E]>)(payload as EventMap[E]));\n }\n\n return { on, emit };\n}\n\nexport type EventBus = ReturnType<typeof createEventBus>;\n","/**\n * JWT strategy — token from config or setToken; optional localStorage persistence\n */\n\nimport type { AuthStrategyBase } from \"../types.js\";\n\nexport interface JwtStrategyOptions {\n /** Initial token */\n token?: string | null;\n /** localStorage key for persistence (omit for in-memory only) */\n storageKey?: string | null;\n}\n\nexport function createJwtStrategy(options: JwtStrategyOptions = {}): AuthStrategyBase {\n let token: string | null = options.token ?? null;\n const storageKey = options.storageKey ?? null;\n\n const storage = typeof window !== \"undefined\" ? window.localStorage : undefined;\n if (storage && storageKey) {\n try {\n const stored = storage.getItem(storageKey);\n if (stored) token = stored;\n } catch {\n // ignore\n }\n }\n\n return {\n async getToken() {\n return token;\n },\n setToken(next: string | null) {\n token = next;\n if (storage && storageKey) {\n try {\n if (next) storage.setItem(storageKey, next);\n else storage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }\n },\n clearToken() {\n token = null;\n if (storage && storageKey) {\n try {\n storage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }\n },\n };\n}\n","/**\n * Custom strategy — caller supplies getToken (e.g. from backend or Privy)\n */\n\nimport type { AuthStrategyBase } from \"../types.js\";\n\nexport function createCustomStrategy(\n getToken: () => Promise<string | null>,\n): AuthStrategyBase {\n return { getToken };\n}\n","/**\n * Horae API client — axios instance with Bearer token from auth strategy\n */\n\nimport axios, { type AxiosInstance } from \"axios\";\nimport type { AuthStrategyBase } from \"./auth/index.js\";\n\nexport interface CreateClientOptions {\n apiBase: string;\n getToken: () => Promise<string | null>;\n}\n\nexport function createClient(options: CreateClientOptions): AxiosInstance {\n const { apiBase, getToken } = options;\n const client = axios.create({\n baseURL: apiBase.replace(/\\/v1\\/?$/, \"\") + \"/v1\",\n });\n\n client.interceptors.request.use(async (config) => {\n const token = await getToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n config.headers[\"ngrok-skip-browser-warning\"] = \"true\";\n return config;\n });\n\n return client;\n}\n\nexport function createClientWithAuth(auth: AuthStrategyBase, apiBase: string): AxiosInstance {\n return createClient({\n apiBase,\n getToken: () => auth.getToken(),\n });\n}\n","/**\n * Horae Passport API — list, single, claim, user, documents\n * Mirrors passport-web shared/api/api.service.ts (token-based auth)\n */\n\nimport type { AxiosInstance } from \"axios\";\nimport type { PassportListItem, PassportDetail, User } from \"./types.js\";\n\nfunction unwrapItems<T>(response: { data?: unknown }): T[] {\n const data = response.data as { data?: { items?: T[] }; items?: T[] } | T[] | undefined;\n if (Array.isArray(data)) return data;\n const inner = data && typeof data === \"object\" && \"data\" in data ? (data as { data?: { items?: T[] } }).data : data;\n const items = (inner && typeof inner === \"object\" && \"items\" in inner\n ? (inner as { items?: T[] }).items\n : Array.isArray(inner)\n ? inner\n : []) as T[];\n return items ?? [];\n}\n\nfunction unwrapData<T>(response: { data?: unknown }): T {\n const data = response.data as { data?: T } | T;\n return (data && typeof data === \"object\" && \"data\" in data ? (data as { data: T }).data : data) as T;\n}\n\nexport function createPassportApi(api: AxiosInstance) {\n return {\n /** List passports claimed by current user */\n async getMyClaimedPassports(): Promise<PassportListItem[]> {\n const res = await api.get(\"/api/passport/claimed\");\n return unwrapItems<PassportListItem>(res) as PassportListItem[];\n },\n\n /** List passports by owner wallet (e.g. Shopify) */\n async getPassportsByOwner(ownerWallet: string): Promise<PassportListItem[]> {\n const res = await api.get(\"/api/passport/claimed\", { params: { owner: ownerWallet } });\n return unwrapItems<PassportListItem>(res) as PassportListItem[];\n },\n\n /** Single passport (authenticated) */\n async getPassport(tokenId: string, isAuthenticated = true): Promise<PassportDetail> {\n const path = isAuthenticated ? `/api/passport/${tokenId}` : `/api/passport/public/${tokenId}`;\n const res = await api.get(path);\n return unwrapData<PassportDetail>(res);\n },\n\n /** Claim passport */\n async claimPassport(data: { tokenId: string; toAddress: string; claimKey: string }) {\n await api.post(\"/api/passport/claim\", data);\n },\n\n /** Shopify claim (serialNumber + optional email) */\n async claimShopifyPassport(data: { serialNumber: string; email?: string }) {\n await api.post(\"/api/passport/shopify-claim\", data);\n },\n\n /** Current user profile */\n async getMe(): Promise<User> {\n const res = await api.get(\"/users/me\");\n const raw = unwrapData<unknown>(res);\n const doc = raw && typeof raw === \"object\" && \"_doc\" in raw ? (raw as { _doc: User })._doc : raw;\n return doc as User;\n },\n\n /** Documents for a passport (owner gets file URLs) */\n async getDocuments(tokenId: string): Promise<{ url?: string; name?: string; [k: string]: unknown }[]> {\n const res = await api.get(`/api/passport/${tokenId}/documents`);\n const responseData = (res.data as { data?: unknown })?.data ?? res.data;\n if (responseData && typeof responseData === \"object\" && \"data\" in responseData && Array.isArray((responseData as { data: unknown[] }).data))\n return (responseData as { data: unknown[] }).data as { url?: string; name?: string; [k: string]: unknown }[];\n if (Array.isArray(responseData)) return responseData as { url?: string; name?: string; [k: string]: unknown }[];\n return [];\n },\n\n /** Transfer passport to user by email */\n async transferPassportToUser(data: { tokenId: string; recipientEmail: string }) {\n await api.post(\"/api/passport/transfer-to-user\", data);\n },\n\n /** Set stolen status */\n async setStolenStatus(data: { tokenId: string; isStolen: boolean }) {\n await api.post(\"/api/passport/set-stolen\", data);\n },\n };\n}\n","/**\n * UI Renderer for @horae/passport-core\n * Dynamically injects the pre-built React SDK bundle to render the UI on the host page.\n */\n\nexport interface RenderOptions {\n /** CSS selector of the container element (e.g. \"#passport-app\") */\n container: string;\n /** UI Host base URL where the bundle is served (default: https://app.horae.io) */\n uiHost?: string;\n /** Initial tab/view (e.g. \"passports\", \"claim\", \"settings\") */\n initialTab?: string;\n}\n\nexport interface RenderPassportOptions extends RenderOptions {\n /** The ID of the passport to show */\n passportId: string;\n}\n\n/**\n * Configure the container with data attributes so the UI bundle can read them upon mounting.\n */\nfunction prepareContainer(options: RenderOptions, apiBase: string, token: string | null) {\n const containerEl = document.querySelector(options.container);\n if (!containerEl) {\n throw new Error(`PassportSDK: container element '${options.container}' not found.`);\n }\n\n // Set necessary data attributes for the UI bundle (similar to Shopify embed contract)\n if (containerEl instanceof HTMLElement) {\n containerEl.dataset.horaeApiBase = apiBase;\n if (options.initialTab) {\n containerEl.dataset.initialTab = options.initialTab;\n }\n\n // Inject the token (the UI bundle will look for this or use its own mechanism)\n if (token) {\n containerEl.dataset.horaeToken = token;\n }\n\n // Add a signature class/id to ensure the embed root is identifiable\n containerEl.classList.add(\"horae-sdk-root\");\n\n // Allow the bundle to easily find its mount point if it uses querySelector internally\n // (We also pass the container selector directly to the mount event later if needed)\n containerEl.dataset.containerSelector = options.container;\n }\n\n return containerEl;\n}\n\n/**\n * Inject the script tag for the UI bundle if it hasn't been injected yet.\n */\nfunction loadUIBundle(uiHost: string): Promise<void> {\n const SCRIPT_ID = \"horae-passport-sdk-ui\";\n\n return new Promise((resolve, reject) => {\n if (document.getElementById(SCRIPT_ID)) {\n // Script already added\n resolve();\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = SCRIPT_ID;\n script.type = \"module\";\n // Target the newly created sdk-embed entrypoint\n script.src = `${uiHost.replace(/\\/$/, '')}/sdk-embed.js`;\n\n script.onload = () => resolve();\n script.onerror = () => reject(new Error(`PassportSDK: Failed to load UI bundle from ${script.src}`));\n\n document.head.appendChild(script);\n });\n}\n\n/**\n * Render the generic SDK App\n */\nexport async function mountApp(\n options: RenderOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n prepareContainer(options, apiBase, token);\n\n const host = options.uiHost || \"https://app.horae.io\";\n await loadUIBundle(host);\n\n // Dispatch a custom event in case the bundle is already loaded and listening for dynamic mounts\n window.dispatchEvent(new CustomEvent(\"horae:sdk:mount\", {\n detail: { container: options.container }\n }));\n}\n\n/**\n * Render specifically the Passport List (maps to \"passports\" tab/view)\n */\nexport async function renderPassportList(\n options: RenderOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n return mountApp({ ...options, initialTab: \"passports\" }, apiBase, token);\n}\n\n/**\n * Render specifically a Single Passport (maps to a specific detail view layout)\n */\nexport async function renderPassport(\n options: RenderPassportOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n const containerEl = prepareContainer(options, apiBase, token);\n\n if (containerEl instanceof HTMLElement) {\n containerEl.dataset.passportId = options.passportId;\n // Set initialTab to \"detail\" or a specific flag the UI recognizes\n containerEl.dataset.initialTab = \"detail\";\n }\n\n const host = options.uiHost || \"https://app.horae.io\";\n await loadUIBundle(host);\n\n window.dispatchEvent(new CustomEvent(\"horae:sdk:mount\", {\n detail: { container: options.container, passportId: options.passportId }\n }));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuBO,SAAS,iBAAiB;AAC/B,QAAM,YAAY,oBAAI,IAAsC;AAE5D,WAAS,GAAuB,OAAU,IAA2B;AACnE,QAAI,CAAC,UAAU,IAAI,KAAK,EAAG,WAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AACzD,cAAU,IAAI,KAAK,EAAG,IAAI,EAAuB;AACjD,WAAO,MAAM,UAAU,IAAI,KAAK,GAAG,OAAO,EAAuB;AAAA,EACnE;AAEA,WAAS,KAAyB,OAAU,SAAuB;AACjE,cAAU,IAAI,KAAK,GAAG,QAAQ,CAAC,OAAQ,GAA6B,OAAsB,CAAC;AAAA,EAC7F;AAEA,SAAO,EAAE,IAAI,KAAK;AACpB;;;ACxBO,SAAS,kBAAkB,UAA8B,CAAC,GAAqB;AACpF,MAAI,QAAuB,QAAQ,SAAS;AAC5C,QAAM,aAAa,QAAQ,cAAc;AAEzC,QAAM,UAAU,OAAO,WAAW,cAAc,OAAO,eAAe;AACtE,MAAI,WAAW,YAAY;AACzB,QAAI;AACF,YAAM,SAAS,QAAQ,QAAQ,UAAU;AACzC,UAAI,OAAQ,SAAQ;AAAA,IACtB,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,WAAW;AACf,aAAO;AAAA,IACT;AAAA,IACA,SAAS,MAAqB;AAC5B,cAAQ;AACR,UAAI,WAAW,YAAY;AACzB,YAAI;AACF,cAAI,KAAM,SAAQ,QAAQ,YAAY,IAAI;AAAA,cACrC,SAAQ,WAAW,UAAU;AAAA,QACpC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,IACA,aAAa;AACX,cAAQ;AACR,UAAI,WAAW,YAAY;AACzB,YAAI;AACF,kBAAQ,WAAW,UAAU;AAAA,QAC/B,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AC/CO,SAAS,qBACd,UACkB;AAClB,SAAO,EAAE,SAAS;AACpB;;;ACNA,mBAA0C;AAQnC,SAAS,aAAa,SAA6C;AACxE,QAAM,EAAE,SAAS,SAAS,IAAI;AAC9B,QAAM,SAAS,aAAAA,QAAM,OAAO;AAAA,IAC1B,SAAS,QAAQ,QAAQ,YAAY,EAAE,IAAI;AAAA,EAC7C,CAAC;AAED,SAAO,aAAa,QAAQ,IAAI,OAAO,WAAW;AAChD,UAAM,QAAQ,MAAM,SAAS;AAC7B,QAAI,OAAO;AACT,aAAO,QAAQ,gBAAgB,UAAU,KAAK;AAAA,IAChD;AACA,WAAO,QAAQ,4BAA4B,IAAI;AAC/C,WAAO;AAAA,EACT,CAAC;AAED,SAAO;AACT;AAEO,SAAS,qBAAqB,MAAwB,SAAgC;AAC3F,SAAO,aAAa;AAAA,IAClB;AAAA,IACA,UAAU,MAAM,KAAK,SAAS;AAAA,EAChC,CAAC;AACH;;;AC3BA,SAAS,YAAe,UAAmC;AACzD,QAAM,OAAO,SAAS;AACtB,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO;AAChC,QAAM,QAAQ,QAAQ,OAAO,SAAS,YAAY,UAAU,OAAQ,KAAoC,OAAO;AAC/G,QAAM,QAAS,SAAS,OAAO,UAAU,YAAY,WAAW,QAC3D,MAA0B,QAC3B,MAAM,QAAQ,KAAK,IACjB,QACA,CAAC;AACP,SAAO,SAAS,CAAC;AACnB;AAEA,SAAS,WAAc,UAAiC;AACtD,QAAM,OAAO,SAAS;AACtB,SAAQ,QAAQ,OAAO,SAAS,YAAY,UAAU,OAAQ,KAAqB,OAAO;AAC5F;AAEO,SAAS,kBAAkB,KAAoB;AACpD,SAAO;AAAA;AAAA,IAEL,MAAM,wBAAqD;AACzD,YAAM,MAAM,MAAM,IAAI,IAAI,uBAAuB;AACjD,aAAO,YAA8B,GAAG;AAAA,IAC1C;AAAA;AAAA,IAGA,MAAM,oBAAoB,aAAkD;AAC1E,YAAM,MAAM,MAAM,IAAI,IAAI,yBAAyB,EAAE,QAAQ,EAAE,OAAO,YAAY,EAAE,CAAC;AACrF,aAAO,YAA8B,GAAG;AAAA,IAC1C;AAAA;AAAA,IAGA,MAAM,YAAY,SAAiB,kBAAkB,MAA+B;AAClF,YAAM,OAAO,kBAAkB,iBAAiB,OAAO,KAAK,wBAAwB,OAAO;AAC3F,YAAM,MAAM,MAAM,IAAI,IAAI,IAAI;AAC9B,aAAO,WAA2B,GAAG;AAAA,IACvC;AAAA;AAAA,IAGA,MAAM,cAAc,MAAgE;AAClF,YAAM,IAAI,KAAK,uBAAuB,IAAI;AAAA,IAC5C;AAAA;AAAA,IAGA,MAAM,qBAAqB,MAAgD;AACzE,YAAM,IAAI,KAAK,+BAA+B,IAAI;AAAA,IACpD;AAAA;AAAA,IAGA,MAAM,QAAuB;AAC3B,YAAM,MAAM,MAAM,IAAI,IAAI,WAAW;AACrC,YAAM,MAAM,WAAoB,GAAG;AACnC,YAAM,MAAM,OAAO,OAAO,QAAQ,YAAY,UAAU,MAAO,IAAuB,OAAO;AAC7F,aAAO;AAAA,IACT;AAAA;AAAA,IAGA,MAAM,aAAa,SAAmF;AACpG,YAAM,MAAM,MAAM,IAAI,IAAI,iBAAiB,OAAO,YAAY;AAC9D,YAAM,eAAgB,IAAI,MAA6B,QAAQ,IAAI;AACnE,UAAI,gBAAgB,OAAO,iBAAiB,YAAY,UAAU,gBAAgB,MAAM,QAAS,aAAqC,IAAI;AACxI,eAAQ,aAAqC;AAC/C,UAAI,MAAM,QAAQ,YAAY,EAAG,QAAO;AACxC,aAAO,CAAC;AAAA,IACV;AAAA;AAAA,IAGA,MAAM,uBAAuB,MAAmD;AAC9E,YAAM,IAAI,KAAK,kCAAkC,IAAI;AAAA,IACvD;AAAA;AAAA,IAGA,MAAM,gBAAgB,MAA8C;AAClE,YAAM,IAAI,KAAK,4BAA4B,IAAI;AAAA,IACjD;AAAA,EACF;AACF;;;AC9DA,SAAS,iBAAiB,SAAwB,SAAiB,OAAsB;AACrF,QAAM,cAAc,SAAS,cAAc,QAAQ,SAAS;AAC5D,MAAI,CAAC,aAAa;AACd,UAAM,IAAI,MAAM,mCAAmC,QAAQ,SAAS,cAAc;AAAA,EACtF;AAGA,MAAI,uBAAuB,aAAa;AACpC,gBAAY,QAAQ,eAAe;AACnC,QAAI,QAAQ,YAAY;AACpB,kBAAY,QAAQ,aAAa,QAAQ;AAAA,IAC7C;AAGA,QAAI,OAAO;AACP,kBAAY,QAAQ,aAAa;AAAA,IACrC;AAGA,gBAAY,UAAU,IAAI,gBAAgB;AAI1C,gBAAY,QAAQ,oBAAoB,QAAQ;AAAA,EACpD;AAEA,SAAO;AACX;AAKA,SAAS,aAAa,QAA+B;AACjD,QAAM,YAAY;AAElB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACpC,QAAI,SAAS,eAAe,SAAS,GAAG;AAEpC,cAAQ;AACR;AAAA,IACJ;AAEA,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,KAAK;AACZ,WAAO,OAAO;AAEd,WAAO,MAAM,GAAG,OAAO,QAAQ,OAAO,EAAE,CAAC;AAEzC,WAAO,SAAS,MAAM,QAAQ;AAC9B,WAAO,UAAU,MAAM,OAAO,IAAI,MAAM,8CAA8C,OAAO,GAAG,EAAE,CAAC;AAEnG,aAAS,KAAK,YAAY,MAAM;AAAA,EACpC,CAAC;AACL;AAKA,eAAsB,SAClB,SACA,SACA,OACa;AACb,mBAAiB,SAAS,SAAS,KAAK;AAExC,QAAM,OAAO,QAAQ,UAAU;AAC/B,QAAM,aAAa,IAAI;AAGvB,SAAO,cAAc,IAAI,YAAY,mBAAmB;AAAA,IACpD,QAAQ,EAAE,WAAW,QAAQ,UAAU;AAAA,EAC3C,CAAC,CAAC;AACN;AAKA,eAAsB,mBAClB,SACA,SACA,OACa;AACb,SAAO,SAAS,EAAE,GAAG,SAAS,YAAY,YAAY,GAAG,SAAS,KAAK;AAC3E;AAKA,eAAsB,eAClB,SACA,SACA,OACa;AACb,QAAM,cAAc,iBAAiB,SAAS,SAAS,KAAK;AAE5D,MAAI,uBAAuB,aAAa;AACpC,gBAAY,QAAQ,aAAa,QAAQ;AAEzC,gBAAY,QAAQ,aAAa;AAAA,EACrC;AAEA,QAAM,OAAO,QAAQ,UAAU;AAC/B,QAAM,aAAa,IAAI;AAEvB,SAAO,cAAc,IAAI,YAAY,mBAAmB;AAAA,IACpD,QAAQ,EAAE,WAAW,QAAQ,WAAW,YAAY,QAAQ,WAAW;AAAA,EAC3E,CAAC,CAAC;AACN;;;ANhFO,SAAS,kBAAkB,QAAwC;AACxE,QAAM,SAAS,eAAe;AAC9B,MAAI;AAEJ,UAAQ,OAAO,cAAc;AAAA,IAC3B,KAAK,OAAO;AACV,YAAM,MAAM,kBAAkB;AAAA,QAC5B,OAAO,OAAO,SAAS;AAAA,QACvB,YAAY,OAAO,mBAAmB;AAAA,MACxC,CAAC;AACD,aAAO;AACP;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,UAAI,CAAC,OAAO,SAAU,OAAM,IAAI,MAAM,0DAA0D;AAChG,aAAO,qBAAqB,OAAO,QAAQ;AAC3C;AAAA,IACF;AAAA,IACA,KAAK;AAEH,aAAO,kBAAkB;AAAA,QACvB,OAAO,OAAO,SAAS;AAAA,QACvB,YAAY,OAAO,mBAAmB;AAAA,MACxC,CAAC;AACD;AAAA,IACF,KAAK;AAEH,UAAI,CAAC,OAAO,SAAU,OAAM,IAAI,MAAM,qFAAqF;AAC3H,aAAO,qBAAqB,OAAO,QAAQ;AAC3C;AAAA,IACF;AACE,YAAM,IAAI,MAAM,qCAAqC,OAAQ,OAAqC,YAAY,CAAC,EAAE;AAAA,EACrH;AAEA,QAAM,SAAS,aAAa,EAAE,SAAS,OAAO,SAAS,UAAU,MAAM,KAAK,SAAS,EAAE,CAAC;AACxF,QAAM,MAAM,kBAAkB,MAAM;AAEpC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,OAAO,OAAO,EAAE,GAAG,OAAO,CAAC;AAAA,IACnC,OAAO,CAAC,YAAY,SAAS,SAAS,OAAO,SAAS,OAAO,SAAS,IAAI;AAAA,IAC1E,oBAAoB,CAAC,YAAY,mBAAmB,SAAS,OAAO,SAAS,OAAO,SAAS,IAAI;AAAA,IACjG,gBAAgB,CAAC,YAAY,eAAe,SAAS,OAAO,SAAS,OAAO,SAAS,IAAI;AAAA,EAC3F;AACF;","names":["axios"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/events.ts","../src/auth/strategies/jwt.ts","../src/auth/strategies/custom.ts","../src/client.ts","../src/api.ts","../src/ui.ts"],"sourcesContent":["/**\n * @horae/passport-core\n * Reusable Passport SDK — auth strategies, Horae API client, events.\n * Token-based auth only; no cross-domain cookies.\n */\n\nexport type {\n PassportSDKConfig,\n AuthStrategy,\n PassportListItem,\n PassportDetail,\n ScaleRegistrationPayload,\n SDKMode,\n User,\n} from \"./types.js\";\nexport { createEventBus } from \"./events.js\";\nexport type { SDKEvent, EventMap, EventBus } from \"./events.js\";\nexport { createJwtStrategy, createCustomStrategy } from \"./auth/index.js\";\nexport type { AuthStrategyBase } from \"./auth/index.js\";\nexport { createClient, createClientWithAuth } from \"./client.js\";\nexport type { CreateClientOptions } from \"./client.js\";\nexport { createPassportApi } from \"./api.js\";\nexport * from \"./ui.js\";\n\nimport type { PassportSDKConfig } from \"./types.js\";\nimport { createEventBus } from \"./events.js\";\nimport { createJwtStrategy } from \"./auth/strategies/jwt.js\";\nimport { createCustomStrategy } from \"./auth/strategies/custom.js\";\nimport { createClient } from \"./client.js\";\nimport { createPassportApi } from \"./api.js\";\nimport type { AuthStrategyBase } from \"./auth/index.js\";\nimport { mountApp, renderPassportList, renderPassport } from \"./ui.js\";\nimport type { RenderOptions, RenderPassportOptions } from \"./ui.js\";\n\nexport interface PassportSDK {\n /** Horae API client (axios) */\n readonly api: ReturnType<typeof createPassportApi>;\n /** Event bus for auth:ready, auth:error, passport:claimed, etc. */\n readonly events: ReturnType<typeof createEventBus>;\n /** Auth strategy instance (for setToken/clearToken when available) */\n readonly auth: AuthStrategyBase;\n /** Config */\n readonly config: Readonly<PassportSDKConfig>;\n /** Mount the generic SDK App in headless mode */\n mount(options: RenderOptions): Promise<void>;\n /** Render the Passport List view */\n renderPassportList(options: RenderOptions): Promise<void>;\n /** Render a Single Passport Detail view */\n renderPassport(options: RenderPassportOptions): Promise<void>;\n}\n\n/**\n * Create the Passport SDK instance.\n * - authStrategy \"jwt\": pass token in config or call setToken on auth after getting JWT from your backend.\n * - authStrategy \"custom\": pass getToken in config.\n * - authStrategy \"shopify\": use @horae/passport-shopify to get JWT from bridge, then use jwt or custom.\n */\nexport function createPassportSDK(config: PassportSDKConfig): PassportSDK {\n const mode = config.mode ?? \"heritage\";\n const authStrategy = config.authStrategy ?? (mode === \"scale\" ? \"custom\" : \"jwt\");\n const events = createEventBus();\n let auth: AuthStrategyBase;\n\n if (mode === \"scale\") {\n // Scale mode does not require wallet/Privy token flow by default.\n auth = createCustomStrategy(async () => config.token ?? null);\n } else {\n switch (authStrategy) {\n case \"jwt\": {\n const jwt = createJwtStrategy({\n token: config.token ?? undefined,\n storageKey: config.tokenStorageKey ?? undefined,\n });\n auth = jwt;\n break;\n }\n case \"custom\": {\n if (!config.getToken) throw new Error(\"PassportSDK: getToken required for authStrategy 'custom'\");\n auth = createCustomStrategy(config.getToken);\n break;\n }\n case \"shopify\":\n // Shopify: use JWT strategy; token is set by @horae/passport-shopify bridge\n auth = createJwtStrategy({\n token: config.token ?? undefined,\n storageKey: config.tokenStorageKey ?? \"shopify_access_token\",\n });\n break;\n case \"privy\":\n // Privy: use custom strategy with getToken from host (e.g. getAccessToken from @privy-io/react-auth)\n if (!config.getToken) throw new Error(\"PassportSDK: getToken required for authStrategy 'privy' (pass Privy getAccessToken)\");\n auth = createCustomStrategy(config.getToken);\n break;\n default:\n throw new Error(`PassportSDK: unknown authStrategy ${String(authStrategy)}`);\n }\n }\n\n const client = createClient({ apiBase: config.apiBase, getToken: () => auth.getToken() });\n const api = createPassportApi(client);\n const fallbackScaleRegistration =\n config.serial || config.brandId\n ? {\n serialNumber: config.serial,\n manufacturerId: config.brandId,\n }\n : undefined;\n const scaleRegistrationPayload = config.scaleRegistration ?? fallbackScaleRegistration;\n const scaleRegistration = scaleRegistrationPayload\n ? JSON.stringify(scaleRegistrationPayload)\n : undefined;\n\n return {\n api,\n events,\n auth,\n config: Object.freeze({ ...config, mode }),\n mount: (options) =>\n mountApp(\n {\n ...options,\n mode,\n viewerUrl: config.viewerUrl,\n scaleRegistration,\n },\n config.apiBase,\n config.token || null,\n ),\n renderPassportList: (options) =>\n renderPassportList(\n {\n ...options,\n mode,\n viewerUrl: config.viewerUrl,\n scaleRegistration,\n },\n config.apiBase,\n config.token || null,\n ),\n renderPassport: (options) =>\n renderPassport(\n {\n ...options,\n mode,\n viewerUrl: config.viewerUrl,\n scaleRegistration,\n },\n config.apiBase,\n config.token || null,\n ),\n };\n}\n\nexport const HoraeSDK = {\n init(config: PassportSDKConfig): PassportSDK {\n return createPassportSDK(config);\n },\n};\n\ndeclare global {\n interface Window {\n HoraeSDK?: typeof HoraeSDK;\n }\n}\n\nif (typeof window !== \"undefined\") {\n window.HoraeSDK = HoraeSDK;\n}\n","/**\n * @horae/passport-core — event emitter for auth and passport events\n */\n\nexport type SDKEvent =\n | \"auth:ready\"\n | \"auth:error\"\n | \"passport:claimed\"\n | \"passport:loaded\"\n | \"passport:list:loaded\"\n | \"token:expired\";\n\nexport type EventMap = {\n \"auth:ready\": void;\n \"auth:error\": { message: string; code?: string };\n \"passport:claimed\": { tokenId: string };\n \"passport:loaded\": { tokenId: string };\n \"passport:list:loaded\": { count: number };\n \"token:expired\": void;\n};\n\ntype Listener<T> = (payload: T) => void;\n\nexport function createEventBus() {\n const listeners = new Map<SDKEvent, Set<Listener<unknown>>>();\n\n function on<E extends SDKEvent>(event: E, fn: Listener<EventMap[E]>) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(fn as Listener<unknown>);\n return () => listeners.get(event)?.delete(fn as Listener<unknown>);\n }\n\n function emit<E extends SDKEvent>(event: E, payload?: EventMap[E]) {\n listeners.get(event)?.forEach((fn) => (fn as Listener<EventMap[E]>)(payload as EventMap[E]));\n }\n\n return { on, emit };\n}\n\nexport type EventBus = ReturnType<typeof createEventBus>;\n","/**\n * JWT strategy — token from config or setToken; optional localStorage persistence\n */\n\nimport type { AuthStrategyBase } from \"../types.js\";\n\nexport interface JwtStrategyOptions {\n /** Initial token */\n token?: string | null;\n /** localStorage key for persistence (omit for in-memory only) */\n storageKey?: string | null;\n}\n\nexport function createJwtStrategy(options: JwtStrategyOptions = {}): AuthStrategyBase {\n let token: string | null = options.token ?? null;\n const storageKey = options.storageKey ?? null;\n\n const storage = typeof window !== \"undefined\" ? window.localStorage : undefined;\n if (storage && storageKey) {\n try {\n const stored = storage.getItem(storageKey);\n if (stored) token = stored;\n } catch {\n // ignore\n }\n }\n\n return {\n async getToken() {\n return token;\n },\n setToken(next: string | null) {\n token = next;\n if (storage && storageKey) {\n try {\n if (next) storage.setItem(storageKey, next);\n else storage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }\n },\n clearToken() {\n token = null;\n if (storage && storageKey) {\n try {\n storage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }\n },\n };\n}\n","/**\n * Custom strategy — caller supplies getToken (e.g. from backend or Privy)\n */\n\nimport type { AuthStrategyBase } from \"../types.js\";\n\nexport function createCustomStrategy(\n getToken: () => Promise<string | null>,\n): AuthStrategyBase {\n return { getToken };\n}\n","/**\n * Horae API client — axios instance with Bearer token from auth strategy\n */\n\nimport axios, { type AxiosInstance } from \"axios\";\nimport type { AuthStrategyBase } from \"./auth/index.js\";\n\nexport interface CreateClientOptions {\n apiBase: string;\n getToken: () => Promise<string | null>;\n}\n\nexport function createClient(options: CreateClientOptions): AxiosInstance {\n const { apiBase, getToken } = options;\n const client = axios.create({\n baseURL: apiBase.replace(/\\/v1\\/?$/, \"\") + \"/v1\",\n });\n\n client.interceptors.request.use(async (config) => {\n const token = await getToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n config.headers[\"ngrok-skip-browser-warning\"] = \"true\";\n return config;\n });\n\n return client;\n}\n\nexport function createClientWithAuth(auth: AuthStrategyBase, apiBase: string): AxiosInstance {\n return createClient({\n apiBase,\n getToken: () => auth.getToken(),\n });\n}\n","/**\n * Horae Passport API — list, single, claim, user, documents\n * Mirrors passport-web shared/api/api.service.ts (token-based auth)\n */\n\nimport type { AxiosInstance } from \"axios\";\nimport type {\n PassportListItem,\n PassportDetail,\n ScaleRegistrationPayload,\n User,\n} from \"./types.js\";\n\nfunction unwrapItems<T>(response: { data?: unknown }): T[] {\n const data = response.data as { data?: { items?: T[] }; items?: T[] } | T[] | undefined;\n if (Array.isArray(data)) return data;\n const inner = data && typeof data === \"object\" && \"data\" in data ? (data as { data?: { items?: T[] } }).data : data;\n const items = (inner && typeof inner === \"object\" && \"items\" in inner\n ? (inner as { items?: T[] }).items\n : Array.isArray(inner)\n ? inner\n : []) as T[];\n return items ?? [];\n}\n\nfunction unwrapData<T>(response: { data?: unknown }): T {\n const data = response.data as { data?: T } | T;\n return (data && typeof data === \"object\" && \"data\" in data ? (data as { data: T }).data : data) as T;\n}\n\nexport function createPassportApi(api: AxiosInstance) {\n return {\n /** List passports claimed by current user */\n async getMyClaimedPassports(): Promise<PassportListItem[]> {\n const res = await api.get(\"/api/passport/claimed\");\n return unwrapItems<PassportListItem>(res) as PassportListItem[];\n },\n\n /** List passports by owner wallet (e.g. Shopify) */\n async getPassportsByOwner(ownerWallet: string): Promise<PassportListItem[]> {\n const res = await api.get(\"/api/passport/claimed\", { params: { owner: ownerWallet } });\n return unwrapItems<PassportListItem>(res) as PassportListItem[];\n },\n\n /** Single passport (authenticated) */\n async getPassport(tokenId: string, isAuthenticated = true): Promise<PassportDetail> {\n const path = isAuthenticated ? `/api/passport/${tokenId}` : `/api/passport/public/${tokenId}`;\n const res = await api.get(path);\n return unwrapData<PassportDetail>(res);\n },\n\n /** Claim passport */\n async claimPassport(data: { tokenId: string; toAddress: string; claimKey: string }) {\n await api.post(\"/api/passport/claim\", data);\n },\n\n /** Shopify claim (serialNumber + optional email) */\n async claimShopifyPassport(data: { serialNumber: string; email?: string }) {\n await api.post(\"/api/passport/shopify-claim\", data);\n },\n\n /** Scale owner registration (serial/email based, no wallet) */\n async registerScaleOwner(payload: ScaleRegistrationPayload): Promise<{\n success: boolean;\n tokenId: string;\n ownerUrl?: string;\n viewerUrl?: string;\n }> {\n const res = await api.post(\"/api/passport/scale/register\", payload);\n return unwrapData<{\n success: boolean;\n tokenId: string;\n ownerUrl?: string;\n viewerUrl?: string;\n }>(res);\n },\n\n /** Scale signed viewer (HMAC signature) */\n async getScaleViewer(tokenId: string, sig: string): Promise<PassportDetail> {\n const res = await api.get(`/api/passport/scale/view/${tokenId}`, {\n params: { sig },\n });\n return unwrapData<PassportDetail>(res);\n },\n\n /** Current user profile */\n async getMe(): Promise<User> {\n const res = await api.get(\"/users/me\");\n const raw = unwrapData<unknown>(res);\n const doc = raw && typeof raw === \"object\" && \"_doc\" in raw ? (raw as { _doc: User })._doc : raw;\n return doc as User;\n },\n\n /** Documents for a passport (owner gets file URLs) */\n async getDocuments(tokenId: string): Promise<{ url?: string; name?: string; [k: string]: unknown }[]> {\n const res = await api.get(`/api/passport/${tokenId}/documents`);\n const responseData = (res.data as { data?: unknown })?.data ?? res.data;\n if (responseData && typeof responseData === \"object\" && \"data\" in responseData && Array.isArray((responseData as { data: unknown[] }).data))\n return (responseData as { data: unknown[] }).data as { url?: string; name?: string; [k: string]: unknown }[];\n if (Array.isArray(responseData)) return responseData as { url?: string; name?: string; [k: string]: unknown }[];\n return [];\n },\n\n /** Transfer passport to user by email */\n async transferPassportToUser(data: { tokenId: string; recipientEmail: string }) {\n await api.post(\"/api/passport/transfer-to-user\", data);\n },\n\n /** Set stolen status */\n async setStolenStatus(data: { tokenId: string; isStolen: boolean }) {\n await api.post(\"/api/passport/set-stolen\", data);\n },\n };\n}\n","/**\n * UI Renderer for @horae/passport-core\n * Dynamically injects the pre-built React SDK bundle to render the UI on the host page.\n */\n\nexport interface RenderOptions {\n /** CSS selector of the container element (e.g. \"#passport-app\") */\n container: string;\n /** UI Host base URL where the bundle is served (default: https://app.horae.io) */\n uiHost?: string;\n /** Initial tab/view (e.g. \"passports\", \"claim\", \"settings\") */\n initialTab?: string;\n /** SDK mode */\n mode?: \"heritage\" | \"scale\";\n /** Scale mode signed viewer URL */\n viewerUrl?: string;\n /** Scale mode registration prefill as JSON string */\n scaleRegistration?: string;\n}\n\nexport interface RenderPassportOptions extends RenderOptions {\n /** The ID of the passport to show */\n passportId: string;\n}\n\n/**\n * Configure the container with data attributes so the UI bundle can read them upon mounting.\n */\nfunction prepareContainer(options: RenderOptions, apiBase: string, token: string | null) {\n const containerEl = document.querySelector(options.container);\n if (!containerEl) {\n throw new Error(`PassportSDK: container element '${options.container}' not found.`);\n }\n\n // Set necessary data attributes for the UI bundle (similar to Shopify embed contract)\n if (containerEl instanceof HTMLElement) {\n containerEl.dataset.horaeApiBase = apiBase;\n if (options.initialTab) {\n containerEl.dataset.initialTab = options.initialTab;\n }\n if (options.mode) {\n containerEl.dataset.horaeMode = options.mode;\n }\n if (options.viewerUrl) {\n containerEl.dataset.horaeViewerUrl = options.viewerUrl;\n }\n if (options.scaleRegistration) {\n containerEl.dataset.horaeScaleRegistration = options.scaleRegistration;\n }\n\n // Inject the token (the UI bundle will look for this or use its own mechanism)\n if (token) {\n containerEl.dataset.horaeToken = token;\n }\n\n // Add a signature class/id to ensure the embed root is identifiable\n containerEl.classList.add(\"horae-sdk-root\");\n\n // Allow the bundle to easily find its mount point if it uses querySelector internally\n // (We also pass the container selector directly to the mount event later if needed)\n containerEl.dataset.containerSelector = options.container;\n }\n\n return containerEl;\n}\n\n/**\n * Inject the script tag for the UI bundle if it hasn't been injected yet.\n */\nfunction loadUIBundle(uiHost: string): Promise<void> {\n const SCRIPT_ID = \"horae-passport-sdk-ui\";\n\n return new Promise((resolve, reject) => {\n if (document.getElementById(SCRIPT_ID)) {\n // Script already added\n resolve();\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = SCRIPT_ID;\n script.type = \"module\";\n // Target the newly created sdk-embed entrypoint\n script.src = `${uiHost.replace(/\\/$/, '')}/sdk-embed.js`;\n\n script.onload = () => resolve();\n script.onerror = () => reject(new Error(`PassportSDK: Failed to load UI bundle from ${script.src}`));\n\n document.head.appendChild(script);\n });\n}\n\n/**\n * Render the generic SDK App\n */\nexport async function mountApp(\n options: RenderOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n prepareContainer(options, apiBase, token);\n\n const host = options.uiHost || \"https://app.horae.io\";\n await loadUIBundle(host);\n\n // Dispatch a custom event in case the bundle is already loaded and listening for dynamic mounts\n window.dispatchEvent(new CustomEvent(\"horae:sdk:mount\", {\n detail: {\n container: options.container,\n mode: options.mode,\n viewerUrl: options.viewerUrl,\n scaleRegistration: options.scaleRegistration\n }\n }));\n}\n\n/**\n * Render specifically the Passport List (maps to \"passports\" tab/view)\n */\nexport async function renderPassportList(\n options: RenderOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n return mountApp({ ...options, initialTab: \"passports\" }, apiBase, token);\n}\n\n/**\n * Render specifically a Single Passport (maps to a specific detail view layout)\n */\nexport async function renderPassport(\n options: RenderPassportOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n const containerEl = prepareContainer(options, apiBase, token);\n\n if (containerEl instanceof HTMLElement) {\n containerEl.dataset.passportId = options.passportId;\n // Set initialTab to \"detail\" or a specific flag the UI recognizes\n containerEl.dataset.initialTab = \"detail\";\n }\n\n const host = options.uiHost || \"https://app.horae.io\";\n await loadUIBundle(host);\n\n window.dispatchEvent(new CustomEvent(\"horae:sdk:mount\", {\n detail: {\n container: options.container,\n passportId: options.passportId,\n mode: options.mode,\n viewerUrl: options.viewerUrl,\n scaleRegistration: options.scaleRegistration\n }\n }));\n}\n"],"mappings":"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","names":["axios"]}
package/dist/index.d.cts CHANGED
@@ -4,11 +4,25 @@ import { AxiosInstance } from 'axios';
4
4
  * @horae/passport-core — shared types
5
5
  */
6
6
  type AuthStrategy = "jwt" | "shopify" | "privy" | "custom";
7
+ type SDKMode = "heritage" | "scale";
8
+ interface ScaleRegistrationPayload {
9
+ serialNumber?: string;
10
+ email?: string;
11
+ manufacturerId?: string;
12
+ reference?: string;
13
+ claimCode?: string;
14
+ }
7
15
  interface PassportSDKConfig {
8
16
  /** Horae API base URL (e.g. https://v2.api.dev.horae.io/v1) */
9
17
  apiBase: string;
18
+ /** Optional brand identifier (compatibility for host integrators) */
19
+ brandId?: string;
20
+ /** Optional serial prefill (compatibility for host integrators) */
21
+ serial?: string;
22
+ /** SDK mode: heritage (wallet/privy) or scale (email registration + signed viewer URL) */
23
+ mode?: SDKMode;
10
24
  /** Auth strategy */
11
- authStrategy: AuthStrategy;
25
+ authStrategy?: AuthStrategy;
12
26
  /** For custom strategy: async token getter */
13
27
  getToken?: () => Promise<string | null>;
14
28
  /** For JWT strategy: initial token (optional; can set later via setToken) */
@@ -17,6 +31,10 @@ interface PassportSDKConfig {
17
31
  tokenStorageKey?: string | null;
18
32
  /** UI Host base URL where the bundle is served (default: https://app.horae.io) */
19
33
  uiHost?: string;
34
+ /** Scale mode: optional pre-signed public viewer URL generated server-side by brand */
35
+ viewerUrl?: string;
36
+ /** Scale mode: optional prefill values for registration flow */
37
+ scaleRegistration?: ScaleRegistrationPayload;
20
38
  }
21
39
  interface PassportListItem {
22
40
  id: string;
@@ -137,6 +155,15 @@ declare function createPassportApi(api: AxiosInstance): {
137
155
  serialNumber: string;
138
156
  email?: string;
139
157
  }): Promise<void>;
158
+ /** Scale owner registration (serial/email based, no wallet) */
159
+ registerScaleOwner(payload: ScaleRegistrationPayload): Promise<{
160
+ success: boolean;
161
+ tokenId: string;
162
+ ownerUrl?: string;
163
+ viewerUrl?: string;
164
+ }>;
165
+ /** Scale signed viewer (HMAC signature) */
166
+ getScaleViewer(tokenId: string, sig: string): Promise<PassportDetail>;
140
167
  /** Current user profile */
141
168
  getMe(): Promise<User>;
142
169
  /** Documents for a passport (owner gets file URLs) */
@@ -168,6 +195,12 @@ interface RenderOptions {
168
195
  uiHost?: string;
169
196
  /** Initial tab/view (e.g. "passports", "claim", "settings") */
170
197
  initialTab?: string;
198
+ /** SDK mode */
199
+ mode?: "heritage" | "scale";
200
+ /** Scale mode signed viewer URL */
201
+ viewerUrl?: string;
202
+ /** Scale mode registration prefill as JSON string */
203
+ scaleRegistration?: string;
171
204
  }
172
205
  interface RenderPassportOptions extends RenderOptions {
173
206
  /** The ID of the passport to show */
@@ -215,5 +248,13 @@ interface PassportSDK {
215
248
  * - authStrategy "shopify": use @horae/passport-shopify to get JWT from bridge, then use jwt or custom.
216
249
  */
217
250
  declare function createPassportSDK(config: PassportSDKConfig): PassportSDK;
251
+ declare const HoraeSDK: {
252
+ init(config: PassportSDKConfig): PassportSDK;
253
+ };
254
+ declare global {
255
+ interface Window {
256
+ HoraeSDK?: typeof HoraeSDK;
257
+ }
258
+ }
218
259
 
219
- export { type AuthStrategy, type AuthStrategyBase, type CreateClientOptions, type EventBus, type EventMap, type PassportDetail, type PassportListItem, type PassportSDK, type PassportSDKConfig, type RenderOptions, type RenderPassportOptions, type SDKEvent, type User, createClient, createClientWithAuth, createCustomStrategy, createEventBus, createJwtStrategy, createPassportApi, createPassportSDK, mountApp, renderPassport, renderPassportList };
260
+ export { type AuthStrategy, type AuthStrategyBase, type CreateClientOptions, type EventBus, type EventMap, HoraeSDK, type PassportDetail, type PassportListItem, type PassportSDK, type PassportSDKConfig, type RenderOptions, type RenderPassportOptions, type SDKEvent, type SDKMode, type ScaleRegistrationPayload, type User, createClient, createClientWithAuth, createCustomStrategy, createEventBus, createJwtStrategy, createPassportApi, createPassportSDK, mountApp, renderPassport, renderPassportList };
package/dist/index.d.ts CHANGED
@@ -4,11 +4,25 @@ import { AxiosInstance } from 'axios';
4
4
  * @horae/passport-core — shared types
5
5
  */
6
6
  type AuthStrategy = "jwt" | "shopify" | "privy" | "custom";
7
+ type SDKMode = "heritage" | "scale";
8
+ interface ScaleRegistrationPayload {
9
+ serialNumber?: string;
10
+ email?: string;
11
+ manufacturerId?: string;
12
+ reference?: string;
13
+ claimCode?: string;
14
+ }
7
15
  interface PassportSDKConfig {
8
16
  /** Horae API base URL (e.g. https://v2.api.dev.horae.io/v1) */
9
17
  apiBase: string;
18
+ /** Optional brand identifier (compatibility for host integrators) */
19
+ brandId?: string;
20
+ /** Optional serial prefill (compatibility for host integrators) */
21
+ serial?: string;
22
+ /** SDK mode: heritage (wallet/privy) or scale (email registration + signed viewer URL) */
23
+ mode?: SDKMode;
10
24
  /** Auth strategy */
11
- authStrategy: AuthStrategy;
25
+ authStrategy?: AuthStrategy;
12
26
  /** For custom strategy: async token getter */
13
27
  getToken?: () => Promise<string | null>;
14
28
  /** For JWT strategy: initial token (optional; can set later via setToken) */
@@ -17,6 +31,10 @@ interface PassportSDKConfig {
17
31
  tokenStorageKey?: string | null;
18
32
  /** UI Host base URL where the bundle is served (default: https://app.horae.io) */
19
33
  uiHost?: string;
34
+ /** Scale mode: optional pre-signed public viewer URL generated server-side by brand */
35
+ viewerUrl?: string;
36
+ /** Scale mode: optional prefill values for registration flow */
37
+ scaleRegistration?: ScaleRegistrationPayload;
20
38
  }
21
39
  interface PassportListItem {
22
40
  id: string;
@@ -137,6 +155,15 @@ declare function createPassportApi(api: AxiosInstance): {
137
155
  serialNumber: string;
138
156
  email?: string;
139
157
  }): Promise<void>;
158
+ /** Scale owner registration (serial/email based, no wallet) */
159
+ registerScaleOwner(payload: ScaleRegistrationPayload): Promise<{
160
+ success: boolean;
161
+ tokenId: string;
162
+ ownerUrl?: string;
163
+ viewerUrl?: string;
164
+ }>;
165
+ /** Scale signed viewer (HMAC signature) */
166
+ getScaleViewer(tokenId: string, sig: string): Promise<PassportDetail>;
140
167
  /** Current user profile */
141
168
  getMe(): Promise<User>;
142
169
  /** Documents for a passport (owner gets file URLs) */
@@ -168,6 +195,12 @@ interface RenderOptions {
168
195
  uiHost?: string;
169
196
  /** Initial tab/view (e.g. "passports", "claim", "settings") */
170
197
  initialTab?: string;
198
+ /** SDK mode */
199
+ mode?: "heritage" | "scale";
200
+ /** Scale mode signed viewer URL */
201
+ viewerUrl?: string;
202
+ /** Scale mode registration prefill as JSON string */
203
+ scaleRegistration?: string;
171
204
  }
172
205
  interface RenderPassportOptions extends RenderOptions {
173
206
  /** The ID of the passport to show */
@@ -215,5 +248,13 @@ interface PassportSDK {
215
248
  * - authStrategy "shopify": use @horae/passport-shopify to get JWT from bridge, then use jwt or custom.
216
249
  */
217
250
  declare function createPassportSDK(config: PassportSDKConfig): PassportSDK;
251
+ declare const HoraeSDK: {
252
+ init(config: PassportSDKConfig): PassportSDK;
253
+ };
254
+ declare global {
255
+ interface Window {
256
+ HoraeSDK?: typeof HoraeSDK;
257
+ }
258
+ }
218
259
 
219
- export { type AuthStrategy, type AuthStrategyBase, type CreateClientOptions, type EventBus, type EventMap, type PassportDetail, type PassportListItem, type PassportSDK, type PassportSDKConfig, type RenderOptions, type RenderPassportOptions, type SDKEvent, type User, createClient, createClientWithAuth, createCustomStrategy, createEventBus, createJwtStrategy, createPassportApi, createPassportSDK, mountApp, renderPassport, renderPassportList };
260
+ export { type AuthStrategy, type AuthStrategyBase, type CreateClientOptions, type EventBus, type EventMap, HoraeSDK, type PassportDetail, type PassportListItem, type PassportSDK, type PassportSDKConfig, type RenderOptions, type RenderPassportOptions, type SDKEvent, type SDKMode, type ScaleRegistrationPayload, type User, createClient, createClientWithAuth, createCustomStrategy, createEventBus, createJwtStrategy, createPassportApi, createPassportSDK, mountApp, renderPassport, renderPassportList };
package/dist/index.js CHANGED
@@ -117,6 +117,18 @@ function createPassportApi(api) {
117
117
  async claimShopifyPassport(data) {
118
118
  await api.post("/api/passport/shopify-claim", data);
119
119
  },
120
+ /** Scale owner registration (serial/email based, no wallet) */
121
+ async registerScaleOwner(payload) {
122
+ const res = await api.post("/api/passport/scale/register", payload);
123
+ return unwrapData(res);
124
+ },
125
+ /** Scale signed viewer (HMAC signature) */
126
+ async getScaleViewer(tokenId, sig) {
127
+ const res = await api.get(`/api/passport/scale/view/${tokenId}`, {
128
+ params: { sig }
129
+ });
130
+ return unwrapData(res);
131
+ },
120
132
  /** Current user profile */
121
133
  async getMe() {
122
134
  const res = await api.get("/users/me");
@@ -155,6 +167,15 @@ function prepareContainer(options, apiBase, token) {
155
167
  if (options.initialTab) {
156
168
  containerEl.dataset.initialTab = options.initialTab;
157
169
  }
170
+ if (options.mode) {
171
+ containerEl.dataset.horaeMode = options.mode;
172
+ }
173
+ if (options.viewerUrl) {
174
+ containerEl.dataset.horaeViewerUrl = options.viewerUrl;
175
+ }
176
+ if (options.scaleRegistration) {
177
+ containerEl.dataset.horaeScaleRegistration = options.scaleRegistration;
178
+ }
158
179
  if (token) {
159
180
  containerEl.dataset.horaeToken = token;
160
181
  }
@@ -184,7 +205,12 @@ async function mountApp(options, apiBase, token) {
184
205
  const host = options.uiHost || "https://app.horae.io";
185
206
  await loadUIBundle(host);
186
207
  window.dispatchEvent(new CustomEvent("horae:sdk:mount", {
187
- detail: { container: options.container }
208
+ detail: {
209
+ container: options.container,
210
+ mode: options.mode,
211
+ viewerUrl: options.viewerUrl,
212
+ scaleRegistration: options.scaleRegistration
213
+ }
188
214
  }));
189
215
  }
190
216
  async function renderPassportList(options, apiBase, token) {
@@ -199,54 +225,108 @@ async function renderPassport(options, apiBase, token) {
199
225
  const host = options.uiHost || "https://app.horae.io";
200
226
  await loadUIBundle(host);
201
227
  window.dispatchEvent(new CustomEvent("horae:sdk:mount", {
202
- detail: { container: options.container, passportId: options.passportId }
228
+ detail: {
229
+ container: options.container,
230
+ passportId: options.passportId,
231
+ mode: options.mode,
232
+ viewerUrl: options.viewerUrl,
233
+ scaleRegistration: options.scaleRegistration
234
+ }
203
235
  }));
204
236
  }
205
237
 
206
238
  // src/index.ts
207
239
  function createPassportSDK(config) {
240
+ const mode = config.mode ?? "heritage";
241
+ const authStrategy = config.authStrategy ?? (mode === "scale" ? "custom" : "jwt");
208
242
  const events = createEventBus();
209
243
  let auth;
210
- switch (config.authStrategy) {
211
- case "jwt": {
212
- const jwt = createJwtStrategy({
213
- token: config.token ?? void 0,
214
- storageKey: config.tokenStorageKey ?? void 0
215
- });
216
- auth = jwt;
217
- break;
218
- }
219
- case "custom": {
220
- if (!config.getToken) throw new Error("PassportSDK: getToken required for authStrategy 'custom'");
221
- auth = createCustomStrategy(config.getToken);
222
- break;
244
+ if (mode === "scale") {
245
+ auth = createCustomStrategy(async () => config.token ?? null);
246
+ } else {
247
+ switch (authStrategy) {
248
+ case "jwt": {
249
+ const jwt = createJwtStrategy({
250
+ token: config.token ?? void 0,
251
+ storageKey: config.tokenStorageKey ?? void 0
252
+ });
253
+ auth = jwt;
254
+ break;
255
+ }
256
+ case "custom": {
257
+ if (!config.getToken) throw new Error("PassportSDK: getToken required for authStrategy 'custom'");
258
+ auth = createCustomStrategy(config.getToken);
259
+ break;
260
+ }
261
+ case "shopify":
262
+ auth = createJwtStrategy({
263
+ token: config.token ?? void 0,
264
+ storageKey: config.tokenStorageKey ?? "shopify_access_token"
265
+ });
266
+ break;
267
+ case "privy":
268
+ if (!config.getToken) throw new Error("PassportSDK: getToken required for authStrategy 'privy' (pass Privy getAccessToken)");
269
+ auth = createCustomStrategy(config.getToken);
270
+ break;
271
+ default:
272
+ throw new Error(`PassportSDK: unknown authStrategy ${String(authStrategy)}`);
223
273
  }
224
- case "shopify":
225
- auth = createJwtStrategy({
226
- token: config.token ?? void 0,
227
- storageKey: config.tokenStorageKey ?? "shopify_access_token"
228
- });
229
- break;
230
- case "privy":
231
- if (!config.getToken) throw new Error("PassportSDK: getToken required for authStrategy 'privy' (pass Privy getAccessToken)");
232
- auth = createCustomStrategy(config.getToken);
233
- break;
234
- default:
235
- throw new Error(`PassportSDK: unknown authStrategy ${String(config.authStrategy)}`);
236
274
  }
237
275
  const client = createClient({ apiBase: config.apiBase, getToken: () => auth.getToken() });
238
276
  const api = createPassportApi(client);
277
+ const fallbackScaleRegistration = config.serial || config.brandId ? {
278
+ serialNumber: config.serial,
279
+ manufacturerId: config.brandId
280
+ } : void 0;
281
+ const scaleRegistrationPayload = config.scaleRegistration ?? fallbackScaleRegistration;
282
+ const scaleRegistration = scaleRegistrationPayload ? JSON.stringify(scaleRegistrationPayload) : void 0;
239
283
  return {
240
284
  api,
241
285
  events,
242
286
  auth,
243
- config: Object.freeze({ ...config }),
244
- mount: (options) => mountApp(options, config.apiBase, config.token || null),
245
- renderPassportList: (options) => renderPassportList(options, config.apiBase, config.token || null),
246
- renderPassport: (options) => renderPassport(options, config.apiBase, config.token || null)
287
+ config: Object.freeze({ ...config, mode }),
288
+ mount: (options) => mountApp(
289
+ {
290
+ ...options,
291
+ mode,
292
+ viewerUrl: config.viewerUrl,
293
+ scaleRegistration
294
+ },
295
+ config.apiBase,
296
+ config.token || null
297
+ ),
298
+ renderPassportList: (options) => renderPassportList(
299
+ {
300
+ ...options,
301
+ mode,
302
+ viewerUrl: config.viewerUrl,
303
+ scaleRegistration
304
+ },
305
+ config.apiBase,
306
+ config.token || null
307
+ ),
308
+ renderPassport: (options) => renderPassport(
309
+ {
310
+ ...options,
311
+ mode,
312
+ viewerUrl: config.viewerUrl,
313
+ scaleRegistration
314
+ },
315
+ config.apiBase,
316
+ config.token || null
317
+ )
247
318
  };
248
319
  }
320
+ var HoraeSDK = {
321
+ init(config) {
322
+ return createPassportSDK(config);
323
+ }
324
+ };
325
+ if (typeof window !== "undefined") {
326
+ window.HoraeSDK = HoraeSDK;
327
+ }
249
328
  export {
329
+ HoraeSDK,
250
330
  createClient,
251
331
  createClientWithAuth,
252
332
  createCustomStrategy,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/events.ts","../src/auth/strategies/jwt.ts","../src/auth/strategies/custom.ts","../src/client.ts","../src/api.ts","../src/ui.ts","../src/index.ts"],"sourcesContent":["/**\n * @horae/passport-core — event emitter for auth and passport events\n */\n\nexport type SDKEvent =\n | \"auth:ready\"\n | \"auth:error\"\n | \"passport:claimed\"\n | \"passport:loaded\"\n | \"passport:list:loaded\"\n | \"token:expired\";\n\nexport type EventMap = {\n \"auth:ready\": void;\n \"auth:error\": { message: string; code?: string };\n \"passport:claimed\": { tokenId: string };\n \"passport:loaded\": { tokenId: string };\n \"passport:list:loaded\": { count: number };\n \"token:expired\": void;\n};\n\ntype Listener<T> = (payload: T) => void;\n\nexport function createEventBus() {\n const listeners = new Map<SDKEvent, Set<Listener<unknown>>>();\n\n function on<E extends SDKEvent>(event: E, fn: Listener<EventMap[E]>) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(fn as Listener<unknown>);\n return () => listeners.get(event)?.delete(fn as Listener<unknown>);\n }\n\n function emit<E extends SDKEvent>(event: E, payload?: EventMap[E]) {\n listeners.get(event)?.forEach((fn) => (fn as Listener<EventMap[E]>)(payload as EventMap[E]));\n }\n\n return { on, emit };\n}\n\nexport type EventBus = ReturnType<typeof createEventBus>;\n","/**\n * JWT strategy — token from config or setToken; optional localStorage persistence\n */\n\nimport type { AuthStrategyBase } from \"../types.js\";\n\nexport interface JwtStrategyOptions {\n /** Initial token */\n token?: string | null;\n /** localStorage key for persistence (omit for in-memory only) */\n storageKey?: string | null;\n}\n\nexport function createJwtStrategy(options: JwtStrategyOptions = {}): AuthStrategyBase {\n let token: string | null = options.token ?? null;\n const storageKey = options.storageKey ?? null;\n\n const storage = typeof window !== \"undefined\" ? window.localStorage : undefined;\n if (storage && storageKey) {\n try {\n const stored = storage.getItem(storageKey);\n if (stored) token = stored;\n } catch {\n // ignore\n }\n }\n\n return {\n async getToken() {\n return token;\n },\n setToken(next: string | null) {\n token = next;\n if (storage && storageKey) {\n try {\n if (next) storage.setItem(storageKey, next);\n else storage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }\n },\n clearToken() {\n token = null;\n if (storage && storageKey) {\n try {\n storage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }\n },\n };\n}\n","/**\n * Custom strategy — caller supplies getToken (e.g. from backend or Privy)\n */\n\nimport type { AuthStrategyBase } from \"../types.js\";\n\nexport function createCustomStrategy(\n getToken: () => Promise<string | null>,\n): AuthStrategyBase {\n return { getToken };\n}\n","/**\n * Horae API client — axios instance with Bearer token from auth strategy\n */\n\nimport axios, { type AxiosInstance } from \"axios\";\nimport type { AuthStrategyBase } from \"./auth/index.js\";\n\nexport interface CreateClientOptions {\n apiBase: string;\n getToken: () => Promise<string | null>;\n}\n\nexport function createClient(options: CreateClientOptions): AxiosInstance {\n const { apiBase, getToken } = options;\n const client = axios.create({\n baseURL: apiBase.replace(/\\/v1\\/?$/, \"\") + \"/v1\",\n });\n\n client.interceptors.request.use(async (config) => {\n const token = await getToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n config.headers[\"ngrok-skip-browser-warning\"] = \"true\";\n return config;\n });\n\n return client;\n}\n\nexport function createClientWithAuth(auth: AuthStrategyBase, apiBase: string): AxiosInstance {\n return createClient({\n apiBase,\n getToken: () => auth.getToken(),\n });\n}\n","/**\n * Horae Passport API — list, single, claim, user, documents\n * Mirrors passport-web shared/api/api.service.ts (token-based auth)\n */\n\nimport type { AxiosInstance } from \"axios\";\nimport type { PassportListItem, PassportDetail, User } from \"./types.js\";\n\nfunction unwrapItems<T>(response: { data?: unknown }): T[] {\n const data = response.data as { data?: { items?: T[] }; items?: T[] } | T[] | undefined;\n if (Array.isArray(data)) return data;\n const inner = data && typeof data === \"object\" && \"data\" in data ? (data as { data?: { items?: T[] } }).data : data;\n const items = (inner && typeof inner === \"object\" && \"items\" in inner\n ? (inner as { items?: T[] }).items\n : Array.isArray(inner)\n ? inner\n : []) as T[];\n return items ?? [];\n}\n\nfunction unwrapData<T>(response: { data?: unknown }): T {\n const data = response.data as { data?: T } | T;\n return (data && typeof data === \"object\" && \"data\" in data ? (data as { data: T }).data : data) as T;\n}\n\nexport function createPassportApi(api: AxiosInstance) {\n return {\n /** List passports claimed by current user */\n async getMyClaimedPassports(): Promise<PassportListItem[]> {\n const res = await api.get(\"/api/passport/claimed\");\n return unwrapItems<PassportListItem>(res) as PassportListItem[];\n },\n\n /** List passports by owner wallet (e.g. Shopify) */\n async getPassportsByOwner(ownerWallet: string): Promise<PassportListItem[]> {\n const res = await api.get(\"/api/passport/claimed\", { params: { owner: ownerWallet } });\n return unwrapItems<PassportListItem>(res) as PassportListItem[];\n },\n\n /** Single passport (authenticated) */\n async getPassport(tokenId: string, isAuthenticated = true): Promise<PassportDetail> {\n const path = isAuthenticated ? `/api/passport/${tokenId}` : `/api/passport/public/${tokenId}`;\n const res = await api.get(path);\n return unwrapData<PassportDetail>(res);\n },\n\n /** Claim passport */\n async claimPassport(data: { tokenId: string; toAddress: string; claimKey: string }) {\n await api.post(\"/api/passport/claim\", data);\n },\n\n /** Shopify claim (serialNumber + optional email) */\n async claimShopifyPassport(data: { serialNumber: string; email?: string }) {\n await api.post(\"/api/passport/shopify-claim\", data);\n },\n\n /** Current user profile */\n async getMe(): Promise<User> {\n const res = await api.get(\"/users/me\");\n const raw = unwrapData<unknown>(res);\n const doc = raw && typeof raw === \"object\" && \"_doc\" in raw ? (raw as { _doc: User })._doc : raw;\n return doc as User;\n },\n\n /** Documents for a passport (owner gets file URLs) */\n async getDocuments(tokenId: string): Promise<{ url?: string; name?: string; [k: string]: unknown }[]> {\n const res = await api.get(`/api/passport/${tokenId}/documents`);\n const responseData = (res.data as { data?: unknown })?.data ?? res.data;\n if (responseData && typeof responseData === \"object\" && \"data\" in responseData && Array.isArray((responseData as { data: unknown[] }).data))\n return (responseData as { data: unknown[] }).data as { url?: string; name?: string; [k: string]: unknown }[];\n if (Array.isArray(responseData)) return responseData as { url?: string; name?: string; [k: string]: unknown }[];\n return [];\n },\n\n /** Transfer passport to user by email */\n async transferPassportToUser(data: { tokenId: string; recipientEmail: string }) {\n await api.post(\"/api/passport/transfer-to-user\", data);\n },\n\n /** Set stolen status */\n async setStolenStatus(data: { tokenId: string; isStolen: boolean }) {\n await api.post(\"/api/passport/set-stolen\", data);\n },\n };\n}\n","/**\n * UI Renderer for @horae/passport-core\n * Dynamically injects the pre-built React SDK bundle to render the UI on the host page.\n */\n\nexport interface RenderOptions {\n /** CSS selector of the container element (e.g. \"#passport-app\") */\n container: string;\n /** UI Host base URL where the bundle is served (default: https://app.horae.io) */\n uiHost?: string;\n /** Initial tab/view (e.g. \"passports\", \"claim\", \"settings\") */\n initialTab?: string;\n}\n\nexport interface RenderPassportOptions extends RenderOptions {\n /** The ID of the passport to show */\n passportId: string;\n}\n\n/**\n * Configure the container with data attributes so the UI bundle can read them upon mounting.\n */\nfunction prepareContainer(options: RenderOptions, apiBase: string, token: string | null) {\n const containerEl = document.querySelector(options.container);\n if (!containerEl) {\n throw new Error(`PassportSDK: container element '${options.container}' not found.`);\n }\n\n // Set necessary data attributes for the UI bundle (similar to Shopify embed contract)\n if (containerEl instanceof HTMLElement) {\n containerEl.dataset.horaeApiBase = apiBase;\n if (options.initialTab) {\n containerEl.dataset.initialTab = options.initialTab;\n }\n\n // Inject the token (the UI bundle will look for this or use its own mechanism)\n if (token) {\n containerEl.dataset.horaeToken = token;\n }\n\n // Add a signature class/id to ensure the embed root is identifiable\n containerEl.classList.add(\"horae-sdk-root\");\n\n // Allow the bundle to easily find its mount point if it uses querySelector internally\n // (We also pass the container selector directly to the mount event later if needed)\n containerEl.dataset.containerSelector = options.container;\n }\n\n return containerEl;\n}\n\n/**\n * Inject the script tag for the UI bundle if it hasn't been injected yet.\n */\nfunction loadUIBundle(uiHost: string): Promise<void> {\n const SCRIPT_ID = \"horae-passport-sdk-ui\";\n\n return new Promise((resolve, reject) => {\n if (document.getElementById(SCRIPT_ID)) {\n // Script already added\n resolve();\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = SCRIPT_ID;\n script.type = \"module\";\n // Target the newly created sdk-embed entrypoint\n script.src = `${uiHost.replace(/\\/$/, '')}/sdk-embed.js`;\n\n script.onload = () => resolve();\n script.onerror = () => reject(new Error(`PassportSDK: Failed to load UI bundle from ${script.src}`));\n\n document.head.appendChild(script);\n });\n}\n\n/**\n * Render the generic SDK App\n */\nexport async function mountApp(\n options: RenderOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n prepareContainer(options, apiBase, token);\n\n const host = options.uiHost || \"https://app.horae.io\";\n await loadUIBundle(host);\n\n // Dispatch a custom event in case the bundle is already loaded and listening for dynamic mounts\n window.dispatchEvent(new CustomEvent(\"horae:sdk:mount\", {\n detail: { container: options.container }\n }));\n}\n\n/**\n * Render specifically the Passport List (maps to \"passports\" tab/view)\n */\nexport async function renderPassportList(\n options: RenderOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n return mountApp({ ...options, initialTab: \"passports\" }, apiBase, token);\n}\n\n/**\n * Render specifically a Single Passport (maps to a specific detail view layout)\n */\nexport async function renderPassport(\n options: RenderPassportOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n const containerEl = prepareContainer(options, apiBase, token);\n\n if (containerEl instanceof HTMLElement) {\n containerEl.dataset.passportId = options.passportId;\n // Set initialTab to \"detail\" or a specific flag the UI recognizes\n containerEl.dataset.initialTab = \"detail\";\n }\n\n const host = options.uiHost || \"https://app.horae.io\";\n await loadUIBundle(host);\n\n window.dispatchEvent(new CustomEvent(\"horae:sdk:mount\", {\n detail: { container: options.container, passportId: options.passportId }\n }));\n}\n","/**\n * @horae/passport-core\n * Reusable Passport SDK — auth strategies, Horae API client, events.\n * Token-based auth only; no cross-domain cookies.\n */\n\nexport type { PassportSDKConfig, AuthStrategy, PassportListItem, PassportDetail, User } from \"./types.js\";\nexport { createEventBus } from \"./events.js\";\nexport type { SDKEvent, EventMap, EventBus } from \"./events.js\";\nexport { createJwtStrategy, createCustomStrategy } from \"./auth/index.js\";\nexport type { AuthStrategyBase } from \"./auth/index.js\";\nexport { createClient, createClientWithAuth } from \"./client.js\";\nexport type { CreateClientOptions } from \"./client.js\";\nexport { createPassportApi } from \"./api.js\";\nexport * from \"./ui.js\";\n\nimport type { PassportSDKConfig } from \"./types.js\";\nimport { createEventBus } from \"./events.js\";\nimport { createJwtStrategy } from \"./auth/strategies/jwt.js\";\nimport { createCustomStrategy } from \"./auth/strategies/custom.js\";\nimport { createClient } from \"./client.js\";\nimport { createPassportApi } from \"./api.js\";\nimport type { AuthStrategyBase } from \"./auth/index.js\";\nimport { mountApp, renderPassportList, renderPassport } from \"./ui.js\";\nimport type { RenderOptions, RenderPassportOptions } from \"./ui.js\";\n\nexport interface PassportSDK {\n /** Horae API client (axios) */\n readonly api: ReturnType<typeof createPassportApi>;\n /** Event bus for auth:ready, auth:error, passport:claimed, etc. */\n readonly events: ReturnType<typeof createEventBus>;\n /** Auth strategy instance (for setToken/clearToken when available) */\n readonly auth: AuthStrategyBase;\n /** Config */\n readonly config: Readonly<PassportSDKConfig>;\n /** Mount the generic SDK App in headless mode */\n mount(options: RenderOptions): Promise<void>;\n /** Render the Passport List view */\n renderPassportList(options: RenderOptions): Promise<void>;\n /** Render a Single Passport Detail view */\n renderPassport(options: RenderPassportOptions): Promise<void>;\n}\n\n/**\n * Create the Passport SDK instance.\n * - authStrategy \"jwt\": pass token in config or call setToken on auth after getting JWT from your backend.\n * - authStrategy \"custom\": pass getToken in config.\n * - authStrategy \"shopify\": use @horae/passport-shopify to get JWT from bridge, then use jwt or custom.\n */\nexport function createPassportSDK(config: PassportSDKConfig): PassportSDK {\n const events = createEventBus();\n let auth: AuthStrategyBase;\n\n switch (config.authStrategy) {\n case \"jwt\": {\n const jwt = createJwtStrategy({\n token: config.token ?? undefined,\n storageKey: config.tokenStorageKey ?? undefined,\n });\n auth = jwt;\n break;\n }\n case \"custom\": {\n if (!config.getToken) throw new Error(\"PassportSDK: getToken required for authStrategy 'custom'\");\n auth = createCustomStrategy(config.getToken);\n break;\n }\n case \"shopify\":\n // Shopify: use JWT strategy; token is set by @horae/passport-shopify bridge\n auth = createJwtStrategy({\n token: config.token ?? undefined,\n storageKey: config.tokenStorageKey ?? \"shopify_access_token\",\n });\n break;\n case \"privy\":\n // Privy: use custom strategy with getToken from host (e.g. getAccessToken from @privy-io/react-auth)\n if (!config.getToken) throw new Error(\"PassportSDK: getToken required for authStrategy 'privy' (pass Privy getAccessToken)\");\n auth = createCustomStrategy(config.getToken);\n break;\n default:\n throw new Error(`PassportSDK: unknown authStrategy ${String((config as { authStrategy?: string }).authStrategy)}`);\n }\n\n const client = createClient({ apiBase: config.apiBase, getToken: () => auth.getToken() });\n const api = createPassportApi(client);\n\n return {\n api,\n events,\n auth,\n config: Object.freeze({ ...config }),\n mount: (options) => mountApp(options, config.apiBase, config.token || null),\n renderPassportList: (options) => renderPassportList(options, config.apiBase, config.token || null),\n renderPassport: (options) => renderPassport(options, config.apiBase, config.token || null),\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/events.ts","../src/auth/strategies/jwt.ts","../src/auth/strategies/custom.ts","../src/client.ts","../src/api.ts","../src/ui.ts","../src/index.ts"],"sourcesContent":["/**\n * @horae/passport-core — event emitter for auth and passport events\n */\n\nexport type SDKEvent =\n | \"auth:ready\"\n | \"auth:error\"\n | \"passport:claimed\"\n | \"passport:loaded\"\n | \"passport:list:loaded\"\n | \"token:expired\";\n\nexport type EventMap = {\n \"auth:ready\": void;\n \"auth:error\": { message: string; code?: string };\n \"passport:claimed\": { tokenId: string };\n \"passport:loaded\": { tokenId: string };\n \"passport:list:loaded\": { count: number };\n \"token:expired\": void;\n};\n\ntype Listener<T> = (payload: T) => void;\n\nexport function createEventBus() {\n const listeners = new Map<SDKEvent, Set<Listener<unknown>>>();\n\n function on<E extends SDKEvent>(event: E, fn: Listener<EventMap[E]>) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(fn as Listener<unknown>);\n return () => listeners.get(event)?.delete(fn as Listener<unknown>);\n }\n\n function emit<E extends SDKEvent>(event: E, payload?: EventMap[E]) {\n listeners.get(event)?.forEach((fn) => (fn as Listener<EventMap[E]>)(payload as EventMap[E]));\n }\n\n return { on, emit };\n}\n\nexport type EventBus = ReturnType<typeof createEventBus>;\n","/**\n * JWT strategy — token from config or setToken; optional localStorage persistence\n */\n\nimport type { AuthStrategyBase } from \"../types.js\";\n\nexport interface JwtStrategyOptions {\n /** Initial token */\n token?: string | null;\n /** localStorage key for persistence (omit for in-memory only) */\n storageKey?: string | null;\n}\n\nexport function createJwtStrategy(options: JwtStrategyOptions = {}): AuthStrategyBase {\n let token: string | null = options.token ?? null;\n const storageKey = options.storageKey ?? null;\n\n const storage = typeof window !== \"undefined\" ? window.localStorage : undefined;\n if (storage && storageKey) {\n try {\n const stored = storage.getItem(storageKey);\n if (stored) token = stored;\n } catch {\n // ignore\n }\n }\n\n return {\n async getToken() {\n return token;\n },\n setToken(next: string | null) {\n token = next;\n if (storage && storageKey) {\n try {\n if (next) storage.setItem(storageKey, next);\n else storage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }\n },\n clearToken() {\n token = null;\n if (storage && storageKey) {\n try {\n storage.removeItem(storageKey);\n } catch {\n // ignore\n }\n }\n },\n };\n}\n","/**\n * Custom strategy — caller supplies getToken (e.g. from backend or Privy)\n */\n\nimport type { AuthStrategyBase } from \"../types.js\";\n\nexport function createCustomStrategy(\n getToken: () => Promise<string | null>,\n): AuthStrategyBase {\n return { getToken };\n}\n","/**\n * Horae API client — axios instance with Bearer token from auth strategy\n */\n\nimport axios, { type AxiosInstance } from \"axios\";\nimport type { AuthStrategyBase } from \"./auth/index.js\";\n\nexport interface CreateClientOptions {\n apiBase: string;\n getToken: () => Promise<string | null>;\n}\n\nexport function createClient(options: CreateClientOptions): AxiosInstance {\n const { apiBase, getToken } = options;\n const client = axios.create({\n baseURL: apiBase.replace(/\\/v1\\/?$/, \"\") + \"/v1\",\n });\n\n client.interceptors.request.use(async (config) => {\n const token = await getToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n config.headers[\"ngrok-skip-browser-warning\"] = \"true\";\n return config;\n });\n\n return client;\n}\n\nexport function createClientWithAuth(auth: AuthStrategyBase, apiBase: string): AxiosInstance {\n return createClient({\n apiBase,\n getToken: () => auth.getToken(),\n });\n}\n","/**\n * Horae Passport API — list, single, claim, user, documents\n * Mirrors passport-web shared/api/api.service.ts (token-based auth)\n */\n\nimport type { AxiosInstance } from \"axios\";\nimport type {\n PassportListItem,\n PassportDetail,\n ScaleRegistrationPayload,\n User,\n} from \"./types.js\";\n\nfunction unwrapItems<T>(response: { data?: unknown }): T[] {\n const data = response.data as { data?: { items?: T[] }; items?: T[] } | T[] | undefined;\n if (Array.isArray(data)) return data;\n const inner = data && typeof data === \"object\" && \"data\" in data ? (data as { data?: { items?: T[] } }).data : data;\n const items = (inner && typeof inner === \"object\" && \"items\" in inner\n ? (inner as { items?: T[] }).items\n : Array.isArray(inner)\n ? inner\n : []) as T[];\n return items ?? [];\n}\n\nfunction unwrapData<T>(response: { data?: unknown }): T {\n const data = response.data as { data?: T } | T;\n return (data && typeof data === \"object\" && \"data\" in data ? (data as { data: T }).data : data) as T;\n}\n\nexport function createPassportApi(api: AxiosInstance) {\n return {\n /** List passports claimed by current user */\n async getMyClaimedPassports(): Promise<PassportListItem[]> {\n const res = await api.get(\"/api/passport/claimed\");\n return unwrapItems<PassportListItem>(res) as PassportListItem[];\n },\n\n /** List passports by owner wallet (e.g. Shopify) */\n async getPassportsByOwner(ownerWallet: string): Promise<PassportListItem[]> {\n const res = await api.get(\"/api/passport/claimed\", { params: { owner: ownerWallet } });\n return unwrapItems<PassportListItem>(res) as PassportListItem[];\n },\n\n /** Single passport (authenticated) */\n async getPassport(tokenId: string, isAuthenticated = true): Promise<PassportDetail> {\n const path = isAuthenticated ? `/api/passport/${tokenId}` : `/api/passport/public/${tokenId}`;\n const res = await api.get(path);\n return unwrapData<PassportDetail>(res);\n },\n\n /** Claim passport */\n async claimPassport(data: { tokenId: string; toAddress: string; claimKey: string }) {\n await api.post(\"/api/passport/claim\", data);\n },\n\n /** Shopify claim (serialNumber + optional email) */\n async claimShopifyPassport(data: { serialNumber: string; email?: string }) {\n await api.post(\"/api/passport/shopify-claim\", data);\n },\n\n /** Scale owner registration (serial/email based, no wallet) */\n async registerScaleOwner(payload: ScaleRegistrationPayload): Promise<{\n success: boolean;\n tokenId: string;\n ownerUrl?: string;\n viewerUrl?: string;\n }> {\n const res = await api.post(\"/api/passport/scale/register\", payload);\n return unwrapData<{\n success: boolean;\n tokenId: string;\n ownerUrl?: string;\n viewerUrl?: string;\n }>(res);\n },\n\n /** Scale signed viewer (HMAC signature) */\n async getScaleViewer(tokenId: string, sig: string): Promise<PassportDetail> {\n const res = await api.get(`/api/passport/scale/view/${tokenId}`, {\n params: { sig },\n });\n return unwrapData<PassportDetail>(res);\n },\n\n /** Current user profile */\n async getMe(): Promise<User> {\n const res = await api.get(\"/users/me\");\n const raw = unwrapData<unknown>(res);\n const doc = raw && typeof raw === \"object\" && \"_doc\" in raw ? (raw as { _doc: User })._doc : raw;\n return doc as User;\n },\n\n /** Documents for a passport (owner gets file URLs) */\n async getDocuments(tokenId: string): Promise<{ url?: string; name?: string; [k: string]: unknown }[]> {\n const res = await api.get(`/api/passport/${tokenId}/documents`);\n const responseData = (res.data as { data?: unknown })?.data ?? res.data;\n if (responseData && typeof responseData === \"object\" && \"data\" in responseData && Array.isArray((responseData as { data: unknown[] }).data))\n return (responseData as { data: unknown[] }).data as { url?: string; name?: string; [k: string]: unknown }[];\n if (Array.isArray(responseData)) return responseData as { url?: string; name?: string; [k: string]: unknown }[];\n return [];\n },\n\n /** Transfer passport to user by email */\n async transferPassportToUser(data: { tokenId: string; recipientEmail: string }) {\n await api.post(\"/api/passport/transfer-to-user\", data);\n },\n\n /** Set stolen status */\n async setStolenStatus(data: { tokenId: string; isStolen: boolean }) {\n await api.post(\"/api/passport/set-stolen\", data);\n },\n };\n}\n","/**\n * UI Renderer for @horae/passport-core\n * Dynamically injects the pre-built React SDK bundle to render the UI on the host page.\n */\n\nexport interface RenderOptions {\n /** CSS selector of the container element (e.g. \"#passport-app\") */\n container: string;\n /** UI Host base URL where the bundle is served (default: https://app.horae.io) */\n uiHost?: string;\n /** Initial tab/view (e.g. \"passports\", \"claim\", \"settings\") */\n initialTab?: string;\n /** SDK mode */\n mode?: \"heritage\" | \"scale\";\n /** Scale mode signed viewer URL */\n viewerUrl?: string;\n /** Scale mode registration prefill as JSON string */\n scaleRegistration?: string;\n}\n\nexport interface RenderPassportOptions extends RenderOptions {\n /** The ID of the passport to show */\n passportId: string;\n}\n\n/**\n * Configure the container with data attributes so the UI bundle can read them upon mounting.\n */\nfunction prepareContainer(options: RenderOptions, apiBase: string, token: string | null) {\n const containerEl = document.querySelector(options.container);\n if (!containerEl) {\n throw new Error(`PassportSDK: container element '${options.container}' not found.`);\n }\n\n // Set necessary data attributes for the UI bundle (similar to Shopify embed contract)\n if (containerEl instanceof HTMLElement) {\n containerEl.dataset.horaeApiBase = apiBase;\n if (options.initialTab) {\n containerEl.dataset.initialTab = options.initialTab;\n }\n if (options.mode) {\n containerEl.dataset.horaeMode = options.mode;\n }\n if (options.viewerUrl) {\n containerEl.dataset.horaeViewerUrl = options.viewerUrl;\n }\n if (options.scaleRegistration) {\n containerEl.dataset.horaeScaleRegistration = options.scaleRegistration;\n }\n\n // Inject the token (the UI bundle will look for this or use its own mechanism)\n if (token) {\n containerEl.dataset.horaeToken = token;\n }\n\n // Add a signature class/id to ensure the embed root is identifiable\n containerEl.classList.add(\"horae-sdk-root\");\n\n // Allow the bundle to easily find its mount point if it uses querySelector internally\n // (We also pass the container selector directly to the mount event later if needed)\n containerEl.dataset.containerSelector = options.container;\n }\n\n return containerEl;\n}\n\n/**\n * Inject the script tag for the UI bundle if it hasn't been injected yet.\n */\nfunction loadUIBundle(uiHost: string): Promise<void> {\n const SCRIPT_ID = \"horae-passport-sdk-ui\";\n\n return new Promise((resolve, reject) => {\n if (document.getElementById(SCRIPT_ID)) {\n // Script already added\n resolve();\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = SCRIPT_ID;\n script.type = \"module\";\n // Target the newly created sdk-embed entrypoint\n script.src = `${uiHost.replace(/\\/$/, '')}/sdk-embed.js`;\n\n script.onload = () => resolve();\n script.onerror = () => reject(new Error(`PassportSDK: Failed to load UI bundle from ${script.src}`));\n\n document.head.appendChild(script);\n });\n}\n\n/**\n * Render the generic SDK App\n */\nexport async function mountApp(\n options: RenderOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n prepareContainer(options, apiBase, token);\n\n const host = options.uiHost || \"https://app.horae.io\";\n await loadUIBundle(host);\n\n // Dispatch a custom event in case the bundle is already loaded and listening for dynamic mounts\n window.dispatchEvent(new CustomEvent(\"horae:sdk:mount\", {\n detail: {\n container: options.container,\n mode: options.mode,\n viewerUrl: options.viewerUrl,\n scaleRegistration: options.scaleRegistration\n }\n }));\n}\n\n/**\n * Render specifically the Passport List (maps to \"passports\" tab/view)\n */\nexport async function renderPassportList(\n options: RenderOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n return mountApp({ ...options, initialTab: \"passports\" }, apiBase, token);\n}\n\n/**\n * Render specifically a Single Passport (maps to a specific detail view layout)\n */\nexport async function renderPassport(\n options: RenderPassportOptions,\n apiBase: string,\n token: string | null\n): Promise<void> {\n const containerEl = prepareContainer(options, apiBase, token);\n\n if (containerEl instanceof HTMLElement) {\n containerEl.dataset.passportId = options.passportId;\n // Set initialTab to \"detail\" or a specific flag the UI recognizes\n containerEl.dataset.initialTab = \"detail\";\n }\n\n const host = options.uiHost || \"https://app.horae.io\";\n await loadUIBundle(host);\n\n window.dispatchEvent(new CustomEvent(\"horae:sdk:mount\", {\n detail: {\n container: options.container,\n passportId: options.passportId,\n mode: options.mode,\n viewerUrl: options.viewerUrl,\n scaleRegistration: options.scaleRegistration\n }\n }));\n}\n","/**\n * @horae/passport-core\n * Reusable Passport SDK — auth strategies, Horae API client, events.\n * Token-based auth only; no cross-domain cookies.\n */\n\nexport type {\n PassportSDKConfig,\n AuthStrategy,\n PassportListItem,\n PassportDetail,\n ScaleRegistrationPayload,\n SDKMode,\n User,\n} from \"./types.js\";\nexport { createEventBus } from \"./events.js\";\nexport type { SDKEvent, EventMap, EventBus } from \"./events.js\";\nexport { createJwtStrategy, createCustomStrategy } from \"./auth/index.js\";\nexport type { AuthStrategyBase } from \"./auth/index.js\";\nexport { createClient, createClientWithAuth } from \"./client.js\";\nexport type { CreateClientOptions } from \"./client.js\";\nexport { createPassportApi } from \"./api.js\";\nexport * from \"./ui.js\";\n\nimport type { PassportSDKConfig } from \"./types.js\";\nimport { createEventBus } from \"./events.js\";\nimport { createJwtStrategy } from \"./auth/strategies/jwt.js\";\nimport { createCustomStrategy } from \"./auth/strategies/custom.js\";\nimport { createClient } from \"./client.js\";\nimport { createPassportApi } from \"./api.js\";\nimport type { AuthStrategyBase } from \"./auth/index.js\";\nimport { mountApp, renderPassportList, renderPassport } from \"./ui.js\";\nimport type { RenderOptions, RenderPassportOptions } from \"./ui.js\";\n\nexport interface PassportSDK {\n /** Horae API client (axios) */\n readonly api: ReturnType<typeof createPassportApi>;\n /** Event bus for auth:ready, auth:error, passport:claimed, etc. */\n readonly events: ReturnType<typeof createEventBus>;\n /** Auth strategy instance (for setToken/clearToken when available) */\n readonly auth: AuthStrategyBase;\n /** Config */\n readonly config: Readonly<PassportSDKConfig>;\n /** Mount the generic SDK App in headless mode */\n mount(options: RenderOptions): Promise<void>;\n /** Render the Passport List view */\n renderPassportList(options: RenderOptions): Promise<void>;\n /** Render a Single Passport Detail view */\n renderPassport(options: RenderPassportOptions): Promise<void>;\n}\n\n/**\n * Create the Passport SDK instance.\n * - authStrategy \"jwt\": pass token in config or call setToken on auth after getting JWT from your backend.\n * - authStrategy \"custom\": pass getToken in config.\n * - authStrategy \"shopify\": use @horae/passport-shopify to get JWT from bridge, then use jwt or custom.\n */\nexport function createPassportSDK(config: PassportSDKConfig): PassportSDK {\n const mode = config.mode ?? \"heritage\";\n const authStrategy = config.authStrategy ?? (mode === \"scale\" ? \"custom\" : \"jwt\");\n const events = createEventBus();\n let auth: AuthStrategyBase;\n\n if (mode === \"scale\") {\n // Scale mode does not require wallet/Privy token flow by default.\n auth = createCustomStrategy(async () => config.token ?? null);\n } else {\n switch (authStrategy) {\n case \"jwt\": {\n const jwt = createJwtStrategy({\n token: config.token ?? undefined,\n storageKey: config.tokenStorageKey ?? undefined,\n });\n auth = jwt;\n break;\n }\n case \"custom\": {\n if (!config.getToken) throw new Error(\"PassportSDK: getToken required for authStrategy 'custom'\");\n auth = createCustomStrategy(config.getToken);\n break;\n }\n case \"shopify\":\n // Shopify: use JWT strategy; token is set by @horae/passport-shopify bridge\n auth = createJwtStrategy({\n token: config.token ?? undefined,\n storageKey: config.tokenStorageKey ?? \"shopify_access_token\",\n });\n break;\n case \"privy\":\n // Privy: use custom strategy with getToken from host (e.g. getAccessToken from @privy-io/react-auth)\n if (!config.getToken) throw new Error(\"PassportSDK: getToken required for authStrategy 'privy' (pass Privy getAccessToken)\");\n auth = createCustomStrategy(config.getToken);\n break;\n default:\n throw new Error(`PassportSDK: unknown authStrategy ${String(authStrategy)}`);\n }\n }\n\n const client = createClient({ apiBase: config.apiBase, getToken: () => auth.getToken() });\n const api = createPassportApi(client);\n const fallbackScaleRegistration =\n config.serial || config.brandId\n ? {\n serialNumber: config.serial,\n manufacturerId: config.brandId,\n }\n : undefined;\n const scaleRegistrationPayload = config.scaleRegistration ?? fallbackScaleRegistration;\n const scaleRegistration = scaleRegistrationPayload\n ? JSON.stringify(scaleRegistrationPayload)\n : undefined;\n\n return {\n api,\n events,\n auth,\n config: Object.freeze({ ...config, mode }),\n mount: (options) =>\n mountApp(\n {\n ...options,\n mode,\n viewerUrl: config.viewerUrl,\n scaleRegistration,\n },\n config.apiBase,\n config.token || null,\n ),\n renderPassportList: (options) =>\n renderPassportList(\n {\n ...options,\n mode,\n viewerUrl: config.viewerUrl,\n scaleRegistration,\n },\n config.apiBase,\n config.token || null,\n ),\n renderPassport: (options) =>\n renderPassport(\n {\n ...options,\n mode,\n viewerUrl: config.viewerUrl,\n scaleRegistration,\n },\n config.apiBase,\n config.token || null,\n ),\n };\n}\n\nexport const HoraeSDK = {\n init(config: PassportSDKConfig): PassportSDK {\n return createPassportSDK(config);\n },\n};\n\ndeclare global {\n interface Window {\n HoraeSDK?: typeof HoraeSDK;\n }\n}\n\nif (typeof window !== \"undefined\") {\n window.HoraeSDK = HoraeSDK;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@horae.io/passport-core",
3
- "version": "1.0.0",
3
+ "version": "1.0.6",
4
4
  "description": "Horae Passport SDK — core client, auth strategies, Horae API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -21,12 +21,16 @@
21
21
  "dev": "tsup --watch"
22
22
  },
23
23
  "dependencies": {
24
- "axios": "^1.8.4",
24
+ "axios": "^1.15.0",
25
25
  "zod": "^3.24.2"
26
26
  },
27
+ "overrides": {
28
+ "axios": "^1.15.0"
29
+ },
27
30
  "devDependencies": {
28
31
  "tsup": "^8.3.5",
29
32
  "typescript": "~5.7.2"
30
33
  },
31
- "peerDependencies": {}
32
- }
34
+ "peerDependencies": {},
35
+ "packageManager": "bun@1.3.10"
36
+ }