@kehto/services 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1366,7 +1366,7 @@ var DEFAULT_THEME = {
1366
1366
  primary: "#7aa2f7"
1367
1367
  }
1368
1368
  // fonts, background, title intentionally undefined — all optional per
1369
- // @napplet/nub/theme Theme interface.
1369
+ // @napplet/nap/theme Theme interface.
1370
1370
  };
1371
1371
  function createThemeService(options = {}) {
1372
1372
  let currentTheme = options.initialTheme ?? DEFAULT_THEME;
@@ -2396,6 +2396,244 @@ function toErrorMessage3(err) {
2396
2396
  return "upload failed";
2397
2397
  }
2398
2398
 
2399
+ // src/intent-service.ts
2400
+ var INTENT_SERVICE_VERSION = "1.0.0";
2401
+ var INTENT_DESCRIPTOR = {
2402
+ name: "intent",
2403
+ version: INTENT_SERVICE_VERSION,
2404
+ description: "NAP-INTENT archetype intent dispatch \u2014 invoke/available/handlers"
2405
+ };
2406
+ function toErrorMessage4(err) {
2407
+ if (err instanceof Error) return err.message;
2408
+ if (typeof err === "string") return err;
2409
+ return "intent request failed";
2410
+ }
2411
+ function createIntentService(options) {
2412
+ if (!options || typeof options.resolver !== "object" || options.resolver === null) {
2413
+ throw new Error("createIntentService: options.resolver is required");
2414
+ }
2415
+ const { resolver } = options;
2416
+ const windows = /* @__PURE__ */ new Map();
2417
+ resolver.onChanged?.((availability) => {
2418
+ for (const send of windows.values()) {
2419
+ send({ type: "intent.changed", availability });
2420
+ }
2421
+ });
2422
+ function settle(call, send, resultType, id, onValue) {
2423
+ let pending;
2424
+ try {
2425
+ pending = Promise.resolve(call());
2426
+ } catch (err) {
2427
+ send({ type: resultType, id, error: toErrorMessage4(err) });
2428
+ return;
2429
+ }
2430
+ pending.then((value) => send(onValue(value))).catch((err) => send({ type: resultType, id, error: toErrorMessage4(err) }));
2431
+ }
2432
+ function handleInvoke(windowId, msg, send) {
2433
+ const m = msg;
2434
+ const id = m.id ?? "";
2435
+ const request = m.request;
2436
+ if (!request || typeof request !== "object" || typeof request.archetype !== "string" || request.archetype.length === 0) {
2437
+ send({ type: "intent.invoke.result", id, error: "invalid request" });
2438
+ return;
2439
+ }
2440
+ settle(
2441
+ () => resolver.invoke(request, { windowId }),
2442
+ send,
2443
+ "intent.invoke.result",
2444
+ id,
2445
+ (result) => ({ type: "intent.invoke.result", id, result })
2446
+ );
2447
+ }
2448
+ function handleAvailable(msg, send) {
2449
+ const m = msg;
2450
+ const id = m.id ?? "";
2451
+ if (typeof m.archetype !== "string" || m.archetype.length === 0) {
2452
+ send({ type: "intent.available.result", id, error: "invalid archetype" });
2453
+ return;
2454
+ }
2455
+ const archetype = m.archetype;
2456
+ settle(
2457
+ () => resolver.available(archetype),
2458
+ send,
2459
+ "intent.available.result",
2460
+ id,
2461
+ (availability) => ({ type: "intent.available.result", id, availability })
2462
+ );
2463
+ }
2464
+ function handleHandlers(msg, send) {
2465
+ const m = msg;
2466
+ const id = m.id ?? "";
2467
+ settle(
2468
+ () => resolver.handlers(),
2469
+ send,
2470
+ "intent.handlers.result",
2471
+ id,
2472
+ (handlers) => ({ type: "intent.handlers.result", id, handlers })
2473
+ );
2474
+ }
2475
+ return {
2476
+ descriptor: INTENT_DESCRIPTOR,
2477
+ handleMessage(windowId, message, send) {
2478
+ windows.set(windowId, send);
2479
+ switch (message.type) {
2480
+ case "intent.invoke":
2481
+ handleInvoke(windowId, message, send);
2482
+ return;
2483
+ case "intent.available":
2484
+ handleAvailable(message, send);
2485
+ return;
2486
+ case "intent.handlers":
2487
+ handleHandlers(message, send);
2488
+ return;
2489
+ default:
2490
+ return;
2491
+ }
2492
+ },
2493
+ onWindowDestroyed(windowId) {
2494
+ windows.delete(windowId);
2495
+ }
2496
+ };
2497
+ }
2498
+
2499
+ // src/catalog-intent-resolver.ts
2500
+ function candidatesFor(catalog, archetype, defaultHandler) {
2501
+ const candidates = [];
2502
+ for (const entry of catalog) {
2503
+ const support = entry.archetypes[archetype];
2504
+ if (!support) continue;
2505
+ candidates.push({
2506
+ dTag: entry.dTag,
2507
+ ...entry.title === void 0 ? {} : { title: entry.title },
2508
+ actions: support.actions,
2509
+ protocols: support.protocols,
2510
+ ...entry.dTag === defaultHandler ? { isDefault: true } : {}
2511
+ });
2512
+ }
2513
+ return candidates;
2514
+ }
2515
+ function fail(archetype, action, error) {
2516
+ return { ok: false, archetype, action, handled: false, error };
2517
+ }
2518
+ function createCatalogIntentResolver(options) {
2519
+ if (!options || typeof options.loadCatalog !== "function") {
2520
+ throw new Error("createCatalogIntentResolver: options.loadCatalog is required");
2521
+ }
2522
+ if (!options.windows || typeof options.windows.open !== "function") {
2523
+ throw new Error("createCatalogIntentResolver: options.windows is required");
2524
+ }
2525
+ const { loadCatalog, windows, getDefaultHandler, chooseHandler, defaultProtocol } = options;
2526
+ const listeners = /* @__PURE__ */ new Set();
2527
+ async function availabilityFor(archetype) {
2528
+ const catalog = await loadCatalog();
2529
+ const def = getDefaultHandler?.(archetype);
2530
+ const candidates = candidatesFor(catalog, archetype, def);
2531
+ return {
2532
+ archetype,
2533
+ available: candidates.length > 0,
2534
+ candidates,
2535
+ hasDefault: def !== void 0 && candidates.some((c) => c.dTag === def)
2536
+ };
2537
+ }
2538
+ async function pickHandler(archetype, candidates, preference, callerWindowId) {
2539
+ if (typeof preference === "string" && preference !== "default" && preference !== "choose") {
2540
+ return preference;
2541
+ }
2542
+ if (preference === "choose") {
2543
+ const picked = await chooseHandler?.(archetype, candidates, callerWindowId);
2544
+ return picked ?? null;
2545
+ }
2546
+ const def = getDefaultHandler?.(archetype);
2547
+ if (def !== void 0 && candidates.some((c) => c.dTag === def)) return def;
2548
+ if (candidates.length === 1) return candidates[0].dTag;
2549
+ if (chooseHandler) {
2550
+ const picked = await chooseHandler(archetype, candidates, callerWindowId);
2551
+ return picked ?? null;
2552
+ }
2553
+ return candidates[0].dTag;
2554
+ }
2555
+ async function invoke(request, context) {
2556
+ const archetype = request.archetype;
2557
+ const action = request.action ?? "open";
2558
+ const catalog = await loadCatalog();
2559
+ const candidates = candidatesFor(catalog, archetype, getDefaultHandler?.(archetype));
2560
+ if (candidates.length === 0) return fail(archetype, action, "no handler");
2561
+ const pickedDTag = await pickHandler(archetype, candidates, request.handler, context.windowId);
2562
+ if (pickedDTag === null) return fail(archetype, action, "user cancelled");
2563
+ const handler = candidates.find((c) => c.dTag === pickedDTag);
2564
+ if (!handler) return fail(archetype, action, "no handler");
2565
+ if (!handler.actions.includes(action)) return fail(archetype, action, "unsupported action");
2566
+ const protocol = request.protocol ?? defaultProtocol?.(archetype) ?? handler.protocols[0];
2567
+ if (protocol !== void 0 && handler.protocols.length > 0 && !handler.protocols.includes(protocol)) {
2568
+ return fail(archetype, action, "unsupported protocol");
2569
+ }
2570
+ let windowId;
2571
+ try {
2572
+ const opened = await windows.open({
2573
+ dTag: handler.dTag,
2574
+ archetype,
2575
+ action,
2576
+ ...protocol === void 0 ? {} : { protocol },
2577
+ ...request.payload === void 0 ? {} : { payload: request.payload },
2578
+ ...request.behavior === void 0 ? {} : { behavior: request.behavior },
2579
+ callerWindowId: context.windowId
2580
+ });
2581
+ windowId = opened.windowId;
2582
+ } catch {
2583
+ return fail(archetype, action, "invoke failed");
2584
+ }
2585
+ return {
2586
+ ok: true,
2587
+ archetype,
2588
+ action,
2589
+ handled: true,
2590
+ handler: handler.dTag,
2591
+ windowId,
2592
+ ...protocol === void 0 ? {} : { protocol }
2593
+ };
2594
+ }
2595
+ async function handlers() {
2596
+ const catalog = await loadCatalog();
2597
+ const archetypes = /* @__PURE__ */ new Set();
2598
+ for (const entry of catalog) {
2599
+ for (const slug of Object.keys(entry.archetypes)) archetypes.add(slug);
2600
+ }
2601
+ return Promise.all([...archetypes].map((a) => availabilityFor(a)));
2602
+ }
2603
+ return {
2604
+ invoke,
2605
+ available: availabilityFor,
2606
+ handlers,
2607
+ onChanged(listener) {
2608
+ listeners.add(listener);
2609
+ return () => listeners.delete(listener);
2610
+ },
2611
+ notifyChanged(archetype) {
2612
+ if (listeners.size === 0) return;
2613
+ void availabilityFor(archetype).then((availability) => {
2614
+ for (const listener of listeners) listener(availability);
2615
+ });
2616
+ }
2617
+ };
2618
+ }
2619
+
2620
+ // src/manifest-intent-catalog.ts
2621
+ var DEFAULT_ACTIONS = ["open"];
2622
+ function manifestToIntentCatalogEntry(manifest) {
2623
+ const archetypes = {};
2624
+ for (const { slug, nap } of manifest.archetypes) {
2625
+ archetypes[slug] = {
2626
+ actions: [...DEFAULT_ACTIONS],
2627
+ protocols: nap ? [nap] : []
2628
+ };
2629
+ }
2630
+ return {
2631
+ dTag: manifest.dTag,
2632
+ ...manifest.title === void 0 ? {} : { title: manifest.title },
2633
+ archetypes
2634
+ };
2635
+ }
2636
+
2399
2637
  // src/cvm-service.ts
2400
2638
  var CVM_SERVICE_VERSION = "1.0.0";
2401
2639
  var CVM_DESCRIPTOR = {
@@ -2438,7 +2676,7 @@ function createCvmService(options) {
2438
2676
  const m = msg;
2439
2677
  const id = m.id ?? "";
2440
2678
  void transport.discover(m.query).then((servers) => send({ type: "cvm.discover.result", id, servers })).catch(
2441
- (err) => send({ type: "cvm.discover.result", id, servers: [], error: toErrorMessage4(err) })
2679
+ (err) => send({ type: "cvm.discover.result", id, servers: [], error: toErrorMessage5(err) })
2442
2680
  );
2443
2681
  }
2444
2682
  function handleRequest(windowId, msg, send) {
@@ -2454,7 +2692,7 @@ function createCvmService(options) {
2454
2692
  }
2455
2693
  openSession(windowId, m.server, send);
2456
2694
  void transport.request(m.server, m.message, m.options).then((message) => send({ type: "cvm.request.result", id, message })).catch(
2457
- (err) => send({ type: "cvm.request.result", id, error: toErrorMessage4(err) })
2695
+ (err) => send({ type: "cvm.request.result", id, error: toErrorMessage5(err) })
2458
2696
  );
2459
2697
  }
2460
2698
  function handleClose(windowId, msg, send) {
@@ -2465,7 +2703,7 @@ function createCvmService(options) {
2465
2703
  return;
2466
2704
  }
2467
2705
  closeSession(windowId, m.server.pubkey);
2468
- void transport.close(m.server).then(() => send({ type: "cvm.close.result", id })).catch((err) => send({ type: "cvm.close.result", id, error: toErrorMessage4(err) }));
2706
+ void transport.close(m.server).then(() => send({ type: "cvm.close.result", id })).catch((err) => send({ type: "cvm.close.result", id, error: toErrorMessage5(err) }));
2469
2707
  }
2470
2708
  return {
2471
2709
  descriptor: CVM_DESCRIPTOR,
@@ -2496,7 +2734,7 @@ function createCvmService(options) {
2496
2734
  }
2497
2735
  };
2498
2736
  }
2499
- function toErrorMessage4(err) {
2737
+ function toErrorMessage5(err) {
2500
2738
  if (err instanceof Error) return err.message;
2501
2739
  if (typeof err === "string") return err;
2502
2740
  return "cvm request failed";
@@ -2505,11 +2743,13 @@ export {
2505
2743
  createAudioService,
2506
2744
  createBrowserMediaBridge,
2507
2745
  createCacheService,
2746
+ createCatalogIntentResolver,
2508
2747
  createConfigService,
2509
2748
  createCoordinatedRelay,
2510
2749
  createCvmService,
2511
2750
  createHttpUploader,
2512
2751
  createIdentityService,
2752
+ createIntentService,
2513
2753
  createKeysService,
2514
2754
  createMediaService,
2515
2755
  createNotificationService,
@@ -2519,6 +2759,7 @@ export {
2519
2759
  createRelayPoolService,
2520
2760
  createResourceService,
2521
2761
  createThemeService,
2522
- createUploadService
2762
+ createUploadService,
2763
+ manifestToIntentCatalogEntry
2523
2764
  };
2524
2765
  //# sourceMappingURL=index.js.map