@iicp/web-node 0.2.4 → 0.2.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/README.md CHANGED
@@ -5,6 +5,11 @@ from the network *and* **serve** a model from a browser tab. ESM, built on the p
5
5
  native `fetch` / `SubtleCrypto` / WebGPU (and runs in Node ≥18). The browser
6
6
  client refuses keyless providers rather than silently sending plaintext.
7
7
 
8
+ IICP supplies intent resolution and provider eligibility/selection. MCP, A2A,
9
+ HTTP or another negotiated binding may then execute the selected task. See the
10
+ public [protocol positioning](https://github.com/RobLe3/IICP/blob/main/standards/IICP_PROTOCOL_POSITIONING.md)
11
+ and [adjacent-protocol comparison](https://github.com/RobLe3/IICP/blob/main/standards/PROTOCOL_COMPARISON_2026-08-15.md).
12
+
8
13
  ```
9
14
  npm install @iicp/web-node
10
15
  ```
@@ -31,11 +36,33 @@ does not support them, and can enforce strict region and signed-policy-manifest
31
36
  before a prompt is sent. Declared prohibited or high-risk public-mesh intents are refused
32
37
  locally. Successful routing receipts exclude prompt, response, token, and endpoint content.
33
38
 
39
+ Restricted trust-domain, federated-private, local-only and custom operating
40
+ modes are not supported by the browser package yet. Passing an explicit
41
+ non-public `operating_mode` to `IicpBrowserClient`, or `operatingMode` to
42
+ `BrowserNodeProvider`, throws `restricted_profile_unsupported` during
43
+ construction, before discovery, registration or relay traffic. The package
44
+ does not persist membership credentials in browser storage and never downgrades
45
+ an explicit private mode to the public directory.
46
+
34
47
  When the chosen node advertises an encryption key (`nodeCxKey(node)`), the payload is
35
48
  **sealed end-to-end** — the directory, relays, and network see only ciphertext. There is
36
49
  no opt-out. A node that does not advertise `cx_public_key`/`public_key` is refused before
37
50
  any network send so browser use cannot silently fall back to plaintext.
38
51
 
52
+ ## Runtime self-description
53
+
54
+ Browser `chat()` calls add a small IICP runtime identity context by default. It
55
+ tells the selected model that it is being accessed through IICP, identifies the
56
+ active intent and browser package version, and includes a model or capability
57
+ fact only when it comes from the selected node's advertisement. It does not
58
+ expose endpoints, full node identities, candidate sets, scores or credentials,
59
+ and it is not a prompt-injection security boundary.
60
+
61
+ Set `runtime_identity: { mode: "disabled" }` to preserve the application
62
+ messages without the capsule, or use `mode: "required"` to refuse when a
63
+ supported instruction channel is unavailable. Non-chat operations and the
64
+ plaintext envelope helper remain unchanged.
65
+
39
66
  ## Serve — be a node from the browser
40
67
 
41
68
  ```ts
@@ -1,5 +1,6 @@
1
1
  import type { ChatMessage } from "./iicpConsumer.js";
2
2
  import type { EffectiveCapability } from "./effectiveCapability.js";
3
+ import { type BrowserOperatingMode } from "./operatingMode.js";
3
4
  export interface BrowserProviderRuntime {
4
5
  chat(messages: ChatMessage[], opts?: {
5
6
  temperature?: number;
@@ -7,6 +8,8 @@ export interface BrowserProviderRuntime {
7
8
  }): Promise<string>;
8
9
  }
9
10
  export interface BrowserProviderConfig {
11
+ /** Explicit operating mode. Browser CUG/local modes currently fail closed. */
12
+ operatingMode?: BrowserOperatingMode;
10
13
  /** Relay node base URL, e.g. "http://127.0.0.1:9484". Required. */
11
14
  relayUrl: string;
12
15
  /** Auto-discovered relay node id. Used to audience-scope relay bind tickets. */
@@ -18,6 +18,7 @@
18
18
  // consumers route to a browser worker with zero client changes.
19
19
  import { maskTunnelUrl } from "./iicpConsumer.js";
20
20
  import { createCxKeyPair, decryptPayload } from "./cxConfidentiality.js";
21
+ import { requireSupportedBrowserMode } from "./operatingMode.js";
21
22
  import { BROWSER_NODE_SDK_COMPATIBILITY_VERSION, BROWSER_NODE_SDK_VERSION, BROWSER_NODE_VERSION, } from "./version.js";
22
23
  const CHAT_INTENT = "urn:iicp:intent:llm:chat:v1";
23
24
  export { BROWSER_NODE_SDK_VERSION } from "./version.js";
@@ -172,6 +173,7 @@ export class BrowserNodeProvider {
172
173
  constructor(runtime, cfg) {
173
174
  this.runtime = runtime;
174
175
  this.cfg = cfg;
176
+ requireSupportedBrowserMode(cfg.operatingMode);
175
177
  this.nodeId = `browser-${crypto.randomUUID().slice(0, 8)}`;
176
178
  }
177
179
  get state() {
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schema": "iicp.browser_build_provenance.v1",
3
3
  "package": "@iicp/web-node",
4
- "implementation_version": "0.2.4",
4
+ "implementation_version": "0.2.6",
5
5
  "sdk_compatibility_version": "0.7.102",
6
- "source_commit": "c26bf228708a5bfad0f8574407ea1a45e4d377c7",
7
- "lockfile_sha256": "54183560d240a4f8573274dfab6dda6c297fc1bcbe5ae18b12d5fa5c801f0ffe"
6
+ "source_commit": "2d839c075c649ca8320af1734845862c8265588f",
7
+ "lockfile_sha256": "3a86e8b68bd9cee5ab5f99b1975b75db0ed924fe582873b9590f0047bb87eea1"
8
8
  }
@@ -1,7 +1,10 @@
1
1
  import { type CxPublicKey } from "./cxConfidentiality.js";
2
2
  import { type RuntimeIdentityOptions } from "./runtimeIdentity.js";
3
+ import { type BrowserOperatingMode } from "./operatingMode.js";
3
4
  export declare const DEFAULT_DIRECTORY_URL = "https://iicp.network";
4
5
  export interface ClientConfig {
6
+ /** Explicit operating mode. Browser CUG/local modes currently fail closed. */
7
+ operating_mode?: BrowserOperatingMode;
5
8
  /** Directory base URL. Default: https://iicp.network (CORS-enabled). */
6
9
  directory_url?: string;
7
10
  /** Per-request timeout (ms). Default 10000. */
@@ -170,7 +173,6 @@ export declare function createRedactedRoutingReceipt(args: {
170
173
  allowedRegions?: readonly string[] | null;
171
174
  requiredManifestIdentityLevel?: RequiredManifestIdentityLevel | null;
172
175
  }): RoutingReceipt;
173
- /** Browser-native, consumer-only IICP client. */
174
176
  export declare class IicpBrowserClient {
175
177
  private readonly directory;
176
178
  private readonly timeout;
@@ -17,7 +17,9 @@
17
17
  // Epic: #446 · Dev: #447 · Research: research/wasm/WASM-1-feasibility.md (#292).
18
18
  import { encryptPayload } from "./cxConfidentiality.js";
19
19
  import { verifyDispatchTicket } from "./dispatchTicket.js";
20
- import { composeRuntimeIdentity } from "./runtimeIdentity.js";
20
+ import { composeRuntimeIdentity, withRuntimeFacts } from "./runtimeIdentity.js";
21
+ import { BROWSER_NODE_VERSION } from "./version.js";
22
+ import { requireSupportedBrowserMode } from "./operatingMode.js";
21
23
  const REFUSED_INTENT_RULES = [
22
24
  { category: "prohibited", rule_id: "eu-ai-act-social-scoring", label: "social scoring", fragments: ["social-scoring", "social_scoring", "social:scoring"] },
23
25
  { category: "prohibited", rule_id: "eu-ai-act-criminal-risk", label: "individual criminal risk prediction", fragments: ["criminal-risk", "criminal_risk", "criminal:risk", "predict-crime"] },
@@ -273,6 +275,41 @@ export function createRedactedRoutingReceipt(args) {
273
275
  };
274
276
  }
275
277
  /** Browser-native, consumer-only IICP client. */
278
+ function selectedAdvertisedModel(node, requestedModel) {
279
+ if (requestedModel && node?.models?.includes(requestedModel))
280
+ return requestedModel;
281
+ return node?.models?.length === 1 ? node.models[0] : undefined;
282
+ }
283
+ function effectiveCapabilityLabels(node, intent, model) {
284
+ const raw = node?.capabilities;
285
+ if (!Array.isArray(raw))
286
+ return [];
287
+ const variants = raw.filter((candidate) => Boolean(candidate) && typeof candidate === "object" && candidate.intent === intent);
288
+ const exact = model
289
+ ? variants.filter((candidate) => Array.isArray(candidate.models) && candidate.models.includes(model))
290
+ : variants;
291
+ const selected = exact.length === 1 ? exact[0] : variants.length === 1 ? variants[0] : undefined;
292
+ if (!selected)
293
+ return [];
294
+ const labels = [];
295
+ for (const value of Array.isArray(selected.input_modalities) ? selected.input_modalities : []) {
296
+ if (typeof value === "string")
297
+ labels.push(`input_modality:${value}`);
298
+ }
299
+ for (const value of Array.isArray(selected.output_modalities) ? selected.output_modalities : []) {
300
+ if (typeof value === "string")
301
+ labels.push(`output_modality:${value}`);
302
+ }
303
+ for (const value of Array.isArray(selected.features) ? selected.features : []) {
304
+ if (typeof value === "string")
305
+ labels.push(value);
306
+ }
307
+ for (const value of Array.isArray(selected.execution_capabilities) ? selected.execution_capabilities : []) {
308
+ if (typeof value === "string")
309
+ labels.push(`execution:${value}`);
310
+ }
311
+ return [...new Set(labels)].sort();
312
+ }
276
313
  export class IicpBrowserClient {
277
314
  directory;
278
315
  timeout;
@@ -281,6 +318,7 @@ export class IicpBrowserClient {
281
318
  routeDiscoveryMode;
282
319
  dispatchTicketKey;
283
320
  constructor(cfg = {}) {
321
+ requireSupportedBrowserMode(cfg.operating_mode);
284
322
  this.directory = (cfg.directory_url ?? DEFAULT_DIRECTORY_URL).replace(/\/+$/, "");
285
323
  this.timeout = cfg.timeout_ms ?? 10_000;
286
324
  this.allowedRegions = normalizeAllowedRegions(cfg.allowed_regions);
@@ -444,7 +482,15 @@ export class IicpBrowserClient {
444
482
  async chatWithReceipt(messages, opts) {
445
483
  const intent = opts.intent ?? "urn:iicp:intent:llm:chat:v1";
446
484
  validateIntent(intent);
447
- messages = composeRuntimeIdentity(messages, intent, opts.runtime_identity);
485
+ const selectedModel = selectedAdvertisedModel(opts.node, opts.model);
486
+ messages = composeRuntimeIdentity(messages, intent, withRuntimeFacts(opts.runtime_identity, {
487
+ client_name: "@iicp/web-node",
488
+ client_version: BROWSER_NODE_VERSION,
489
+ connection_mode: "routed",
490
+ selected_model: selectedModel,
491
+ effective_capabilities: effectiveCapabilityLabels(opts.node, intent, selectedModel),
492
+ selection_reason: "matched_intent_and_constraints",
493
+ }));
448
494
  const taskId = globalThis.crypto?.randomUUID?.() ?? `task-${Date.now()}-${Math.random().toString(16).slice(2)}`;
449
495
  const payload = { messages, model: opts.model };
450
496
  // IICP-CX S.16: encryption is MANDATORY (privacy-first #360) — no opt-out.
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from "./dispatchTicket.js";
3
3
  export * from "./cxConfidentiality.js";
4
4
  export * from "./effectiveCapability.js";
5
5
  export * from "./runtimeIdentity.js";
6
+ export * from "./operatingMode.js";
6
7
  export * from "./browserNodeProvider.js";
7
8
  export * from "./webllmRuntime.js";
8
9
  export * from "./version.js";
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ export * from "./dispatchTicket.js";
10
10
  export * from "./cxConfidentiality.js";
11
11
  export * from "./effectiveCapability.js";
12
12
  export * from "./runtimeIdentity.js";
13
+ export * from "./operatingMode.js";
13
14
  export * from "./browserNodeProvider.js";
14
15
  export * from "./webllmRuntime.js";
15
16
  export * from "./version.js";
@@ -0,0 +1,4 @@
1
+ export type BrowserOperatingMode = "public" | "private" | "federated_private" | "local_only" | "custom";
2
+ export declare const RESTRICTED_BROWSER_UNSUPPORTED = "restricted_profile_unsupported";
3
+ /** Refuse unsupported modes before discovery, registration or relay work. */
4
+ export declare function requireSupportedBrowserMode(mode?: BrowserOperatingMode): void;
@@ -0,0 +1,8 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ export const RESTRICTED_BROWSER_UNSUPPORTED = "restricted_profile_unsupported";
3
+ /** Refuse unsupported modes before discovery, registration or relay work. */
4
+ export function requireSupportedBrowserMode(mode = "public") {
5
+ if (mode !== "public") {
6
+ throw new Error(RESTRICTED_BROWSER_UNSUPPORTED);
7
+ }
8
+ }
@@ -3,17 +3,26 @@ export declare const RUNTIME_IDENTITY_PROFILE_ID = "urn:iicp:profile:runtime-ide
3
3
  export declare const RUNTIME_IDENTITY_MARKER = "IICP-RUNTIME-CONTEXT/1";
4
4
  export declare const RUNTIME_IDENTITY_CHAT_INTENT = "urn:iicp:intent:llm:chat:v1";
5
5
  export declare const RUNTIME_IDENTITY_MAX_BYTES = 2048;
6
- export type RuntimeIdentityMode = "disabled" | "explicit" | "required";
6
+ export declare const CANONICAL_IICP_EXPLANATION = "IICP is the Intent-based Inter-agent Communication Protocol: a provider-neutral control plane that discovers eligible intelligence services, evaluates them under explicit constraints, selects a provider, and leaves execution to a supported provider mechanism.";
7
+ export declare function isDirectIicpExplainer(prompt: string): boolean;
8
+ export declare function validIicpExplanation(answer: string): boolean;
9
+ export type RuntimeIdentityMode = "auto" | "disabled" | "explicit" | "required";
7
10
  export type RuntimeIdentityInstructionChannel = "system" | "unsupported";
11
+ export type RuntimeIdentityConnectionMode = "routed" | "local_browser";
12
+ export type RuntimeIdentitySelectionReason = "matched_intent_and_constraints" | "explicit_model_match" | "fallback_after_unavailable_candidate" | "intentional_exploration" | "local_browser_execution";
8
13
  export interface RuntimeIdentityOptions {
9
14
  mode?: RuntimeIdentityMode;
10
15
  instruction_channel?: RuntimeIdentityInstructionChannel;
11
16
  selected_model?: string;
12
17
  effective_capabilities?: string[];
13
- selection_reason?: "matched_intent_and_constraints";
18
+ selection_reason?: RuntimeIdentitySelectionReason;
19
+ client_name?: string;
20
+ client_version?: string;
21
+ connection_mode?: RuntimeIdentityConnectionMode;
14
22
  }
15
23
  export declare class RuntimeIdentityContextUnsupported extends Error {
16
24
  constructor();
17
25
  }
26
+ export declare function withRuntimeFacts(options: RuntimeIdentityOptions | undefined, facts: Required<Pick<RuntimeIdentityOptions, "client_name" | "client_version" | "connection_mode" | "selection_reason">> & Pick<RuntimeIdentityOptions, "selected_model" | "effective_capabilities">): RuntimeIdentityOptions;
18
27
  export declare function renderRuntimeIdentity(intent: string, options: RuntimeIdentityOptions): string;
19
28
  export declare function composeRuntimeIdentity(messages: readonly ChatMessage[], intent: string, options?: RuntimeIdentityOptions): ChatMessage[];
@@ -2,22 +2,79 @@ export const RUNTIME_IDENTITY_PROFILE_ID = "urn:iicp:profile:runtime-identity-co
2
2
  export const RUNTIME_IDENTITY_MARKER = "IICP-RUNTIME-CONTEXT/1";
3
3
  export const RUNTIME_IDENTITY_CHAT_INTENT = "urn:iicp:intent:llm:chat:v1";
4
4
  export const RUNTIME_IDENTITY_MAX_BYTES = 2048;
5
- const BASE_CAPSULE = "This request reached you through IICP, the Intent-based Inter-agent Communication Protocol. IICP discovers eligible services and routes requests. You are the selected model or service, not IICP. When asked about this connection, use only supplied runtime facts; do not guess missing facts.";
5
+ const MAX_FACT_BYTES = 160;
6
+ const MAX_CAPABILITIES = 32;
7
+ export const CANONICAL_IICP_EXPLANATION = "IICP is the Intent-based Inter-agent Communication Protocol: a provider-neutral control plane that discovers eligible intelligence services, evaluates them under explicit constraints, selects a provider, and leaves execution to a supported provider mechanism.";
8
+ export function isDirectIicpExplainer(prompt) {
9
+ const value = prompt.trim().toLowerCase().replace(/[.?!]+$/u, "");
10
+ return ["what is iicp", "what does iicp stand for", "explain iicp", "describe iicp", "what is this"].includes(value);
11
+ }
12
+ export function validIicpExplanation(answer) {
13
+ const value = answer.toLowerCase();
14
+ return value.includes("intent-based inter-agent communication protocol")
15
+ && (value.includes("control plane") || value.includes("discover"))
16
+ && !value.includes("industrial internet of things computing");
17
+ }
18
+ const BASE_CAPSULE = "This request reached you through IICP, the Intent-based Inter-agent Communication Protocol. IICP is a provider-neutral control plane that turns a requested intent and constraints into discovery, eligibility evaluation and provider selection; execution then uses a supported provider mechanism. You are the selected model or service, not IICP. If asked what IICP is or stands for, use this definition. IICP does not mean Industrial Internet of Things Computing. Use only supplied runtime facts and do not guess missing facts.";
6
19
  export class RuntimeIdentityContextUnsupported extends Error {
7
20
  constructor() {
8
21
  super("required_identity_context_unsupported");
9
22
  this.name = "RuntimeIdentityContextUnsupported";
10
23
  }
11
24
  }
25
+ const selectionText = {
26
+ matched_intent_and_constraints: "This service matched the requested intent and constraints.",
27
+ explicit_model_match: "This service matched the requested model and constraints.",
28
+ fallback_after_unavailable_candidate: "This service was selected after an earlier candidate was unavailable.",
29
+ intentional_exploration: "This service was selected for an intentional routing exploration.",
30
+ local_browser_execution: "This model is running locally in the browser.",
31
+ };
32
+ export function withRuntimeFacts(options, facts) {
33
+ return {
34
+ ...(options ?? {}),
35
+ ...facts,
36
+ selected_model: facts.selected_model,
37
+ effective_capabilities: [...(facts.effective_capabilities ?? [])],
38
+ };
39
+ }
40
+ function boundedFact(value, name) {
41
+ if (!value || /[\u0000-\u001f\u007f]/u.test(value)) {
42
+ throw new Error(`runtime identity ${name} contains control characters`);
43
+ }
44
+ if (new TextEncoder().encode(value).byteLength > MAX_FACT_BYTES) {
45
+ throw new Error(`runtime identity ${name} exceeds the bounded fact limit`);
46
+ }
47
+ return value;
48
+ }
12
49
  export function renderRuntimeIdentity(intent, options) {
13
- const lines = [`[${RUNTIME_IDENTITY_MARKER}]`, BASE_CAPSULE, "Runtime facts:", `- intent: ${intent}`];
50
+ const lines = [`[${RUNTIME_IDENTITY_MARKER}]`, BASE_CAPSULE, "Runtime facts:", `- intent: ${boundedFact(intent, "intent")}`];
51
+ if (options.client_name || options.client_version) {
52
+ if (!options.client_name || !options.client_version)
53
+ throw new Error("runtime identity client name and version must be supplied together");
54
+ lines.push(`- client: ${boundedFact(options.client_name, "client name")} ${boundedFact(options.client_version, "client version")}`);
55
+ }
56
+ if (options.connection_mode === "routed") {
57
+ lines.push("- connection: routed through IICP to an eligible provider.");
58
+ }
59
+ else if (options.connection_mode === "local_browser") {
60
+ lines.push("- connection: This model is running locally in the browser; no remote IICP provider was selected.");
61
+ }
62
+ else if (options.connection_mode !== undefined) {
63
+ throw new Error("runtime identity connection mode is unsupported");
64
+ }
14
65
  if (options.selected_model)
15
- lines.push(`- selected model (provider assertion): ${options.selected_model}`);
66
+ lines.push(`- selected model: ${boundedFact(options.selected_model, "selected model")}`);
67
+ if ((options.effective_capabilities?.length ?? 0) > MAX_CAPABILITIES) {
68
+ throw new Error("runtime identity effective capabilities exceed the bounded count");
69
+ }
16
70
  if (options.effective_capabilities?.length) {
17
- lines.push(`- effective capabilities: ${options.effective_capabilities.join(", ")}`);
71
+ lines.push(`- effective capabilities: ${options.effective_capabilities.map((value) => boundedFact(value, "effective capability")).join(", ")}`);
18
72
  }
19
- if (options.selection_reason === "matched_intent_and_constraints") {
20
- lines.push("- selection: This service matched the requested intent and constraints.");
73
+ if (options.selection_reason) {
74
+ const selection = selectionText[options.selection_reason];
75
+ if (!selection)
76
+ throw new Error("runtime identity selection reason is unsupported");
77
+ lines.push(`- selection: ${selection}`);
21
78
  }
22
79
  const rendered = lines.join("\n");
23
80
  if (new TextEncoder().encode(rendered).byteLength > RUNTIME_IDENTITY_MAX_BYTES) {
@@ -27,10 +84,20 @@ export function renderRuntimeIdentity(intent, options) {
27
84
  }
28
85
  export function composeRuntimeIdentity(messages, intent, options) {
29
86
  const original = [...messages];
30
- const mode = options?.mode ?? "disabled";
31
- if (mode === "disabled" || intent !== RUNTIME_IDENTITY_CHAT_INTENT)
87
+ const resolved = options ?? {};
88
+ const mode = resolved.mode ?? "auto";
89
+ if (intent !== RUNTIME_IDENTITY_CHAT_INTENT)
32
90
  return original;
33
- if (options?.instruction_channel === "unsupported") {
91
+ if (!["auto", "disabled", "explicit", "required"].includes(mode)) {
92
+ throw new Error("runtime identity mode is unsupported");
93
+ }
94
+ if (mode === "disabled")
95
+ return original;
96
+ if (resolved.instruction_channel !== undefined
97
+ && !["system", "unsupported"].includes(resolved.instruction_channel)) {
98
+ throw new Error("runtime identity instruction channel is unsupported");
99
+ }
100
+ if (resolved.instruction_channel === "unsupported") {
34
101
  if (mode === "required")
35
102
  throw new RuntimeIdentityContextUnsupported();
36
103
  return original;
@@ -43,7 +110,7 @@ export function composeRuntimeIdentity(messages, intent, options) {
43
110
  insertion += 1;
44
111
  return [
45
112
  ...original.slice(0, insertion),
46
- { role: "system", content: renderRuntimeIdentity(intent, options ?? {}) },
113
+ { role: "system", content: renderRuntimeIdentity(intent, resolved) },
47
114
  ...original.slice(insertion),
48
115
  ];
49
116
  }
package/dist/version.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const BROWSER_NODE_VERSION = "0.2.4";
1
+ export declare const BROWSER_NODE_VERSION = "0.2.6";
2
2
  export declare const BROWSER_NODE_SDK_COMPATIBILITY_VERSION = "0.7.102";
3
3
  /** Backward-compatible registration value for directories that know only sdk_version. */
4
4
  export declare const BROWSER_NODE_SDK_VERSION = "0.7.102";
package/dist/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Browser implementation and IICP SDK-compatibility versions are separate axes.
2
2
  // Keep package.json synchronized with BROWSER_NODE_VERSION; the quality gate
3
3
  // rejects drift. SDK compatibility describes the registration contract only.
4
- export const BROWSER_NODE_VERSION = "0.2.4";
4
+ export const BROWSER_NODE_VERSION = "0.2.6";
5
5
  export const BROWSER_NODE_SDK_COMPATIBILITY_VERSION = "0.7.102";
6
6
  /** Backward-compatible registration value for directories that know only sdk_version. */
7
7
  export const BROWSER_NODE_SDK_VERSION = BROWSER_NODE_SDK_COMPATIBILITY_VERSION;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iicp/web-node",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Browser-native IICP node (consume + serve): discovery-mesh client with mandatory E2E encryption (IICP-CX) + WebLLM provider. Zero-config, ESM.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",