statewire 0.16.0 → 0.17.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.
Files changed (83) hide show
  1. package/README.md +12 -4
  2. package/dist/client/connection.d.ts +5 -1
  3. package/dist/client/connection.d.ts.map +1 -1
  4. package/dist/client/connection.js +19 -4
  5. package/dist/client/connection.js.map +1 -1
  6. package/dist/client/core.d.ts.map +1 -1
  7. package/dist/client/core.js +2 -0
  8. package/dist/client/core.js.map +1 -1
  9. package/dist/client/session.d.ts +15 -4
  10. package/dist/client/session.d.ts.map +1 -1
  11. package/dist/client/session.js +232 -50
  12. package/dist/client/session.js.map +1 -1
  13. package/dist/client/sessionStore.d.ts +5 -1
  14. package/dist/client/sessionStore.d.ts.map +1 -1
  15. package/dist/client/sessionStore.js +3 -1
  16. package/dist/client/sessionStore.js.map +1 -1
  17. package/dist/host/host.d.ts +1 -0
  18. package/dist/host/host.d.ts.map +1 -1
  19. package/dist/host/host.js.map +1 -1
  20. package/dist/host/http.d.ts.map +1 -1
  21. package/dist/host/http.js +27 -9
  22. package/dist/host/http.js.map +1 -1
  23. package/dist/host/socket.d.ts +10 -3
  24. package/dist/host/socket.d.ts.map +1 -1
  25. package/dist/host/socket.js +103 -39
  26. package/dist/host/socket.js.map +1 -1
  27. package/dist/host-internal.d.ts +9 -1
  28. package/dist/host-internal.d.ts.map +1 -1
  29. package/dist/host-internal.js +1 -1
  30. package/dist/index.d.ts +3 -1
  31. package/dist/statewire.d.ts +33 -2
  32. package/dist/statewire.d.ts.map +1 -1
  33. package/dist/statewire.js +34 -3
  34. package/dist/statewire.js.map +1 -1
  35. package/dist/transports/fixtures.js +1 -0
  36. package/dist/transports/fixtures.js.map +1 -1
  37. package/dist/transports/remote.d.ts.map +1 -1
  38. package/dist/transports/remote.js +15 -8
  39. package/dist/transports/remote.js.map +1 -1
  40. package/dist/transports/sse.d.ts.map +1 -1
  41. package/dist/transports/sse.js +8 -8
  42. package/dist/transports/sse.js.map +1 -1
  43. package/dist/transports/testing.d.ts +1 -1
  44. package/dist/transports/testing.d.ts.map +1 -1
  45. package/dist/transports/testing.js +12 -4
  46. package/dist/transports/testing.js.map +1 -1
  47. package/dist/transports/ws.js +2 -2
  48. package/dist/transports/ws.js.map +1 -1
  49. package/dist/types.d.ts +7 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js.map +1 -1
  52. package/dist/wire/documents.d.ts +25 -2
  53. package/dist/wire/documents.d.ts.map +1 -1
  54. package/dist/wire/documents.js +27 -7
  55. package/dist/wire/documents.js.map +1 -1
  56. package/dist/wire/protocol.d.ts +55 -0
  57. package/dist/wire/protocol.d.ts.map +1 -0
  58. package/dist/wire/protocol.js +221 -0
  59. package/dist/wire/protocol.js.map +1 -0
  60. package/dist/wire/version.d.ts +1 -3
  61. package/dist/wire/version.d.ts.map +1 -1
  62. package/dist/wire/version.js +1 -3
  63. package/dist/wire/version.js.map +1 -1
  64. package/package.json +1 -1
  65. package/src/client/connection.ts +43 -13
  66. package/src/client/core.ts +6 -0
  67. package/src/client/session.ts +338 -39
  68. package/src/client/sessionStore.ts +8 -0
  69. package/src/host/host.ts +1 -0
  70. package/src/host/http.ts +36 -7
  71. package/src/host/socket.ts +141 -50
  72. package/src/host-internal.ts +12 -1
  73. package/src/index.ts +3 -0
  74. package/src/statewire.ts +109 -6
  75. package/src/transports/fixtures.ts +1 -1
  76. package/src/transports/remote.ts +16 -7
  77. package/src/transports/sse.ts +18 -8
  78. package/src/transports/testing.ts +10 -2
  79. package/src/transports/ws.ts +1 -1
  80. package/src/types.ts +11 -0
  81. package/src/wire/documents.ts +126 -8
  82. package/src/wire/protocol.ts +327 -0
  83. package/src/wire/version.ts +0 -2
package/dist/types.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { StatewireDocuments } from "./wire/documents.js";
2
+ import { StatewireProtocol } from "./wire/protocol.js";
1
3
  import { StatewireClient } from "./statewire.js";
2
4
  import { StatewirePath } from "./wire/ops.js";
3
5
  //#region src/types.d.ts
@@ -9,6 +11,7 @@ declare namespace Statewire {
9
11
  }; }[keyof TCommands];
10
12
  type CommandsProxy<TCommands extends Commands> = { [K in keyof TCommands]: (...args: Parameters<TCommands[K]>) => Promise<Awaited<ReturnType<TCommands[K]>>>; };
11
13
  type CommandUpdate<TCommands extends Commands = Commands> = { [K in keyof TCommands]: {
14
+ readonly protocol?: string;
12
15
  method: K;
13
16
  params: Parameters<TCommands[K]>;
14
17
  seq: number;
@@ -43,6 +46,10 @@ declare namespace Statewire {
43
46
  }
44
47
  interface Statewire<TState = any, TCommands extends Statewire.Commands = Statewire.Commands> {
45
48
  state: TState;
49
+ documents?: StatewireDocuments.Source;
50
+ selection?: StatewireProtocol.Selection | undefined;
51
+ invoke?: (protocol: string, method: string, params: readonly unknown[]) => Promise<unknown>;
52
+ updateContext?: (ops: readonly unknown[]) => void;
46
53
  commands: Statewire.CommandsProxy<TCommands>;
47
54
  connection?: StatewireClient.Connection;
48
55
  source?: Statewire.StateSource;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;kBAGiB;OACH,WAAW,mBAAmB;OAE9B,QAAQ,kBAAkB,WAAW,eAC9C,WAAW;IAAc,QAAQ;IAAG,QAAQ,WAAW,UAAU;aAC5D;OAEI,cAAc,kBAAkB,eACzC,WAAW,gBACP,MAAM,WAAW,UAAU,QAC3B,QAAQ,QAAQ,WAAW,UAAU;OAGhC,cAAc,kBAAkB,WAAW,eACpD,WAAW;IACV,QAAQ;IACR,QAAQ,WAAW,UAAU;IAC7B;IACA;IACA;IACA,UAAU,gBAAgB;aAEtB;;OAGI;IACV;;IAEA,mBAAmB;;IAEnB,cAAc;;OAGJ;IACN;IAAe,MAAM;IAAe;;IACpC;IAAW,MAAM;IAAe;;IAChC;IAAc,MAAM;;OAEd;IACV,YAAY;IACZ,eAAe;;;UAIF,UACf,cACA,kBAAkB,UAAU,WAAW,UAAU;EAEjD,OAAO;EACP,UAAU,UAAU,cAAc;EAClC,aAAa,gBAAgB;EAC7B,SAAS,UAAU;;EAEnB;;EAEA;EACA;aAAkB;;;EAElB,cAAc,OAAO;;EAErB;IACE,qBAAqB,gBAAgB;IACrC,QAAQ,OAAO,gBAAgB,kBAAkB;IACjD,UAAU,OAAO,gBAAgB;;;cAuBxB,2BAA2B;WAC7B,SAAS,gBAAgB;EAEtB,YAAA,SAAS,gBAAgB"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;kBAKiB;OACH,WAAW,mBAAmB;OAE9B,QAAQ,kBAAkB,WAAW,eAC9C,WAAW;IAAc,QAAQ;IAAG,QAAQ,WAAW,UAAU;aAC5D;OAEI,cAAc,kBAAkB,eACzC,WAAW,gBACP,MAAM,WAAW,UAAU,QAC3B,QAAQ,QAAQ,WAAW,UAAU;OAGhC,cAAc,kBAAkB,WAAW,eACpD,WAAW;aACD;IACT,QAAQ;IACR,QAAQ,WAAW,UAAU;IAC7B;IACA;IACA;IACA,UAAU,gBAAgB;aAEtB;;OAGI;IACV;;IAEA,mBAAmB;;IAEnB,cAAc;;OAGJ;IACN;IAAe,MAAM;IAAe;;IACpC;IAAW,MAAM;IAAe;;IAChC;IAAc,MAAM;;OAEd;IACV,YAAY;IACZ,eAAe;;;UAIF,UACf,cACA,kBAAkB,UAAU,WAAW,UAAU;EAEjD,OAAO;EACP,YAAY,mBAAmB;EAC/B,YAAY,kBAAkB;EAC9B,UACE,kBACA,gBACA,+BACG;EACL,iBAAiB;EACjB,UAAU,UAAU,cAAc;EAClC,aAAa,gBAAgB;EAC7B,SAAS,UAAU;;EAEnB;;EAEA;EACA;aAAkB;;;EAElB,cAAc,OAAO;;EAErB;IACE,qBAAqB,gBAAgB;IACrC,QAAQ,OAAO,gBAAgB,kBAAkB;IACjD,UAAU,OAAO,gBAAgB;;;cAuBxB,2BAA2B;WAC7B,SAAS,gBAAgB;EAEtB,YAAA,SAAS,gBAAgB"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":["StatewireClient","StatewirePath","Statewire","Commands","Record","args","Command","TCommands","method","K","params","Parameters","CommandsProxy","Promise","Awaited","ReturnType","CommandUpdate","seq","status","result","failure","SendFailure","StateSource","snapshot","takeChanged","setOnChange","listener","Op","op","path","value","Changes","isChangedAt","getChangedKeys","state","TState","commands","connection","Connection","source","durableSeq","isBusy","work","isIdle","setContext","failures","list","FailedCommand","retry","entry","discard","describe","fate","code","message","cause","StatewireSendError","Error","constructor","name"],"sources":["../src/types.ts"],"sourcesContent":["import type { StatewireClient } from \"./statewire\";\nimport type { StatewirePath } from \"./wire/ops\";\n\nexport namespace Statewire {\n export type Commands = Record<string, (...args: never[]) => unknown>;\n\n export type Command<TCommands extends Commands = Commands> = {\n [K in keyof TCommands]: { method: K; params: Parameters<TCommands[K]> };\n }[keyof TCommands];\n\n export type CommandsProxy<TCommands extends Commands> = {\n [K in keyof TCommands]: (\n ...args: Parameters<TCommands[K]>\n ) => Promise<Awaited<ReturnType<TCommands[K]>>>;\n };\n\n export type CommandUpdate<TCommands extends Commands = Commands> = {\n [K in keyof TCommands]: {\n method: K;\n params: Parameters<TCommands[K]>;\n seq: number;\n status: \"queued\" | \"posted\" | \"applied\" | \"settled\";\n result?: unknown;\n failure?: StatewireClient.SendFailure;\n };\n }[keyof TCommands];\n\n /** Push-based canonical state feed a statewire hands to the client core. */\n export type StateSource = {\n snapshot: () => unknown;\n /** Drain the paths changed since the last take (`[]` entry = whole state). */\n takeChanged: () => StatewirePath[];\n /** Synchronous, per change; the consumer owns coalescing. */\n setOnChange: (listener: (() => void) | null) => void;\n };\n\n export type Op =\n | { op: \"replace\"; path: StatewirePath; value: unknown }\n | { op: \"add\"; path: StatewirePath; value: unknown }\n | { op: \"remove\"; path: StatewirePath };\n\n export type Changes = {\n isChangedAt(path: readonly (string | number)[]): boolean;\n getChangedKeys(path: readonly (string | number)[]): string[];\n };\n}\n\nexport interface Statewire<\n TState = any,\n TCommands extends Statewire.Commands = Statewire.Commands,\n> {\n state: TState;\n commands: Statewire.CommandsProxy<TCommands>;\n connection?: StatewireClient.Connection;\n source?: Statewire.StateSource;\n /** Highest command seq the server's dur flag states durably admitted — never lost, never run again — and released from the resend queue. */\n durableSeq?: number;\n /** Negation of the server's broadcast idle level; absent means always busy. */\n isBusy?: boolean;\n work?: { readonly isIdle: boolean };\n /** Replace this client's ambient context on the server; it rides the ctx lane (no verdict). */\n setContext?: (value: Record<string, unknown>) => void;\n /** The retained failed-send lane; present on transports with a durable session. */\n failures?: {\n list: () => readonly StatewireClient.FailedCommand[];\n retry: (entry: StatewireClient.FailedCommand) => Promise<unknown>;\n discard: (entry: StatewireClient.FailedCommand) => void;\n };\n}\n\nconst describe = (failure: StatewireClient.SendFailure): string => {\n switch (failure.fate) {\n case \"rejected\":\n return `statewire: command rejected${failure.code ? ` (${failure.code})` : \"\"}${failure.message ? `: ${failure.message}` : \"\"}`;\n case \"aborted\":\n return `statewire: command aborted (${failure.cause})`;\n case \"lost\":\n return `statewire: command lost (${failure.cause})`;\n case \"failed\":\n return failure.message\n ? `statewire: command failed: ${failure.message}`\n : \"statewire: command failed\";\n case \"crashed\":\n return \"statewire: command crashed\";\n case \"expired\":\n return `statewire: command result expired (${failure.cause})`;\n }\n};\n\nexport class StatewireSendError extends Error {\n readonly failure: StatewireClient.SendFailure;\n\n constructor(failure: StatewireClient.SendFailure) {\n super(describe(failure));\n this.name = \"StatewireSendError\";\n this.failure = failure;\n }\n}\n"],"mappings":";AAsEA,MAAMmD,YAAY/B,YAAiD;CACjE,QAAQA,QAAQgC,MAAhB;EACE,KAAK,YACH,OAAO,8BAA8BhC,QAAQiC,OAAO,KAAKjC,QAAQiC,KAAI,KAAM,KAAKjC,QAAQkC,UAAU,KAAKlC,QAAQkC,YAAY;EAC7H,KAAK,WACH,OAAO,+BAA+BlC,QAAQmC,MAAK;EACrD,KAAK,QACH,OAAO,4BAA4BnC,QAAQmC,MAAK;EAClD,KAAK,UACH,OAAOnC,QAAQkC,UACX,8BAA8BlC,QAAQkC,YACtC;EACN,KAAK,WACH,OAAO;EACT,KAAK,WACH,OAAO,sCAAsClC,QAAQmC,MAAK;CAC9D;AACF;AAEA,IAAaC,qBAAb,cAAwCC,MAAM;CAC5C;CAEAC,YAAYtC,SAAsC;EAChD,MAAM+B,SAAS/B,OAAO,CAAC;EACvB,KAAKuC,OAAO;EACZ,KAAKvC,UAAUA;CACjB;AACF"}
1
+ {"version":3,"file":"types.js","names":["StatewireDocuments","StatewireProtocol","StatewireClient","StatewirePath","Statewire","Commands","Record","args","Command","TCommands","method","K","params","Parameters","CommandsProxy","Promise","Awaited","ReturnType","CommandUpdate","protocol","seq","status","result","failure","SendFailure","StateSource","snapshot","takeChanged","setOnChange","listener","Op","op","path","value","Changes","isChangedAt","getChangedKeys","state","TState","documents","Source","selection","Selection","invoke","updateContext","ops","commands","connection","Connection","source","durableSeq","isBusy","work","isIdle","setContext","failures","list","FailedCommand","retry","entry","discard","describe","fate","code","message","cause","StatewireSendError","Error","constructor","name"],"sources":["../src/types.ts"],"sourcesContent":["import type { StatewireDocuments } from \"./wire/documents\";\nimport type { StatewireProtocol } from \"./wire/protocol\";\nimport type { StatewireClient } from \"./statewire\";\nimport type { StatewirePath } from \"./wire/ops\";\n\nexport namespace Statewire {\n export type Commands = Record<string, (...args: never[]) => unknown>;\n\n export type Command<TCommands extends Commands = Commands> = {\n [K in keyof TCommands]: { method: K; params: Parameters<TCommands[K]> };\n }[keyof TCommands];\n\n export type CommandsProxy<TCommands extends Commands> = {\n [K in keyof TCommands]: (\n ...args: Parameters<TCommands[K]>\n ) => Promise<Awaited<ReturnType<TCommands[K]>>>;\n };\n\n export type CommandUpdate<TCommands extends Commands = Commands> = {\n [K in keyof TCommands]: {\n readonly protocol?: string;\n method: K;\n params: Parameters<TCommands[K]>;\n seq: number;\n status: \"queued\" | \"posted\" | \"applied\" | \"settled\";\n result?: unknown;\n failure?: StatewireClient.SendFailure;\n };\n }[keyof TCommands];\n\n /** Push-based canonical state feed a statewire hands to the client core. */\n export type StateSource = {\n snapshot: () => unknown;\n /** Drain the paths changed since the last take (`[]` entry = whole state). */\n takeChanged: () => StatewirePath[];\n /** Synchronous, per change; the consumer owns coalescing. */\n setOnChange: (listener: (() => void) | null) => void;\n };\n\n export type Op =\n | { op: \"replace\"; path: StatewirePath; value: unknown }\n | { op: \"add\"; path: StatewirePath; value: unknown }\n | { op: \"remove\"; path: StatewirePath };\n\n export type Changes = {\n isChangedAt(path: readonly (string | number)[]): boolean;\n getChangedKeys(path: readonly (string | number)[]): string[];\n };\n}\n\nexport interface Statewire<\n TState = any,\n TCommands extends Statewire.Commands = Statewire.Commands,\n> {\n state: TState;\n documents?: StatewireDocuments.Source;\n selection?: StatewireProtocol.Selection | undefined;\n invoke?: (\n protocol: string,\n method: string,\n params: readonly unknown[],\n ) => Promise<unknown>;\n updateContext?: (ops: readonly unknown[]) => void;\n commands: Statewire.CommandsProxy<TCommands>;\n connection?: StatewireClient.Connection;\n source?: Statewire.StateSource;\n /** Highest command seq the server's dur flag states durably admitted — never lost, never run again — and released from the resend queue. */\n durableSeq?: number;\n /** Negation of the server's broadcast idle level; absent means always busy. */\n isBusy?: boolean;\n work?: { readonly isIdle: boolean };\n /** Replace this client's ambient context on the server; it rides the ctx lane (no verdict). */\n setContext?: (value: Record<string, unknown>) => void;\n /** The retained failed-send lane; present on transports with a durable session. */\n failures?: {\n list: () => readonly StatewireClient.FailedCommand[];\n retry: (entry: StatewireClient.FailedCommand) => Promise<unknown>;\n discard: (entry: StatewireClient.FailedCommand) => void;\n };\n}\n\nconst describe = (failure: StatewireClient.SendFailure): string => {\n switch (failure.fate) {\n case \"rejected\":\n return `statewire: command rejected${failure.code ? ` (${failure.code})` : \"\"}${failure.message ? `: ${failure.message}` : \"\"}`;\n case \"aborted\":\n return `statewire: command aborted (${failure.cause})`;\n case \"lost\":\n return `statewire: command lost (${failure.cause})`;\n case \"failed\":\n return failure.message\n ? `statewire: command failed: ${failure.message}`\n : \"statewire: command failed\";\n case \"crashed\":\n return \"statewire: command crashed\";\n case \"expired\":\n return `statewire: command result expired (${failure.cause})`;\n }\n};\n\nexport class StatewireSendError extends Error {\n readonly failure: StatewireClient.SendFailure;\n\n constructor(failure: StatewireClient.SendFailure) {\n super(describe(failure));\n this.name = \"StatewireSendError\";\n this.failure = failure;\n }\n}\n"],"mappings":";AAiFA,MAAM6D,YAAYtC,YAAiD;CACjE,QAAQA,QAAQuC,MAAhB;EACE,KAAK,YACH,OAAO,8BAA8BvC,QAAQwC,OAAO,KAAKxC,QAAQwC,KAAI,KAAM,KAAKxC,QAAQyC,UAAU,KAAKzC,QAAQyC,YAAY;EAC7H,KAAK,WACH,OAAO,+BAA+BzC,QAAQ0C,MAAK;EACrD,KAAK,QACH,OAAO,4BAA4B1C,QAAQ0C,MAAK;EAClD,KAAK,UACH,OAAO1C,QAAQyC,UACX,8BAA8BzC,QAAQyC,YACtC;EACN,KAAK,WACH,OAAO;EACT,KAAK,WACH,OAAO,sCAAsCzC,QAAQ0C,MAAK;CAC9D;AACF;AAEA,IAAaC,qBAAb,cAAwCC,MAAM;CAC5C;CAEAC,YAAY7C,SAAsC;EAChD,MAAMsC,SAAStC,OAAO,CAAC;EACvB,KAAK8C,OAAO;EACZ,KAAK9C,UAAUA;CACjB;AACF"}
@@ -1,8 +1,25 @@
1
1
  import { StatewirePath } from "./ops.js";
2
2
  //#region src/wire/documents.d.ts
3
3
  declare namespace StatewireDocuments {
4
+ type CacheEntry = {
5
+ version: string;
6
+ value: unknown;
7
+ };
8
+ type Storage = {
9
+ namespace?: string;
10
+ load: (identity: readonly string[]) => CacheEntry | undefined;
11
+ save: (identity: readonly string[], entry: CacheEntry) => void;
12
+ subscribe?: (listener: () => void) => () => void;
13
+ };
14
+ type Source = {
15
+ get: (protocol: string, key?: readonly string[], prefix?: readonly string[]) => unknown;
16
+ list: () => ReadonlyMap<number, Document>;
17
+ subscribe: (listener: () => void) => () => void;
18
+ };
4
19
  type Document = {
5
20
  key: readonly string[] | null;
21
+ protocol?: string;
22
+ main?: boolean;
6
23
  value: unknown;
7
24
  };
8
25
  type State = {
@@ -10,11 +27,17 @@ declare namespace StatewireDocuments {
10
27
  documents: ReadonlyMap<number, Document>;
11
28
  };
12
29
  }
13
- declare const applyDocumentOps: (previous: StatewireDocuments.State, ops: readonly unknown[]) => {
30
+ declare const applyDocumentOps: (previous: StatewireDocuments.State, ops: readonly unknown[], protocols?: readonly {
31
+ name: string;
32
+ version: string;
33
+ }[], strict?: boolean) => {
14
34
  mode: "mounted" | "keyless";
15
35
  documents: Map<number, StatewireDocuments.Document>;
16
36
  changedPaths: StatewirePath[];
17
37
  };
38
+ declare const mainDocument: (state: StatewireDocuments.State, protocol: string) => StatewireDocuments.Document | undefined;
39
+ declare const resolveDocumentKey: (key: readonly string[], prefix?: readonly string[]) => readonly string[] | undefined;
40
+ declare const findDocument: (state: StatewireDocuments.State, protocol: string, key?: readonly string[], prefix?: readonly string[]) => StatewireDocuments.Document | undefined;
18
41
  //#endregion
19
- export { StatewireDocuments, applyDocumentOps };
42
+ export { StatewireDocuments, applyDocumentOps, findDocument, mainDocument, resolveDocumentKey };
20
43
  //# sourceMappingURL=documents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"documents.d.ts","names":[],"sources":["../../src/wire/documents.ts"],"mappings":";;kBAIiB;OACH;IAAa;IAA+B;;OAC5C;IACV;IACA,WAAW,oBAAoB;;;cAQtB,mBACX,UAAU,mBAAmB,OAC7B"}
1
+ {"version":3,"file":"documents.d.ts","names":[],"sources":["../../src/wire/documents.ts"],"mappings":";;kBAKiB;OACH;IAAe;IAAiB;;OAChC;IACV;IACA,OAAO,gCAAgC;IACvC,OAAO,6BAA6B,OAAO;IAC3C,aAAa;;OAEH;IACV,MACE,kBACA,yBACA;IAEF,YAAY,oBAAoB;IAChC,YAAY;;OAEF;IACV;IACA;IACA;IACA;;OAEU;IACV;IACA,WAAW,oBAAoB;;;cAQtB,mBACX,UAAU,mBAAmB,OAC7B,yBACA;EAAuB;EAAc;KACrC;;;;;cAqJW,eACX,OAAO,mBAAmB,OAC1B,qBAAgB,mBAAA;cAML,qBACX,wBACA;cAQW,eACX,OAAO,mBAAmB,OAC1B,kBACA,yBACA,+BAA0B,mBAAA"}
@@ -1,11 +1,12 @@
1
+ import { protocolToken } from "./protocol.js";
1
2
  import { applyOps } from "./ops.js";
2
3
  import { reviveValue } from "./meta.js";
3
4
  //#region src/wire/documents.ts
4
5
  const invalid = (message) => {
5
6
  throw new Error(`statewire: protocol error: ${message}`);
6
7
  };
7
- const applyDocumentOps = (previous, ops) => {
8
- let mode = previous.mode;
8
+ const applyDocumentOps = (previous, ops, protocols, strict = false) => {
9
+ let mode = previous.mode ?? (protocols !== void 0 && ops.length === 0 ? "mounted" : null);
9
10
  const documents = new Map(previous.documents);
10
11
  const changedPaths = [];
11
12
  for (const raw of ops) {
@@ -20,10 +21,12 @@ const applyDocumentOps = (previous, ops) => {
20
21
  "replace",
21
22
  "remove"
22
23
  ].includes(op.op)) {
24
+ if (strict) invalid("unknown context operation");
23
25
  const { doc: _doc, ...unknown } = op;
24
26
  applyOps(void 0, [unknown]);
25
27
  continue;
26
28
  }
29
+ if (protocols !== void 0 && mode === null && op.op !== "mount") invalid("negotiated state must start with mounts");
27
30
  if (mode === null) {
28
31
  if (op.op === "mount") mode = "mounted";
29
32
  else if (op.op === "replace" && doc === 0 && Array.isArray(op.path) && op.path.length === 0 && "value" in op) {
@@ -37,22 +40,32 @@ const applyDocumentOps = (previous, ops) => {
37
40
  if (mode === "keyless" && (doc !== 0 || op.op === "mount" || op.op === "unmount")) invalid("keyless mode only supports mutations of document 0");
38
41
  if (op.op === "mount") {
39
42
  if (documents.has(doc)) invalid("document is already mounted");
40
- if (!Array.isArray(op.key) || !op.key.every((key) => typeof key === "string") || !("value" in op)) invalid("mount requires a key array and value");
43
+ if (op.key !== void 0 && (!Array.isArray(op.key) || !op.key.every((key) => typeof key === "string")) || !("value" in op)) invalid("mount requires value and an optional key array");
44
+ if (op.protocol !== void 0 && (typeof op.protocol !== "string" || !protocolToken.test(op.protocol) || op.protocol === "*")) invalid("invalid mount protocol");
45
+ if (protocols !== void 0 && !protocols.some((p) => p.name === op.protocol)) invalid("mount protocol was not negotiated");
46
+ if (op.main !== void 0 && typeof op.main !== "boolean") invalid("main must be boolean");
47
+ if (op.main === true && [...documents.values()].some((d) => d.protocol === op.protocol && d.main)) invalid("protocol already has a main document");
48
+ if (op.key !== void 0 && [...documents.values()].some((d) => d.protocol === op.protocol && JSON.stringify(d.key) === JSON.stringify(op.key))) invalid("protocol document key is already mounted");
41
49
  documents.set(doc, {
42
- key: op.key,
43
- value: op.meta === void 0 ? op.value : reviveValue(op.value, op.meta)
50
+ key: op.key === void 0 ? null : op.key,
51
+ ...op.protocol === void 0 ? {} : { protocol: op.protocol },
52
+ ...op.main === void 0 ? {} : { main: op.main },
53
+ value: op.meta === void 0 ? op.value : reviveValue(op.value, op.meta, { rejectUnknown: strict })
44
54
  });
45
55
  if (doc === 0) changedPaths.push([]);
46
56
  } else if (op.op === "unmount") {
57
+ const document = documents.get(doc);
58
+ if (protocols !== void 0 && document !== void 0 && !protocols.some((p) => p.name === document.protocol)) invalid("document protocol was not negotiated");
47
59
  if (!documents.delete(doc)) invalid("document is not mounted");
48
60
  if (doc === 0) changedPaths.push([]);
49
61
  } else if (op.op === "add" || op.op === "replace" || op.op === "remove") {
50
62
  const document = documents.get(doc);
63
+ if (protocols !== void 0 && document !== void 0 && !protocols.some((p) => p.name === document.protocol)) invalid("document protocol was not negotiated");
51
64
  if (!document) invalid("document is not mounted");
52
65
  if (!Array.isArray(op.path) || !op.path.every((part) => typeof part === "string" || typeof part === "number" && Number.isSafeInteger(part) && part >= 0)) invalid("operation requires a valid path");
53
66
  if (op.op !== "remove" && !("value" in op)) invalid("operation requires a value");
54
67
  const { doc: _doc, meta, ...mutation } = op;
55
- if (meta !== void 0) mutation.value = reviveValue(mutation.value, meta);
68
+ if (meta !== void 0) mutation.value = reviveValue(mutation.value, meta, { rejectUnknown: strict });
56
69
  const applied = applyOps(document.value, [mutation]);
57
70
  documents.set(doc, {
58
71
  ...document,
@@ -68,7 +81,14 @@ const applyDocumentOps = (previous, ops) => {
68
81
  changedPaths
69
82
  };
70
83
  };
84
+ const mainDocument = (state, protocol) => [...state.documents.values()].find((document) => document.protocol === protocol && document.main);
85
+ const resolveDocumentKey = (key, prefix) => key[0] === "." ? prefix === void 0 ? void 0 : [...prefix, ...key.slice(1)] : key;
86
+ const findDocument = (state, protocol, key, prefix) => {
87
+ if (key === void 0) return mainDocument(state, protocol);
88
+ const resolved = resolveDocumentKey(key, prefix);
89
+ return [...state.documents.values()].find((document) => document.protocol === protocol && document.key !== null && (JSON.stringify(document.key) === JSON.stringify(key) || resolved !== void 0 && JSON.stringify(resolveDocumentKey(document.key, prefix)) === JSON.stringify(resolved)));
90
+ };
71
91
  //#endregion
72
- export { applyDocumentOps };
92
+ export { applyDocumentOps, findDocument, mainDocument, resolveDocumentKey };
73
93
 
74
94
  //# sourceMappingURL=documents.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"documents.js","names":["applyOps","reviveValue","StatewirePath","StatewireDocuments","Document","key","value","State","mode","documents","ReadonlyMap","invalid","message","Error","applyDocumentOps","previous","ops","Map","changedPaths","raw","Array","isArray","op","Record","doc","undefined","Number","isSafeInteger","includes","_doc","unknown","path","length","set","has","every","meta","push","delete","document","get","part","mutation","applied","state"],"sources":["../../src/wire/documents.ts"],"sourcesContent":["import { applyOps } from \"./ops\";\nimport { reviveValue } from \"./meta\";\nimport type { StatewirePath } from \"./ops\";\n\nexport namespace StatewireDocuments {\n export type Document = { key: readonly string[] | null; value: unknown };\n export type State = {\n mode: \"mounted\" | \"keyless\" | null;\n documents: ReadonlyMap<number, Document>;\n };\n}\n\nconst invalid: (message: string) => never = (message) => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nexport const applyDocumentOps = (\n previous: StatewireDocuments.State,\n ops: readonly unknown[],\n) => {\n let mode = previous.mode;\n const documents = new Map(previous.documents);\n const changedPaths: StatewirePath[] = [];\n for (const raw of ops) {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n invalid(\"operation must be an object\");\n }\n const op = raw as Record<string, unknown>;\n const doc = op.doc === undefined ? 0 : op.doc;\n if (typeof doc !== \"number\" || !Number.isSafeInteger(doc) || doc < 0) {\n invalid(\"doc must be a nonnegative safe integer\");\n }\n if (\n ![\"mount\", \"unmount\", \"add\", \"replace\", \"remove\"].includes(\n op.op as string,\n )\n ) {\n const { doc: _doc, ...unknown } = op;\n applyOps(undefined, [unknown]);\n continue;\n }\n if (mode === null) {\n if (op.op === \"mount\") mode = \"mounted\";\n else if (\n op.op === \"replace\" &&\n doc === 0 &&\n Array.isArray(op.path) &&\n op.path.length === 0 &&\n \"value\" in op\n ) {\n mode = \"keyless\";\n documents.set(0, { key: null, value: undefined });\n } else\n invalid(\n \"first operation must mount a document or replace document 0 at the root\",\n );\n }\n if (\n mode === \"keyless\" &&\n (doc !== 0 || op.op === \"mount\" || op.op === \"unmount\")\n ) {\n invalid(\"keyless mode only supports mutations of document 0\");\n }\n if (op.op === \"mount\") {\n if (documents.has(doc)) invalid(\"document is already mounted\");\n if (\n !Array.isArray(op.key) ||\n !op.key.every((key) => typeof key === \"string\") ||\n !(\"value\" in op)\n ) {\n invalid(\"mount requires a key array and value\");\n }\n documents.set(doc, {\n key: op.key,\n value:\n op.meta === undefined ? op.value : reviveValue(op.value, op.meta),\n });\n if (doc === 0) changedPaths.push([]);\n } else if (op.op === \"unmount\") {\n if (!documents.delete(doc)) invalid(\"document is not mounted\");\n if (doc === 0) changedPaths.push([]);\n } else if (op.op === \"add\" || op.op === \"replace\" || op.op === \"remove\") {\n const document = documents.get(doc);\n if (!document) invalid(\"document is not mounted\");\n if (\n !Array.isArray(op.path) ||\n !op.path.every(\n (part) =>\n typeof part === \"string\" ||\n (typeof part === \"number\" &&\n Number.isSafeInteger(part) &&\n part >= 0),\n )\n ) {\n invalid(\"operation requires a valid path\");\n }\n if (op.op !== \"remove\" && !(\"value\" in op))\n invalid(\"operation requires a value\");\n const { doc: _doc, meta, ...mutation } = op;\n if (meta !== undefined)\n mutation.value = reviveValue(mutation.value, meta);\n const applied = applyOps(document.value, [mutation]);\n documents.set(doc, { ...document, value: applied.state });\n if (doc === 0) changedPaths.push(...applied.changedPaths);\n }\n }\n if (mode === null) invalid(\"hello missing snapshot\");\n return { mode, documents, changedPaths };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"documents.js","names":["applyOps","reviveValue","protocolToken","StatewirePath","StatewireDocuments","CacheEntry","version","value","Storage","namespace","load","identity","save","entry","subscribe","listener","Source","get","protocol","key","prefix","list","ReadonlyMap","Document","main","State","mode","documents","invalid","message","Error","applyDocumentOps","previous","ops","protocols","name","strict","undefined","length","Map","changedPaths","raw","Array","isArray","op","Record","doc","Number","isSafeInteger","includes","_doc","unknown","path","set","has","every","test","some","p","values","d","JSON","stringify","meta","rejectUnknown","push","document","delete","part","mutation","applied","state","mainDocument","find","resolveDocumentKey","slice","findDocument","resolved"],"sources":["../../src/wire/documents.ts"],"sourcesContent":["import { applyOps } from \"./ops\";\nimport { reviveValue } from \"./meta\";\nimport { protocolToken } from \"./protocol\";\nimport type { StatewirePath } from \"./ops\";\n\nexport namespace StatewireDocuments {\n export type CacheEntry = { version: string; value: unknown };\n export type Storage = {\n namespace?: string;\n load: (identity: readonly string[]) => CacheEntry | undefined;\n save: (identity: readonly string[], entry: CacheEntry) => void;\n subscribe?: (listener: () => void) => () => void;\n };\n export type Source = {\n get: (\n protocol: string,\n key?: readonly string[],\n prefix?: readonly string[],\n ) => unknown;\n list: () => ReadonlyMap<number, Document>;\n subscribe: (listener: () => void) => () => void;\n };\n export type Document = {\n key: readonly string[] | null;\n protocol?: string;\n main?: boolean;\n value: unknown;\n };\n export type State = {\n mode: \"mounted\" | \"keyless\" | null;\n documents: ReadonlyMap<number, Document>;\n };\n}\n\nconst invalid: (message: string) => never = (message) => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nexport const applyDocumentOps = (\n previous: StatewireDocuments.State,\n ops: readonly unknown[],\n protocols?: readonly { name: string; version: string }[],\n strict = false,\n) => {\n let mode =\n previous.mode ??\n (protocols !== undefined && ops.length === 0 ? \"mounted\" : null);\n const documents = new Map(previous.documents);\n const changedPaths: StatewirePath[] = [];\n for (const raw of ops) {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n invalid(\"operation must be an object\");\n }\n const op = raw as Record<string, unknown>;\n const doc = op.doc === undefined ? 0 : op.doc;\n if (typeof doc !== \"number\" || !Number.isSafeInteger(doc) || doc < 0) {\n invalid(\"doc must be a nonnegative safe integer\");\n }\n if (\n ![\"mount\", \"unmount\", \"add\", \"replace\", \"remove\"].includes(\n op.op as string,\n )\n ) {\n if (strict) invalid(\"unknown context operation\");\n const { doc: _doc, ...unknown } = op;\n applyOps(undefined, [unknown]);\n continue;\n }\n if (protocols !== undefined && mode === null && op.op !== \"mount\")\n invalid(\"negotiated state must start with mounts\");\n if (mode === null) {\n if (op.op === \"mount\") mode = \"mounted\";\n else if (\n op.op === \"replace\" &&\n doc === 0 &&\n Array.isArray(op.path) &&\n op.path.length === 0 &&\n \"value\" in op\n ) {\n mode = \"keyless\";\n documents.set(0, { key: null, value: undefined });\n } else\n invalid(\n \"first operation must mount a document or replace document 0 at the root\",\n );\n }\n if (\n mode === \"keyless\" &&\n (doc !== 0 || op.op === \"mount\" || op.op === \"unmount\")\n ) {\n invalid(\"keyless mode only supports mutations of document 0\");\n }\n if (op.op === \"mount\") {\n if (documents.has(doc)) invalid(\"document is already mounted\");\n if (\n (op.key !== undefined &&\n (!Array.isArray(op.key) ||\n !op.key.every((key) => typeof key === \"string\"))) ||\n !(\"value\" in op)\n ) {\n invalid(\"mount requires value and an optional key array\");\n }\n if (\n op.protocol !== undefined &&\n (typeof op.protocol !== \"string\" ||\n !protocolToken.test(op.protocol) ||\n op.protocol === \"*\")\n )\n invalid(\"invalid mount protocol\");\n if (\n protocols !== undefined &&\n !protocols.some((p) => p.name === op.protocol)\n )\n invalid(\"mount protocol was not negotiated\");\n if (op.main !== undefined && typeof op.main !== \"boolean\")\n invalid(\"main must be boolean\");\n if (\n op.main === true &&\n [...documents.values()].some(\n (d) => d.protocol === op.protocol && d.main,\n )\n )\n invalid(\"protocol already has a main document\");\n if (\n op.key !== undefined &&\n [...documents.values()].some(\n (d) =>\n d.protocol === op.protocol &&\n JSON.stringify(d.key) === JSON.stringify(op.key),\n )\n )\n invalid(\"protocol document key is already mounted\");\n documents.set(doc, {\n key: op.key === undefined ? null : (op.key as string[]),\n ...(op.protocol === undefined\n ? {}\n : { protocol: op.protocol as string }),\n ...(op.main === undefined ? {} : { main: op.main as boolean }),\n value:\n op.meta === undefined\n ? op.value\n : reviveValue(op.value, op.meta, { rejectUnknown: strict }),\n });\n if (doc === 0) changedPaths.push([]);\n } else if (op.op === \"unmount\") {\n const document = documents.get(doc);\n if (\n protocols !== undefined &&\n document !== undefined &&\n !protocols.some((p) => p.name === document.protocol)\n )\n invalid(\"document protocol was not negotiated\");\n if (!documents.delete(doc)) invalid(\"document is not mounted\");\n if (doc === 0) changedPaths.push([]);\n } else if (op.op === \"add\" || op.op === \"replace\" || op.op === \"remove\") {\n const document = documents.get(doc);\n if (\n protocols !== undefined &&\n document !== undefined &&\n !protocols.some((p) => p.name === document.protocol)\n )\n invalid(\"document protocol was not negotiated\");\n if (!document) invalid(\"document is not mounted\");\n if (\n !Array.isArray(op.path) ||\n !op.path.every(\n (part) =>\n typeof part === \"string\" ||\n (typeof part === \"number\" &&\n Number.isSafeInteger(part) &&\n part >= 0),\n )\n ) {\n invalid(\"operation requires a valid path\");\n }\n if (op.op !== \"remove\" && !(\"value\" in op))\n invalid(\"operation requires a value\");\n const { doc: _doc, meta, ...mutation } = op;\n if (meta !== undefined)\n mutation.value = reviveValue(mutation.value, meta, {\n rejectUnknown: strict,\n });\n const applied = applyOps(document.value, [mutation]);\n documents.set(doc, { ...document, value: applied.state });\n if (doc === 0) changedPaths.push(...applied.changedPaths);\n }\n }\n if (mode === null) invalid(\"hello missing snapshot\");\n return { mode, documents, changedPaths };\n};\n\nexport const mainDocument = (\n state: StatewireDocuments.State,\n protocol: string,\n) =>\n [...state.documents.values()].find(\n (document) => document.protocol === protocol && document.main,\n );\n\nexport const resolveDocumentKey = (\n key: readonly string[],\n prefix?: readonly string[],\n) =>\n key[0] === \".\"\n ? prefix === undefined\n ? undefined\n : [...prefix, ...key.slice(1)]\n : key;\n\nexport const findDocument = (\n state: StatewireDocuments.State,\n protocol: string,\n key?: readonly string[],\n prefix?: readonly string[],\n) => {\n if (key === undefined) return mainDocument(state, protocol);\n const resolved = resolveDocumentKey(key, prefix);\n return [...state.documents.values()].find(\n (document) =>\n document.protocol === protocol &&\n document.key !== null &&\n (JSON.stringify(document.key) === JSON.stringify(key) ||\n (resolved !== undefined &&\n JSON.stringify(resolveDocumentKey(document.key, prefix)) ===\n JSON.stringify(resolved))),\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ //#region src/wire/protocol.d.ts
2
+ declare namespace StatewireProtocol {
3
+ type Range = {
4
+ version: string;
5
+ minVersion?: string;
6
+ };
7
+ type Offer = Range & {
8
+ name: string;
9
+ optional?: boolean;
10
+ };
11
+ type Selection = {
12
+ version: string;
13
+ protocols: {
14
+ name: string;
15
+ version: string;
16
+ }[];
17
+ };
18
+ type Options = {
19
+ wireVersion?: Range;
20
+ applicationProtocols?: readonly Offer[] | "*";
21
+ protocol?: string;
22
+ keyPrefixes?: Readonly<Record<string, readonly string[]>>;
23
+ };
24
+ type Definition = Range & {
25
+ name: string;
26
+ requires?: Readonly<Record<string, Range>>;
27
+ };
28
+ }
29
+ declare const WIRE_VERSION = "2026-09-07";
30
+ declare const DEFAULT_PROTOCOL = "default";
31
+ declare const PROTOCOL_HEADER = "Statewire-Protocol";
32
+ declare const VERSION_HEADER = "Statewire-Version";
33
+ declare const protocolToken: RegExp;
34
+ declare const validateVersion: (value: unknown) => string;
35
+ declare const validateRange: (range: StatewireProtocol.Range) => {
36
+ version: string;
37
+ minVersion: string;
38
+ };
39
+ declare const inRange: (value: string, range: StatewireProtocol.Range) => boolean;
40
+ declare const protocolOffers: (options: StatewireProtocol.Options) => readonly StatewireProtocol.Offer[] | "*";
41
+ declare const negotiationHeaders: (options: StatewireProtocol.Options) => Record<string, string>;
42
+ declare const parseNegotiation: (headers: Headers) => Required<Pick<StatewireProtocol.Options, "wireVersion" | "applicationProtocols">>;
43
+ declare const validateSelection: (value: unknown, options: StatewireProtocol.Options) => StatewireProtocol.Selection;
44
+ declare const negotiateProtocols: (headers: Headers, wire: StatewireProtocol.Range, definitions: readonly StatewireProtocol.Definition[]) => StatewireProtocol.Selection | {
45
+ fin: {
46
+ reason: "protocol-error";
47
+ code: string;
48
+ status: number;
49
+ message: string;
50
+ payload?: unknown;
51
+ };
52
+ };
53
+ //#endregion
54
+ export { DEFAULT_PROTOCOL, PROTOCOL_HEADER, StatewireProtocol, VERSION_HEADER, WIRE_VERSION, inRange, negotiateProtocols, negotiationHeaders, parseNegotiation, protocolOffers, protocolToken, validateRange, validateSelection, validateVersion };
55
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","names":[],"sources":["../../src/wire/protocol.ts"],"mappings":";kBAAiB;OACH;IAAU;IAAiB;;OAC3B,QAAQ;IAAU;IAAc;;OAChC;IACV;IACA;MAAa;MAAc;;;OAEjB;IACV,cAAc;IACd,gCAAgC;IAChC;IACA,cAAc,SAAS;;OAEb,aAAa;IACvB;IACA,WAAW,SAAS,eAAe;;;cAI1B;cACA;cACA;cACA;cACA,eAAa;cAMb,kBAAmB;cAanB,gBAAiB,OAAO,kBAAkB;;;;cAU1C,UAAW,eAAe,OAAO,kBAAkB;cAKnD,iBAAkB,SAAS,kBAAkB,qBAAO,kBAAA;cAKpD,qBACX,SAAS,kBAAkB,YAC1B;cA6DU,mBACX,SAAS,YACR,SACD,KAAK,kBAAkB;cA0DZ,oBACX,gBACA,SAAS,kBAAkB,YAC1B,kBAAkB;cAqCR,qBACX,SAAS,SACT,MAAM,kBAAkB,OACxB,sBAAsB,kBAAkB,iBAEtC,kBAAkB;EAEhB;IACE;IACA;IACA;IACA;IACA"}
@@ -0,0 +1,221 @@
1
+ //#region src/wire/protocol.ts
2
+ const WIRE_VERSION = "2026-09-07";
3
+ const DEFAULT_PROTOCOL = "default";
4
+ const PROTOCOL_HEADER = "Statewire-Protocol";
5
+ const VERSION_HEADER = "Statewire-Version";
6
+ const protocolToken = /^[A-Za-z*][A-Za-z0-9!#$%&'*+.^_`|~:/-]*$/;
7
+ const invalid = (message) => {
8
+ throw new Error(`statewire: protocol error: ${message}`);
9
+ };
10
+ const validateVersion = (value) => {
11
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return invalid("version must be a YYYY-MM-DD date");
12
+ const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00.000Z`);
13
+ if (!Number.isFinite(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== value || value.startsWith("0000")) return invalid("invalid version date");
14
+ return value;
15
+ };
16
+ const validateRange = (range) => {
17
+ const version = validateVersion(range.version);
18
+ const minVersion = range.minVersion === void 0 ? version : validateVersion(range.minVersion);
19
+ if (minVersion > version) invalid("min-version exceeds version");
20
+ return {
21
+ version,
22
+ minVersion
23
+ };
24
+ };
25
+ const inRange = (value, range) => {
26
+ const checked = validateRange(range);
27
+ return value >= checked.minVersion && value <= checked.version;
28
+ };
29
+ const protocolOffers = (options) => options.applicationProtocols ?? [{
30
+ name: options.protocol ?? "default",
31
+ version: "2026-09-07"
32
+ }];
33
+ const negotiationHeaders = (options) => {
34
+ const suffix = (range) => {
35
+ const { version, minVersion } = validateRange(range);
36
+ return `"${version}"${minVersion === version ? "" : `; min-version="${minVersion}"`}`;
37
+ };
38
+ const offers = protocolOffers(options);
39
+ const seen = /* @__PURE__ */ new Set();
40
+ if (offers !== "*" && !offers.length) invalid("protocol list must not be empty");
41
+ return {
42
+ [VERSION_HEADER]: suffix(options.wireVersion ?? { version: "2026-09-07" }),
43
+ [PROTOCOL_HEADER]: offers === "*" ? "*" : offers.map((offer) => {
44
+ if (!protocolToken.test(offer.name) || offer.name === "*" || seen.has(offer.name)) invalid("invalid or duplicate protocol name");
45
+ if (offer.optional !== void 0 && typeof offer.optional !== "boolean") invalid("optional must be boolean");
46
+ seen.add(offer.name);
47
+ return `${offer.name}; version=${suffix(offer)}${offer.optional ? "; optional" : ""}`;
48
+ }).join(", ")
49
+ };
50
+ };
51
+ const parseItem = (input) => {
52
+ const atom = String.raw`"(?:[\x20-\x21\x23-\x5b\x5d-\x7e]|\\["\\])*"|[A-Za-z*][A-Za-z0-9!#$%&'*+.^_\x60|~:/-]*|\?[01]`;
53
+ const text = input.trim();
54
+ const match = new RegExp(`^(?:${atom})`).exec(text);
55
+ if (!match) return invalid("invalid structured item");
56
+ const quoted = match[0].startsWith("\"");
57
+ const decode = (raw) => raw.slice(1, -1).replace(/\\(["\\])/g, "$1");
58
+ const value = quoted ? decode(match[0]) : match[0];
59
+ const params = /* @__PURE__ */ new Map();
60
+ let rest = text.slice(match[0].length);
61
+ while (rest) {
62
+ const parameter = new RegExp(`^; *([a-z*][a-z0-9_.*-]*)(?:=(${atom}))?`).exec(rest);
63
+ if (!parameter) return invalid("invalid structured parameters");
64
+ const key = parameter[1];
65
+ const raw = parameter[2];
66
+ if (params.has(key)) invalid("duplicate parameter");
67
+ if (raw === void 0 || raw === "?1") params.set(key, true);
68
+ else if (raw === "?0") params.set(key, false);
69
+ else if (raw.startsWith("\"")) params.set(key, decode(raw));
70
+ else invalid("parameter must be string or boolean");
71
+ rest = rest.slice(parameter[0].length);
72
+ }
73
+ return {
74
+ value,
75
+ quoted,
76
+ params
77
+ };
78
+ };
79
+ const parseNegotiation = (headers) => {
80
+ const wire = headers.get(VERSION_HEADER);
81
+ const application = headers.get(PROTOCOL_HEADER);
82
+ if (wire === null || application === null) return invalid("negotiation fields are required");
83
+ const item = parseItem(wire);
84
+ if (!item.quoted || [...item.params.keys()].some((k) => k !== "min-version")) invalid("invalid Statewire-Version");
85
+ const minVersion = item.params.get("min-version");
86
+ if (minVersion !== void 0 && typeof minVersion !== "string") return invalid("min-version must be a string");
87
+ const wireVersion = validateRange({
88
+ version: item.value,
89
+ ...minVersion === void 0 ? {} : { minVersion }
90
+ });
91
+ if (application.trim() === "*") return {
92
+ wireVersion,
93
+ applicationProtocols: "*"
94
+ };
95
+ const names = /* @__PURE__ */ new Set();
96
+ return {
97
+ wireVersion,
98
+ applicationProtocols: application.split(",").map((text) => {
99
+ const { value: name, quoted, params } = parseItem(text);
100
+ if (quoted || !protocolToken.test(name) || name === "*" || names.has(name)) invalid("invalid or duplicate protocol name");
101
+ names.add(name);
102
+ if ([...params.keys()].some((k) => ![
103
+ "version",
104
+ "min-version",
105
+ "optional"
106
+ ].includes(k))) invalid("unsupported parameter");
107
+ const version = params.get("version");
108
+ const minVersion = params.get("min-version");
109
+ const optional = params.get("optional") ?? false;
110
+ if (typeof version !== "string" || minVersion !== void 0 && typeof minVersion !== "string" || typeof optional !== "boolean") return invalid("invalid protocol parameters");
111
+ return {
112
+ name,
113
+ ...validateRange({
114
+ version,
115
+ ...minVersion === void 0 ? {} : { minVersion }
116
+ }),
117
+ optional
118
+ };
119
+ })
120
+ };
121
+ };
122
+ const validateSelection = (value, options) => {
123
+ if (typeof value !== "object" || value === null) return invalid("missing negotiation selection");
124
+ const syn = value;
125
+ const version = validateVersion(syn.version);
126
+ if (!inRange(version, options.wireVersion ?? { version: "2026-09-07" })) invalid("selected wire version is outside offer");
127
+ if (!Array.isArray(syn.protocols)) return invalid("syn.protocols must be an array");
128
+ const offers = protocolOffers(options);
129
+ const seen = /* @__PURE__ */ new Set();
130
+ const protocols = syn.protocols.map((entry) => {
131
+ if (typeof entry !== "object" || entry === null) return invalid("invalid selected protocol");
132
+ const item = entry;
133
+ const name = item.name;
134
+ if (typeof name !== "string" || !protocolToken.test(name) || name === "*" || seen.has(name)) return invalid("invalid selected protocol name");
135
+ const version = validateVersion(item.version);
136
+ seen.add(name);
137
+ if (offers !== "*") {
138
+ const offer = offers.find((o) => o.name === name);
139
+ if (!offer || !inRange(version, offer)) invalid("selected protocol is outside offer");
140
+ }
141
+ return {
142
+ name,
143
+ version
144
+ };
145
+ });
146
+ if (offers !== "*" && offers.some((o) => !o.optional && !seen.has(o.name))) invalid("required protocol missing from selection");
147
+ return {
148
+ version,
149
+ protocols
150
+ };
151
+ };
152
+ const negotiateProtocols = (headers, wire, definitions) => {
153
+ const supported = {
154
+ ...validateRange(wire),
155
+ protocols: definitions.map((d) => ({
156
+ name: d.name,
157
+ ...validateRange(d)
158
+ }))
159
+ };
160
+ const failure = (code, message) => ({ fin: {
161
+ reason: "protocol-error",
162
+ code,
163
+ message,
164
+ status: code === "invalid-negotiation" ? 400 : 406,
165
+ ...code === "invalid-negotiation" ? {} : { payload: supported }
166
+ } });
167
+ let request;
168
+ try {
169
+ request = parseNegotiation(headers);
170
+ } catch (error) {
171
+ return failure("invalid-negotiation", error instanceof Error ? error.message : "invalid negotiation");
172
+ }
173
+ const version = [wire.version, request.wireVersion.version].sort()[0];
174
+ if (!inRange(version, wire) || !inRange(version, request.wireVersion)) return failure("unsupported-version", "Statewire versions do not overlap");
175
+ const offers = request.applicationProtocols === "*" ? definitions.map((d) => ({
176
+ name: d.name,
177
+ version: d.version,
178
+ optional: false
179
+ })) : request.applicationProtocols;
180
+ const registry = new Map(definitions.map((d) => [d.name, d]));
181
+ if (registry.size !== definitions.length) throw new Error("statewire: duplicate registered protocol");
182
+ const offered = new Map(offers.map((o) => [o.name, o]));
183
+ const solve = (names) => {
184
+ const active = new Set(names);
185
+ for (const name of active) {
186
+ const definition = registry.get(name);
187
+ if (!definition || !offered.has(name)) return void 0;
188
+ for (const dependency of Object.keys(definition.requires ?? {})) active.add(dependency);
189
+ }
190
+ const result = /* @__PURE__ */ new Map();
191
+ for (const name of active) {
192
+ const ranges = [
193
+ registry.get(name),
194
+ offered.get(name),
195
+ ...[...active].flatMap((parent) => {
196
+ const dependency = registry.get(parent).requires?.[name];
197
+ return dependency ? [dependency] : [];
198
+ })
199
+ ].map(validateRange);
200
+ const lower = ranges.map((r) => r.minVersion).sort().at(-1);
201
+ const upper = ranges.map((r) => r.version).sort()[0];
202
+ if (lower > upper) return void 0;
203
+ result.set(name, upper);
204
+ }
205
+ return result;
206
+ };
207
+ let selected = solve(new Set(offers.filter((o) => !o.optional).map((o) => o.name)));
208
+ if (!selected) return failure("unsupported-protocol", "required protocol combination is unsupported");
209
+ for (const offer of offers) if (offer.optional) selected = solve(/* @__PURE__ */ new Set([...selected.keys(), offer.name])) ?? selected;
210
+ return {
211
+ version,
212
+ protocols: offers.flatMap((o) => selected.has(o.name) ? [{
213
+ name: o.name,
214
+ version: selected.get(o.name)
215
+ }] : [])
216
+ };
217
+ };
218
+ //#endregion
219
+ export { DEFAULT_PROTOCOL, PROTOCOL_HEADER, VERSION_HEADER, WIRE_VERSION, inRange, negotiateProtocols, negotiationHeaders, parseNegotiation, protocolOffers, protocolToken, validateRange, validateSelection, validateVersion };
220
+
221
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","names":["StatewireProtocol","Range","version","minVersion","Offer","name","optional","Selection","protocols","Options","wireVersion","applicationProtocols","protocol","keyPrefixes","Readonly","Record","Definition","requires","WIRE_VERSION","DEFAULT_PROTOCOL","PROTOCOL_HEADER","VERSION_HEADER","protocolToken","invalid","message","Error","validateVersion","value","test","parsed","Date","Number","isFinite","getTime","toISOString","slice","startsWith","validateRange","range","undefined","inRange","checked","protocolOffers","options","negotiationHeaders","suffix","offers","seen","Set","length","map","offer","has","add","join","parseItem","input","atom","String","raw","text","trim","match","RegExp","exec","quoted","decode","replace","params","Map","rest","parameter","key","set","parseNegotiation","headers","Headers","Required","Pick","wire","get","application","item","keys","some","k","names","split","includes","validateSelection","syn","Array","isArray","entry","find","o","negotiateProtocols","definitions","fin","reason","code","status","payload","supported","d","failure","const","request","ReturnType","error","sort","registry","size","offered","solve","active","definition","dependency","Object","result","ranges","flatMap","parent","lower","r","at","upper","selected","filter"],"sources":["../../src/wire/protocol.ts"],"sourcesContent":["export namespace StatewireProtocol {\n export type Range = { version: string; minVersion?: string };\n export type Offer = Range & { name: string; optional?: boolean };\n export type Selection = {\n version: string;\n protocols: { name: string; version: string }[];\n };\n export type Options = {\n wireVersion?: Range;\n applicationProtocols?: readonly Offer[] | \"*\";\n protocol?: string;\n keyPrefixes?: Readonly<Record<string, readonly string[]>>;\n };\n export type Definition = Range & {\n name: string;\n requires?: Readonly<Record<string, Range>>;\n };\n}\n\nexport const WIRE_VERSION = \"2026-09-07\";\nexport const DEFAULT_PROTOCOL = \"default\";\nexport const PROTOCOL_HEADER = \"Statewire-Protocol\";\nexport const VERSION_HEADER = \"Statewire-Version\";\nexport const protocolToken = /^[A-Za-z*][A-Za-z0-9!#$%&'*+.^_`|~:/-]*$/;\n\nconst invalid = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nexport const validateVersion = (value: unknown): string => {\n if (typeof value !== \"string\" || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value))\n return invalid(\"version must be a YYYY-MM-DD date\");\n const parsed = new Date(`${value}T00:00:00.000Z`);\n if (\n !Number.isFinite(parsed.getTime()) ||\n parsed.toISOString().slice(0, 10) !== value ||\n value.startsWith(\"0000\")\n )\n return invalid(\"invalid version date\");\n return value;\n};\n\nexport const validateRange = (range: StatewireProtocol.Range) => {\n const version = validateVersion(range.version);\n const minVersion =\n range.minVersion === undefined\n ? version\n : validateVersion(range.minVersion);\n if (minVersion > version) invalid(\"min-version exceeds version\");\n return { version, minVersion };\n};\n\nexport const inRange = (value: string, range: StatewireProtocol.Range) => {\n const checked = validateRange(range);\n return value >= checked.minVersion && value <= checked.version;\n};\n\nexport const protocolOffers = (options: StatewireProtocol.Options) =>\n options.applicationProtocols ?? [\n { name: options.protocol ?? DEFAULT_PROTOCOL, version: WIRE_VERSION },\n ];\n\nexport const negotiationHeaders = (\n options: StatewireProtocol.Options,\n): Record<string, string> => {\n const suffix = (range: StatewireProtocol.Range) => {\n const { version, minVersion } = validateRange(range);\n return `\"${version}\"${minVersion === version ? \"\" : `; min-version=\"${minVersion}\"`}`;\n };\n const offers = protocolOffers(options);\n const seen = new Set<string>();\n if (offers !== \"*\" && !offers.length)\n invalid(\"protocol list must not be empty\");\n return {\n [VERSION_HEADER]: suffix(options.wireVersion ?? { version: WIRE_VERSION }),\n [PROTOCOL_HEADER]:\n offers === \"*\"\n ? \"*\"\n : offers\n .map((offer) => {\n if (\n !protocolToken.test(offer.name) ||\n offer.name === \"*\" ||\n seen.has(offer.name)\n )\n invalid(\"invalid or duplicate protocol name\");\n if (\n offer.optional !== undefined &&\n typeof offer.optional !== \"boolean\"\n )\n invalid(\"optional must be boolean\");\n seen.add(offer.name);\n return `${offer.name}; version=${suffix(offer)}${offer.optional ? \"; optional\" : \"\"}`;\n })\n .join(\", \"),\n };\n};\n\nconst parseItem = (input: string) => {\n const atom = String.raw`\"(?:[\\x20-\\x21\\x23-\\x5b\\x5d-\\x7e]|\\\\[\"\\\\])*\"|[A-Za-z*][A-Za-z0-9!#$%&'*+.^_\\x60|~:/-]*|\\?[01]`;\n const text = input.trim();\n const match = new RegExp(`^(?:${atom})`).exec(text);\n if (!match) return invalid(\"invalid structured item\");\n const quoted = match[0].startsWith('\"');\n const decode = (raw: string) => raw.slice(1, -1).replace(/\\\\([\"\\\\])/g, \"$1\");\n const value = quoted ? decode(match[0]) : match[0];\n const params = new Map<string, string | boolean>();\n let rest = text.slice(match[0].length);\n while (rest) {\n const parameter = new RegExp(\n `^; *([a-z*][a-z0-9_.*-]*)(?:=(${atom}))?`,\n ).exec(rest);\n if (!parameter) return invalid(\"invalid structured parameters\");\n const key = parameter[1]!;\n const raw = parameter[2];\n if (params.has(key)) invalid(\"duplicate parameter\");\n if (raw === undefined || raw === \"?1\") params.set(key, true);\n else if (raw === \"?0\") params.set(key, false);\n else if (raw.startsWith('\"')) params.set(key, decode(raw));\n else invalid(\"parameter must be string or boolean\");\n rest = rest.slice(parameter[0].length);\n }\n return { value, quoted, params };\n};\n\nexport const parseNegotiation = (\n headers: Headers,\n): Required<\n Pick<StatewireProtocol.Options, \"wireVersion\" | \"applicationProtocols\">\n> => {\n const wire = headers.get(VERSION_HEADER);\n const application = headers.get(PROTOCOL_HEADER);\n if (wire === null || application === null)\n return invalid(\"negotiation fields are required\");\n const item = parseItem(wire);\n if (!item.quoted || [...item.params.keys()].some((k) => k !== \"min-version\"))\n invalid(\"invalid Statewire-Version\");\n const minVersion = item.params.get(\"min-version\");\n if (minVersion !== undefined && typeof minVersion !== \"string\")\n return invalid(\"min-version must be a string\");\n const wireVersion = validateRange({\n version: item.value,\n ...(minVersion === undefined ? {} : { minVersion }),\n });\n if (application.trim() === \"*\")\n return { wireVersion, applicationProtocols: \"*\" };\n const names = new Set<string>();\n const applicationProtocols = application\n .split(\",\")\n .map((text): StatewireProtocol.Offer => {\n const { value: name, quoted, params } = parseItem(text);\n if (\n quoted ||\n !protocolToken.test(name) ||\n name === \"*\" ||\n names.has(name)\n )\n invalid(\"invalid or duplicate protocol name\");\n names.add(name);\n if (\n [...params.keys()].some(\n (k) => ![\"version\", \"min-version\", \"optional\"].includes(k),\n )\n )\n invalid(\"unsupported parameter\");\n const version = params.get(\"version\");\n const minVersion = params.get(\"min-version\");\n const optional = params.get(\"optional\") ?? false;\n if (\n typeof version !== \"string\" ||\n (minVersion !== undefined && typeof minVersion !== \"string\") ||\n typeof optional !== \"boolean\"\n )\n return invalid(\"invalid protocol parameters\");\n return {\n name,\n ...validateRange({\n version,\n ...(minVersion === undefined ? {} : { minVersion }),\n }),\n optional,\n };\n });\n return { wireVersion, applicationProtocols };\n};\n\nexport const validateSelection = (\n value: unknown,\n options: StatewireProtocol.Options,\n): StatewireProtocol.Selection => {\n if (typeof value !== \"object\" || value === null)\n return invalid(\"missing negotiation selection\");\n const syn = value as Record<string, unknown>;\n const version = validateVersion(syn.version);\n if (!inRange(version, options.wireVersion ?? { version: WIRE_VERSION }))\n invalid(\"selected wire version is outside offer\");\n if (!Array.isArray(syn.protocols))\n return invalid(\"syn.protocols must be an array\");\n const offers = protocolOffers(options);\n const seen = new Set<string>();\n const protocols = syn.protocols.map((entry: unknown) => {\n if (typeof entry !== \"object\" || entry === null)\n return invalid(\"invalid selected protocol\");\n const item = entry as Record<string, unknown>;\n const name = item.name;\n if (\n typeof name !== \"string\" ||\n !protocolToken.test(name) ||\n name === \"*\" ||\n seen.has(name)\n )\n return invalid(\"invalid selected protocol name\");\n const version = validateVersion(item.version);\n seen.add(name);\n if (offers !== \"*\") {\n const offer = offers.find((o) => o.name === name);\n if (!offer || !inRange(version, offer))\n invalid(\"selected protocol is outside offer\");\n }\n return { name, version };\n });\n if (offers !== \"*\" && offers.some((o) => !o.optional && !seen.has(o.name)))\n invalid(\"required protocol missing from selection\");\n return { version, protocols };\n};\n\nexport const negotiateProtocols = (\n headers: Headers,\n wire: StatewireProtocol.Range,\n definitions: readonly StatewireProtocol.Definition[],\n):\n | StatewireProtocol.Selection\n | {\n fin: {\n reason: \"protocol-error\";\n code: string;\n status: number;\n message: string;\n payload?: unknown;\n };\n } => {\n const supported = {\n ...validateRange(wire),\n protocols: definitions.map((d) => ({ name: d.name, ...validateRange(d) })),\n };\n const failure = (code: string, message: string) => ({\n fin: {\n reason: \"protocol-error\" as const,\n code,\n message,\n status: code === \"invalid-negotiation\" ? 400 : 406,\n ...(code === \"invalid-negotiation\" ? {} : { payload: supported }),\n },\n });\n let request: ReturnType<typeof parseNegotiation>;\n try {\n request = parseNegotiation(headers);\n } catch (error) {\n return failure(\n \"invalid-negotiation\",\n error instanceof Error ? error.message : \"invalid negotiation\",\n );\n }\n const version = [wire.version, request.wireVersion.version].sort()[0]!;\n if (!inRange(version, wire) || !inRange(version, request.wireVersion))\n return failure(\"unsupported-version\", \"Statewire versions do not overlap\");\n const offers =\n request.applicationProtocols === \"*\"\n ? definitions.map((d) => ({\n name: d.name,\n version: d.version,\n optional: false,\n }))\n : request.applicationProtocols;\n const registry = new Map(definitions.map((d) => [d.name, d]));\n if (registry.size !== definitions.length)\n throw new Error(\"statewire: duplicate registered protocol\");\n const offered = new Map(offers.map((o) => [o.name, o]));\n const solve = (names: Set<string>) => {\n const active = new Set(names);\n for (const name of active) {\n const definition = registry.get(name);\n if (!definition || !offered.has(name)) return undefined;\n for (const dependency of Object.keys(definition.requires ?? {}))\n active.add(dependency);\n }\n const result = new Map<string, string>();\n for (const name of active) {\n const ranges = [\n registry.get(name)!,\n offered.get(name)!,\n ...[...active].flatMap((parent) => {\n const dependency = registry.get(parent)!.requires?.[name];\n return dependency ? [dependency] : [];\n }),\n ].map(validateRange);\n const lower = ranges\n .map((r) => r.minVersion)\n .sort()\n .at(-1)!;\n const upper = ranges.map((r) => r.version).sort()[0]!;\n if (lower > upper) return undefined;\n result.set(name, upper);\n }\n return result;\n };\n let selected = solve(\n new Set(offers.filter((o) => !o.optional).map((o) => o.name)),\n );\n if (!selected)\n return failure(\n \"unsupported-protocol\",\n \"required protocol combination is unsupported\",\n );\n for (const offer of offers) {\n if (offer.optional)\n selected = solve(new Set([...selected.keys(), offer.name])) ?? selected;\n }\n return {\n version,\n protocols: offers.flatMap((o) =>\n selected!.has(o.name)\n ? [{ name: o.name, version: selected!.get(o.name)! }]\n : [],\n ),\n };\n};\n"],"mappings":"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"}
@@ -1,7 +1,5 @@
1
1
  //#region src/wire/version.d.ts
2
- declare const PROTOCOL_VERSION = "1";
3
- declare const VERSION_HEADER = "Statewire-Version";
4
2
  declare const WS_SUBPROTOCOL = "statewire.v1";
5
3
  //#endregion
6
- export { PROTOCOL_VERSION, VERSION_HEADER, WS_SUBPROTOCOL };
4
+ export { WS_SUBPROTOCOL };
7
5
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","names":[],"sources":["../../src/wire/version.ts"],"mappings":";cAAa;cACA;cACA"}
1
+ {"version":3,"file":"version.d.ts","names":[],"sources":["../../src/wire/version.ts"],"mappings":";cAAa"}
@@ -1,8 +1,6 @@
1
1
  //#region src/wire/version.ts
2
- const PROTOCOL_VERSION = "1";
3
- const VERSION_HEADER = "Statewire-Version";
4
2
  const WS_SUBPROTOCOL = "statewire.v1";
5
3
  //#endregion
6
- export { PROTOCOL_VERSION, VERSION_HEADER, WS_SUBPROTOCOL };
4
+ export { WS_SUBPROTOCOL };
7
5
 
8
6
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","names":["PROTOCOL_VERSION","VERSION_HEADER","WS_SUBPROTOCOL"],"sources":["../../src/wire/version.ts"],"sourcesContent":["export const PROTOCOL_VERSION = \"1\";\nexport const VERSION_HEADER = \"Statewire-Version\";\nexport const WS_SUBPROTOCOL = \"statewire.v1\";\n"],"mappings":";AAAA,MAAaA,mBAAmB;AAChC,MAAaC,iBAAiB;AAC9B,MAAaC,iBAAiB"}
1
+ {"version":3,"file":"version.js","names":["WS_SUBPROTOCOL"],"sources":["../../src/wire/version.ts"],"sourcesContent":["export const WS_SUBPROTOCOL = \"statewire.v1\";\n"],"mappings":";AAAA,MAAaA,iBAAiB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "statewire",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "State over the wire: snapshot-first delta streaming and command submission for any state and any command",
5
5
  "license": "MIT",
6
6
  "repository": {