@kehto/shell 0.24.5 → 0.25.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
@@ -2210,36 +2210,90 @@ function nappletNamespacePrelude(domains, normalizeIntentUri2) {
2210
2210
  };
2211
2211
  }
2212
2212
  function makeMedia() {
2213
+ const sessions = /* @__PURE__ */ new Set();
2214
+ const ended = /* @__PURE__ */ new Map();
2215
+ const retained = /* @__PURE__ */ new Map();
2216
+ const callbacks = /* @__PURE__ */ new Map();
2217
+ const warnings = /* @__PURE__ */ new Set();
2218
+ const warn = (name, replacement) => {
2219
+ if (warnings.has(name)) return;
2220
+ warnings.add(name);
2221
+ console.warn(`[KEHTO-MEDIA-${name}] Deprecated media API; use ${replacement}. Warned once per endpoint.`);
2222
+ };
2223
+ listen((event) => {
2224
+ if (!isParentMessage(event)) return;
2225
+ const msg = event.data;
2226
+ if (!msg || typeof msg !== "object" || typeof msg.sessionId !== "string") return;
2227
+ const sessionId = msg.sessionId;
2228
+ if (msg.type === "media.session.create.result" && !msg.error) {
2229
+ if (!ended.has(sessionId)) sessions.add(sessionId);
2230
+ return;
2231
+ }
2232
+ if (!sessions.has(sessionId) || ended.has(sessionId)) return;
2233
+ if (msg.type === "media.session.ended") {
2234
+ ended.set(sessionId, msg);
2235
+ retained.delete(sessionId);
2236
+ sessions.delete(sessionId);
2237
+ } else if (["media.state", "media.capabilities", "media.controls"].includes(msg.type)) {
2238
+ const cache2 = retained.get(sessionId) ?? /* @__PURE__ */ new Map();
2239
+ cache2.set(msg.type, msg);
2240
+ retained.set(sessionId, cache2);
2241
+ } else if (msg.type !== "media.command") return;
2242
+ const delivery = Array.from(callbacks.get(sessionId)?.get(msg.type) ?? []);
2243
+ for (const callback of delivery) callback(msg);
2244
+ if (ended.has(sessionId)) callbacks.delete(sessionId);
2245
+ });
2213
2246
  const on = (type, sessionId, callback) => {
2214
- const off = listen((event) => {
2215
- if (!isParentMessage(event)) return;
2216
- const msg = event.data;
2217
- if (typeof msg === "object" && msg !== null && msg.type === type && msg.sessionId === sessionId) callback(msg);
2247
+ const terminal = ended.get(sessionId);
2248
+ if (terminal) {
2249
+ if (type === "media.session.ended") callback(terminal);
2250
+ return subscriptionHandle(() => {
2251
+ });
2252
+ }
2253
+ const byType = callbacks.get(sessionId) ?? /* @__PURE__ */ new Map();
2254
+ const handlers = byType.get(type) ?? /* @__PURE__ */ new Set();
2255
+ handlers.add(callback);
2256
+ byType.set(type, handlers);
2257
+ callbacks.set(sessionId, byType);
2258
+ const cached = retained.get(sessionId)?.get(type);
2259
+ if (cached) callback(cached);
2260
+ return subscriptionHandle(() => {
2261
+ handlers.delete(callback);
2218
2262
  });
2219
- return subscriptionHandle(off);
2220
2263
  };
2221
- return {
2264
+ const command = (sessionId, value) => {
2265
+ if (ended.has(sessionId)) return;
2266
+ fire({ ...value && typeof value === "object" ? value : {}, type: "media.command", sessionId });
2267
+ };
2268
+ return Object.freeze({
2222
2269
  createSession: (options) => request(
2223
- { type: "media.session.create", ...options && typeof options === "object" ? options : {} },
2270
+ { ...options && typeof options === "object" ? options : {}, type: "media.session.create" },
2224
2271
  "media.session.create.result",
2225
2272
  withoutEnvelope,
2226
2273
  { rejectOnError: false }
2227
2274
  ),
2228
2275
  updateSession: (sessionId, metadata) => fire({ type: "media.session.update", sessionId, metadata }),
2229
2276
  destroySession: (sessionId) => fire({ type: "media.session.destroy", sessionId }),
2230
- reportState: (sessionId, state) => fire({ type: "media.state", sessionId, ...state && typeof state === "object" ? state : {} }),
2277
+ reportState: (sessionId, state) => fire({ ...state && typeof state === "object" ? state : {}, type: "media.state", sessionId }),
2231
2278
  reportCapabilities: (sessionId, actions) => fire({ type: "media.capabilities", sessionId, actions }),
2232
- sendCommand: (sessionId, action, value) => fire({ type: "media.command", sessionId, action, ...value === void 0 ? {} : { value } }),
2233
- onCommand: (sessionId, callback) => on("media.command", sessionId, (msg) => callback(msg.action, msg.value)),
2234
- onState: (sessionId, callback) => on("media.state", sessionId, (msg) => callback({
2235
- status: msg.status,
2236
- position: msg.position,
2237
- duration: msg.duration,
2238
- volume: msg.volume
2239
- })),
2279
+ command,
2280
+ sendCommand: (sessionId, action, value) => {
2281
+ warn("SEND-COMMAND", "media.command(sessionId, { action, value })");
2282
+ command(sessionId, { action, ...value === void 0 ? {} : { value } });
2283
+ },
2284
+ onCommand: (sessionId, callback) => {
2285
+ const legacy = callback.length >= 2;
2286
+ if (legacy) warn("COMMAND-CALLBACK", "media.onCommand(sessionId, command => ...)");
2287
+ return on("media.command", sessionId, (msg) => legacy ? callback(msg.action, msg.value) : callback({ action: msg.action, ...msg.value === void 0 ? {} : { value: msg.value }, ...msg.reason === void 0 ? {} : { reason: msg.reason } }));
2288
+ },
2289
+ onState: (sessionId, callback) => on("media.state", sessionId, (msg) => {
2290
+ const { type: _type, sessionId: _sessionId, ...state } = msg;
2291
+ callback(state);
2292
+ }),
2240
2293
  onCapabilities: (sessionId, callback) => on("media.capabilities", sessionId, (msg) => callback(msg.actions)),
2241
- onControls: (sessionId, callback) => on("media.controls", sessionId, (msg) => callback(msg.controls))
2242
- };
2294
+ onControls: (sessionId, callback) => on("media.controls", sessionId, (msg) => callback(msg.controls)),
2295
+ onEnded: (sessionId, callback) => on("media.session.ended", sessionId, (msg) => callback({ sessionId: msg.sessionId, reason: msg.reason }))
2296
+ });
2243
2297
  }
2244
2298
  function makeNotify() {
2245
2299
  const on = (type, callback) => {
@@ -2877,10 +2931,12 @@ function nappletNamespacePrelude(domains, normalizeIntentUri2) {
2877
2931
  intent ??= Object.freeze(makeIntent());
2878
2932
  return intent;
2879
2933
  }
2934
+ let media;
2880
2935
  function isProtectedDomain(domain) {
2881
- return domain === "gamepad" || domain === "shell" || domain === "inc" || domain === "identity" || domain === "theme" || domain === "intent";
2936
+ return domain === "media" || domain === "gamepad" || domain === "shell" || domain === "inc" || domain === "identity" || domain === "theme" || domain === "intent";
2882
2937
  }
2883
2938
  function makeDomain(domain, existing) {
2939
+ if (domain === "media") return media ??= makeMedia();
2884
2940
  if (domain === "gamepad") return gamepad ??= makeGamepad();
2885
2941
  if (domain === "shell") return shell;
2886
2942
  if (domain === "inc") return makeProtectedInc(existing);
@@ -2895,8 +2951,6 @@ function nappletNamespacePrelude(domains, normalizeIntentUri2) {
2895
2951
  return makeStorage();
2896
2952
  case "keys":
2897
2953
  return makeKeys();
2898
- case "media":
2899
- return makeMedia();
2900
2954
  case "notify":
2901
2955
  return makeNotify();
2902
2956
  case "config":