@earendil-works/chord 1.2.0 → 1.4.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 (122) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +69 -14
  3. package/dist/cell.d.ts +30 -9
  4. package/dist/cell.d.ts.map +1 -1
  5. package/dist/cell.js +52 -12
  6. package/dist/cell.js.map +1 -1
  7. package/dist/cluster.d.ts +4 -3
  8. package/dist/cluster.d.ts.map +1 -1
  9. package/dist/cluster.js +58 -42
  10. package/dist/cluster.js.map +1 -1
  11. package/dist/connection.d.ts +171 -58
  12. package/dist/connection.d.ts.map +1 -1
  13. package/dist/connection.js +676 -217
  14. package/dist/connection.js.map +1 -1
  15. package/dist/context/index.d.ts +8 -0
  16. package/dist/context/index.d.ts.map +1 -1
  17. package/dist/context/index.js +15 -0
  18. package/dist/context/index.js.map +1 -1
  19. package/dist/contract.d.ts +120 -45
  20. package/dist/contract.d.ts.map +1 -1
  21. package/dist/contract.js +104 -15
  22. package/dist/contract.js.map +1 -1
  23. package/dist/declare.d.ts +11 -48
  24. package/dist/declare.d.ts.map +1 -1
  25. package/dist/declare.js +1 -21
  26. package/dist/declare.js.map +1 -1
  27. package/dist/delta/index.d.ts +2 -1
  28. package/dist/delta/index.d.ts.map +1 -1
  29. package/dist/delta/index.js +4 -0
  30. package/dist/delta/index.js.map +1 -1
  31. package/dist/errors.d.ts +4 -3
  32. package/dist/errors.d.ts.map +1 -1
  33. package/dist/errors.js +15 -0
  34. package/dist/errors.js.map +1 -1
  35. package/dist/host.d.ts +214 -120
  36. package/dist/host.d.ts.map +1 -1
  37. package/dist/host.js +446 -241
  38. package/dist/host.js.map +1 -1
  39. package/dist/index.d.ts +8 -8
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +4 -4
  42. package/dist/index.js.map +1 -1
  43. package/dist/link.d.ts +47 -12
  44. package/dist/link.d.ts.map +1 -1
  45. package/dist/link.js +200 -14
  46. package/dist/link.js.map +1 -1
  47. package/dist/loader.d.ts.map +1 -1
  48. package/dist/loader.js +7 -2
  49. package/dist/loader.js.map +1 -1
  50. package/dist/manager.d.ts.map +1 -1
  51. package/dist/manager.js +35 -9
  52. package/dist/manager.js.map +1 -1
  53. package/dist/object.d.ts +438 -0
  54. package/dist/object.d.ts.map +1 -0
  55. package/dist/{record.js → object.js} +614 -335
  56. package/dist/object.js.map +1 -0
  57. package/dist/output.d.ts +91 -0
  58. package/dist/output.d.ts.map +1 -0
  59. package/dist/output.js +360 -0
  60. package/dist/output.js.map +1 -0
  61. package/dist/registry.d.ts +3 -3
  62. package/dist/registry.d.ts.map +1 -1
  63. package/dist/registry.js +1 -1
  64. package/dist/registry.js.map +1 -1
  65. package/dist/reload.d.ts +35 -27
  66. package/dist/reload.d.ts.map +1 -1
  67. package/dist/reload.js +256 -192
  68. package/dist/reload.js.map +1 -1
  69. package/dist/remote.d.ts +130 -35
  70. package/dist/remote.d.ts.map +1 -1
  71. package/dist/remote.js +493 -189
  72. package/dist/remote.js.map +1 -1
  73. package/dist/sqlite/cloudflare.d.ts +52 -0
  74. package/dist/sqlite/cloudflare.d.ts.map +1 -0
  75. package/dist/sqlite/cloudflare.js +134 -0
  76. package/dist/sqlite/cloudflare.js.map +1 -0
  77. package/dist/sqlite/database.d.ts +37 -0
  78. package/dist/sqlite/database.d.ts.map +1 -0
  79. package/dist/sqlite/database.js +2 -0
  80. package/dist/sqlite/database.js.map +1 -0
  81. package/dist/sqlite/index.d.ts +4 -0
  82. package/dist/sqlite/index.d.ts.map +1 -0
  83. package/dist/sqlite/index.js +3 -0
  84. package/dist/sqlite/index.js.map +1 -0
  85. package/dist/sqlite/migrations.d.ts +10 -0
  86. package/dist/sqlite/migrations.d.ts.map +1 -0
  87. package/dist/sqlite/migrations.js +33 -0
  88. package/dist/sqlite/migrations.js.map +1 -0
  89. package/dist/sqlite/node.d.ts +38 -0
  90. package/dist/sqlite/node.d.ts.map +1 -0
  91. package/dist/sqlite/node.js +174 -0
  92. package/dist/sqlite/node.js.map +1 -0
  93. package/dist/sqlite/schema.d.ts +3 -0
  94. package/dist/sqlite/schema.d.ts.map +1 -0
  95. package/dist/sqlite/schema.js +10 -0
  96. package/dist/sqlite/schema.js.map +1 -0
  97. package/dist/telemetry-sqlite/index.d.ts +24 -0
  98. package/dist/telemetry-sqlite/index.d.ts.map +1 -0
  99. package/dist/telemetry-sqlite/index.js +273 -0
  100. package/dist/telemetry-sqlite/index.js.map +1 -0
  101. package/dist/telemetry-sqlite/store.d.ts +9 -0
  102. package/dist/telemetry-sqlite/store.d.ts.map +1 -0
  103. package/dist/telemetry-sqlite/store.js +110 -0
  104. package/dist/telemetry-sqlite/store.js.map +1 -0
  105. package/dist/types.d.ts +39 -28
  106. package/dist/types.d.ts.map +1 -1
  107. package/dist/types.js.map +1 -1
  108. package/dist/websocket.d.ts +4 -5
  109. package/dist/websocket.d.ts.map +1 -1
  110. package/dist/websocket.js +3 -2
  111. package/dist/websocket.js.map +1 -1
  112. package/dist/wire.d.ts +210 -129
  113. package/dist/wire.d.ts.map +1 -1
  114. package/dist/wire.js +108 -55
  115. package/dist/wire.js.map +1 -1
  116. package/docs/guide.md +267 -203
  117. package/docs/spec.md +141 -114
  118. package/docs/tutorial.md +257 -235
  119. package/package.json +27 -1
  120. package/dist/record.d.ts +0 -320
  121. package/dist/record.d.ts.map +0 -1
  122. package/dist/record.js.map +0 -1
@@ -0,0 +1,110 @@
1
+ function storedSpan(row) {
2
+ return {
3
+ id: row.id,
4
+ traceId: row.trace_id,
5
+ ...(row.parent_id === null ? {} : { parentId: row.parent_id }),
6
+ name: row.name,
7
+ startedMs: row.started_ms,
8
+ endedMs: row.ended_ms,
9
+ attributes: JSON.parse(row.attributes),
10
+ events: JSON.parse(row.events).map((event) => ({ name: event.name, timeMs: event.time_ms, attributes: event.attributes })),
11
+ links: JSON.parse(row.links).map((link) => ({
12
+ traceId: link.trace_id,
13
+ spanId: link.span_id,
14
+ ...(link.attributes === undefined ? {} : { attributes: link.attributes }),
15
+ })),
16
+ status: JSON.parse(row.status),
17
+ };
18
+ }
19
+ // JSON equality must distinguish boolean true from numeric 1. json_each also handles arbitrary attribute keys.
20
+ function attributesSql(attributes, column, params) {
21
+ return (Object.entries(attributes ?? {})
22
+ .map(([key, value]) => {
23
+ const type = typeof value === "number"
24
+ ? "entry.type IN ('integer', 'real')"
25
+ : typeof value === "boolean"
26
+ ? `entry.type = '${value ? "true" : "false"}'`
27
+ : "entry.type = 'text'";
28
+ params.push(key, typeof value === "boolean" ? Number(value) : value);
29
+ return `EXISTS (SELECT 1 FROM json_each(${column}) entry WHERE entry.key = ? AND ${type} AND entry.value = ?)`;
30
+ })
31
+ .join(" AND ") || "1");
32
+ }
33
+ export async function getTrace(db, traceId) {
34
+ const rows = await db.all("SELECT * FROM telemetry_spans WHERE trace_id = ? ORDER BY started_ms, id", traceId);
35
+ return rows.length ? { traceId, spans: rows.map(storedSpan) } : undefined;
36
+ }
37
+ export async function findTraces(db, query = {}) {
38
+ const limit = query.limit ?? 20;
39
+ const conditions = [];
40
+ const params = [];
41
+ if (query.name !== undefined) {
42
+ conditions.push("(SELECT name FROM telemetry_spans WHERE trace_id = heads.trace_id ORDER BY started_ms, id LIMIT 1) = ?");
43
+ params.push(query.name);
44
+ }
45
+ if (query.startMin !== undefined) {
46
+ conditions.push("started_ms >= ?");
47
+ params.push(query.startMin);
48
+ }
49
+ if (query.startMax !== undefined) {
50
+ conditions.push("started_ms <= ?");
51
+ params.push(query.startMax);
52
+ }
53
+ if (query.errors)
54
+ conditions.push("EXISTS (SELECT 1 FROM telemetry_spans WHERE trace_id = heads.trace_id AND json_extract(status, '$.status') = 'error')");
55
+ if (query.attributes)
56
+ conditions.push(`EXISTS (SELECT 1 FROM telemetry_spans candidate WHERE candidate.trace_id = heads.trace_id AND ${attributesSql(query.attributes, "candidate.attributes", params)})`);
57
+ if (query.cursor !== undefined) {
58
+ const cursor = JSON.parse(query.cursor);
59
+ conditions.push("(started_ms < ? OR (started_ms = ? AND trace_id > ?))");
60
+ params.push(cursor[0], cursor[0], cursor[1]);
61
+ }
62
+ return db.transaction(async (tx) => {
63
+ const heads = await tx.all(`WITH heads AS (
64
+ SELECT trace_id, min(started_ms) started_ms FROM telemetry_spans GROUP BY trace_id
65
+ ) SELECT * FROM heads WHERE ${conditions.join(" AND ") || "1"} ORDER BY started_ms DESC, trace_id LIMIT ?`, ...params, limit + 1);
66
+ const more = heads.length > limit;
67
+ if (more)
68
+ heads.pop();
69
+ if (!heads.length)
70
+ return { traces: [] };
71
+ const rows = await tx.all("SELECT * FROM telemetry_spans WHERE trace_id IN (SELECT value FROM json_each(?)) ORDER BY started_ms, id", JSON.stringify(heads.map((head) => head.trace_id)));
72
+ const grouped = new Map();
73
+ for (const row of rows) {
74
+ const spans = grouped.get(row.trace_id) ?? [];
75
+ spans.push(storedSpan(row));
76
+ grouped.set(row.trace_id, spans);
77
+ }
78
+ const last = heads.at(-1);
79
+ return {
80
+ traces: heads.map((head) => ({ traceId: head.trace_id, spans: grouped.get(head.trace_id) })),
81
+ ...(more ? { cursor: JSON.stringify([last.started_ms, last.trace_id]) } : {}),
82
+ };
83
+ });
84
+ }
85
+ export async function findMetrics(db, query) {
86
+ const params = [query.name];
87
+ const conditions = ["name = ?"];
88
+ if (query.startMin !== undefined) {
89
+ conditions.push("interval_ms >= ?");
90
+ params.push(query.startMin);
91
+ }
92
+ if (query.startMax !== undefined) {
93
+ conditions.push("interval_ms <= ?");
94
+ params.push(query.startMax);
95
+ }
96
+ conditions.push(attributesSql(query.attributes, "attributes", params));
97
+ const rows = await db.all(`SELECT * FROM telemetry_metrics WHERE ${conditions.join(" AND ")} ORDER BY interval_ms, series_key`, ...params);
98
+ return rows.map((row) => ({
99
+ intervalMs: row.interval_ms,
100
+ name: row.name,
101
+ kind: row.kind,
102
+ ...(row.unit === null ? {} : { unit: row.unit }),
103
+ attributes: JSON.parse(row.attributes),
104
+ count: row.count,
105
+ sum: row.sum,
106
+ min: row.min,
107
+ max: row.max,
108
+ }));
109
+ }
110
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/telemetry-sqlite/store.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tMetricQuery,\n\tSpanAttributes,\n\tSpanStatus,\n\tStoredMetric,\n\tStoredSpan,\n\tStoredTrace,\n\tTraceQuery,\n} from \"@earendil-works/pi-telemetry\";\nimport type { SqliteDatabase, SqliteValue } from \"../sqlite/index.ts\";\n\ntype SpanRow = {\n\tid: string;\n\ttrace_id: string;\n\tparent_id: string | null;\n\tname: string;\n\tstarted_ms: number;\n\tended_ms: number;\n\tattributes: string;\n\tevents: string;\n\tlinks: string;\n\tstatus: string;\n};\n\nfunction storedSpan(row: SpanRow): StoredSpan {\n\treturn {\n\t\tid: row.id,\n\t\ttraceId: row.trace_id,\n\t\t...(row.parent_id === null ? {} : { parentId: row.parent_id }),\n\t\tname: row.name,\n\t\tstartedMs: row.started_ms,\n\t\tendedMs: row.ended_ms,\n\t\tattributes: JSON.parse(row.attributes) as SpanAttributes,\n\t\tevents: (JSON.parse(row.events) as { name: string; time_ms: number; attributes: SpanAttributes }[]).map(\n\t\t\t(event) => ({ name: event.name, timeMs: event.time_ms, attributes: event.attributes }),\n\t\t),\n\t\tlinks: (JSON.parse(row.links) as { trace_id: string; span_id: string; attributes?: SpanAttributes }[]).map(\n\t\t\t(link) => ({\n\t\t\t\ttraceId: link.trace_id,\n\t\t\t\tspanId: link.span_id,\n\t\t\t\t...(link.attributes === undefined ? {} : { attributes: link.attributes }),\n\t\t\t}),\n\t\t),\n\t\tstatus: JSON.parse(row.status) as SpanStatus,\n\t};\n}\n\n// JSON equality must distinguish boolean true from numeric 1. json_each also handles arbitrary attribute keys.\nfunction attributesSql(attributes: TraceQuery[\"attributes\"], column: string, params: SqliteValue[]): string {\n\treturn (\n\t\tObject.entries(attributes ?? {})\n\t\t\t.map(([key, value]) => {\n\t\t\t\tconst type =\n\t\t\t\t\ttypeof value === \"number\"\n\t\t\t\t\t\t? \"entry.type IN ('integer', 'real')\"\n\t\t\t\t\t\t: typeof value === \"boolean\"\n\t\t\t\t\t\t\t? `entry.type = '${value ? \"true\" : \"false\"}'`\n\t\t\t\t\t\t\t: \"entry.type = 'text'\";\n\t\t\t\tparams.push(key, typeof value === \"boolean\" ? Number(value) : value);\n\t\t\t\treturn `EXISTS (SELECT 1 FROM json_each(${column}) entry WHERE entry.key = ? AND ${type} AND entry.value = ?)`;\n\t\t\t})\n\t\t\t.join(\" AND \") || \"1\"\n\t);\n}\n\nexport async function getTrace(db: SqliteDatabase, traceId: string): Promise<StoredTrace | undefined> {\n\tconst rows = await db.all<SpanRow>(\n\t\t\"SELECT * FROM telemetry_spans WHERE trace_id = ? ORDER BY started_ms, id\",\n\t\ttraceId,\n\t);\n\treturn rows.length ? { traceId, spans: rows.map(storedSpan) } : undefined;\n}\n\nexport async function findTraces(\n\tdb: SqliteDatabase,\n\tquery: TraceQuery = {},\n): Promise<{ traces: readonly StoredTrace[]; cursor?: string }> {\n\tconst limit = query.limit ?? 20;\n\tconst conditions: string[] = [];\n\tconst params: SqliteValue[] = [];\n\tif (query.name !== undefined) {\n\t\tconditions.push(\n\t\t\t\"(SELECT name FROM telemetry_spans WHERE trace_id = heads.trace_id ORDER BY started_ms, id LIMIT 1) = ?\",\n\t\t);\n\t\tparams.push(query.name);\n\t}\n\tif (query.startMin !== undefined) {\n\t\tconditions.push(\"started_ms >= ?\");\n\t\tparams.push(query.startMin);\n\t}\n\tif (query.startMax !== undefined) {\n\t\tconditions.push(\"started_ms <= ?\");\n\t\tparams.push(query.startMax);\n\t}\n\tif (query.errors)\n\t\tconditions.push(\n\t\t\t\"EXISTS (SELECT 1 FROM telemetry_spans WHERE trace_id = heads.trace_id AND json_extract(status, '$.status') = 'error')\",\n\t\t);\n\tif (query.attributes)\n\t\tconditions.push(\n\t\t\t`EXISTS (SELECT 1 FROM telemetry_spans candidate WHERE candidate.trace_id = heads.trace_id AND ${attributesSql(query.attributes, \"candidate.attributes\", params)})`,\n\t\t);\n\tif (query.cursor !== undefined) {\n\t\tconst cursor = JSON.parse(query.cursor) as [number, string];\n\t\tconditions.push(\"(started_ms < ? OR (started_ms = ? AND trace_id > ?))\");\n\t\tparams.push(cursor[0], cursor[0], cursor[1]);\n\t}\n\treturn db.transaction(async (tx) => {\n\t\tconst heads = await tx.all<{ trace_id: string; started_ms: number }>(\n\t\t\t`WITH heads AS (\n\t\t\tSELECT trace_id, min(started_ms) started_ms FROM telemetry_spans GROUP BY trace_id\n\t\t) SELECT * FROM heads WHERE ${conditions.join(\" AND \") || \"1\"} ORDER BY started_ms DESC, trace_id LIMIT ?`,\n\t\t\t...params,\n\t\t\tlimit + 1,\n\t\t);\n\t\tconst more = heads.length > limit;\n\t\tif (more) heads.pop();\n\t\tif (!heads.length) return { traces: [] };\n\t\tconst rows = await tx.all<SpanRow>(\n\t\t\t\"SELECT * FROM telemetry_spans WHERE trace_id IN (SELECT value FROM json_each(?)) ORDER BY started_ms, id\",\n\t\t\tJSON.stringify(heads.map((head) => head.trace_id)),\n\t\t);\n\t\tconst grouped = new Map<string, StoredSpan[]>();\n\t\tfor (const row of rows) {\n\t\t\tconst spans = grouped.get(row.trace_id) ?? [];\n\t\t\tspans.push(storedSpan(row));\n\t\t\tgrouped.set(row.trace_id, spans);\n\t\t}\n\t\tconst last = heads.at(-1)!;\n\t\treturn {\n\t\t\ttraces: heads.map((head) => ({ traceId: head.trace_id, spans: grouped.get(head.trace_id)! })),\n\t\t\t...(more ? { cursor: JSON.stringify([last.started_ms, last.trace_id]) } : {}),\n\t\t};\n\t});\n}\n\nexport async function findMetrics(db: SqliteDatabase, query: MetricQuery): Promise<readonly StoredMetric[]> {\n\tconst params: SqliteValue[] = [query.name];\n\tconst conditions = [\"name = ?\"];\n\tif (query.startMin !== undefined) {\n\t\tconditions.push(\"interval_ms >= ?\");\n\t\tparams.push(query.startMin);\n\t}\n\tif (query.startMax !== undefined) {\n\t\tconditions.push(\"interval_ms <= ?\");\n\t\tparams.push(query.startMax);\n\t}\n\tconditions.push(attributesSql(query.attributes, \"attributes\", params));\n\tconst rows = await db.all<{\n\t\tinterval_ms: number;\n\t\tname: string;\n\t\tkind: StoredMetric[\"kind\"];\n\t\tunit: string | null;\n\t\tattributes: string;\n\t\tcount: number;\n\t\tsum: number;\n\t\tmin: number;\n\t\tmax: number;\n\t}>(`SELECT * FROM telemetry_metrics WHERE ${conditions.join(\" AND \")} ORDER BY interval_ms, series_key`, ...params);\n\treturn rows.map((row) => ({\n\t\tintervalMs: row.interval_ms,\n\t\tname: row.name,\n\t\tkind: row.kind,\n\t\t...(row.unit === null ? {} : { unit: row.unit }),\n\t\tattributes: JSON.parse(row.attributes) as SpanAttributes,\n\t\tcount: row.count,\n\t\tsum: row.sum,\n\t\tmin: row.min,\n\t\tmax: row.max,\n\t}));\n}\n"]}
package/dist/types.d.ts CHANGED
@@ -1,23 +1,35 @@
1
- import type { AnyContract, Handle, InputOf } from "./contract.ts";
1
+ import type { AnyContract, InputOf, Ref } from "./contract.ts";
2
2
  import type { Op } from "./delta/index.ts";
3
- /** App-defined, JSON-serializable identity of a caller. Mapped to a record key by `createHost({ principalKey })`. */
4
- export type Principal = unknown;
5
- export interface GetOptions {
6
- /** Principal the record is created for. Defaults to the host principal. */
7
- readonly principal?: Principal;
8
- /** Host name. Only the local host in phase 1a. */
9
- readonly at?: string;
3
+ /**
4
+ * Options of `get`. `P` is the app's principal type: a JSON-serializable identity of a caller, mapped to an object key
5
+ * by `createHost({ principalKey })`.
6
+ */
7
+ export interface GetOptions<P = unknown> {
8
+ /** Principal the object is created for. Defaults to the host's own principal (`createHost({ self })`). */
9
+ readonly principal?: P;
10
+ /**
11
+ * False: a method-only reference. It receives no state (unless another reference to the same object wants it), and
12
+ * is ready once its object is live.
13
+ */
14
+ readonly state?: boolean;
10
15
  }
11
16
  /**
12
- * The explicit call context of one root (a short Chord call tree). Calls made with it carry its root id and epoch;
13
- * `get` holds are released when the call that received this ctx settles.
17
+ * The explicit call context of one root (a short Chord call tree). Calls made with it carry its root id and code
18
+ * version; `get` references are released when the call that received this ctx settles.
14
19
  */
15
- export interface Ctx {
20
+ export interface Ctx<P = unknown> {
16
21
  readonly signal: AbortSignal;
17
22
  readonly rootId: string;
18
- readonly epoch: number;
19
- readonly principal: Principal;
20
- get<C extends AnyContract>(type: C, input: InputOf<C>, options?: GetOptions): Handle<C>;
23
+ readonly codeVersion: number;
24
+ /** Who the root acts as: the caller at ingress, the host's own principal inside objects. */
25
+ readonly principal: P;
26
+ /**
27
+ * A reference for this call, released when the call settles. Resolves once it is ready: live, with every state
28
+ * member of its variant (unless `state: false`). Rejects with the activation error, `aborted` when the ctx is
29
+ * aborted or the call settles first, or `unavailable/ready_timeout` after the host's `readyTimeout`; the reference
30
+ * is released then.
31
+ */
32
+ get<C extends AnyContract>(type: C, input: InputOf<C>, options?: GetOptions<P>): Promise<Ref<C>>;
21
33
  }
22
34
  export type StateEvent<T> = {
23
35
  readonly type: "snap";
@@ -30,7 +42,7 @@ export type StateEvent<T> = {
30
42
  readonly type: "reset";
31
43
  readonly value: T;
32
44
  };
33
- /** A readable state source: a cell, a derivation, or a handle's state member. Values are immutable by contract. */
45
+ /** A readable state source: a cell, a derivation, or a reference's state member. Values are immutable by contract. */
34
46
  export interface Readable<T> {
35
47
  readonly value: T;
36
48
  /** Called with the current value immediately, then with every new value. */
@@ -39,38 +51,37 @@ export interface Readable<T> {
39
51
  events(listener: (event: StateEvent<T>) => void): () => void;
40
52
  }
41
53
  /**
42
- * What a behavior may expose as a state member: a cell, a derivation, or a held object's state member (whose value is
43
- * `undefined` only while that object is loading; a record is live only after its holds are).
54
+ * What an implementation may expose as a state member: a cell, a derivation, or a held object's state member (an
55
+ * object goes live only once the members it exposes have their values).
44
56
  */
45
- export type StateSource<T> = Readable<T> | Readable<T | undefined>;
57
+ export type StateSource<T> = Readable<T>;
46
58
  declare const EXPOSED: unique symbol;
47
- /** A local member backed by a resource (`self.expose(res.x)`): handles read the resource's value once live. */
59
+ /** A local member backed by a resource (`self.expose(res.x)`): references read the resource's value once live. */
48
60
  export interface Exposed<T> {
49
61
  readonly [EXPOSED]: T;
50
62
  }
51
- export type HandleStatus = "loading" | "live" | "released" | "gone";
63
+ export type RefStatus = "loading" | "live" | "released" | "gone";
52
64
  export interface Shape {
53
- readonly kind: string | undefined;
65
+ readonly variant: string | undefined;
54
66
  readonly members: readonly string[];
55
67
  /** Fingerprint of the provider contract. */
56
68
  readonly contract: string;
57
- readonly epoch: number;
58
69
  }
59
- export interface HandleBase<C extends AnyContract> {
60
- /** The consumer contract token this handle was bound with. */
70
+ export interface RefBase<C extends AnyContract> {
71
+ /** The consumer contract token this reference was bound with. */
61
72
  readonly contract: C;
62
- readonly status: HandleStatus;
73
+ readonly status: RefStatus;
63
74
  readonly ready: Promise<void>;
64
- readonly kind: string | undefined;
75
+ readonly variant: string | undefined;
65
76
  readonly shape: Shape | undefined;
66
- /** Why the handle is gone, if it is. */
77
+ /** Why the reference is gone, if it is. */
67
78
  readonly error: unknown;
68
79
  onShape(listener: (shape: Shape) => void): () => void;
69
80
  /**
70
81
  * Called after every status change (`loading` → `live`, `live` → `loading` while a link reconnects, `released`,
71
82
  * `gone` with `error`). A UI watches for `gone` to `get` again.
72
83
  */
73
- onStatus(listener: (status: HandleStatus, error: unknown) => void): () => void;
84
+ onStatus(listener: (status: RefStatus, error: unknown) => void): () => void;
74
85
  release(): void;
75
86
  }
76
87
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AnyContract, Handle, InputOf } from \"./contract.ts\";\nimport type { Op } from \"./delta/index.ts\";\n\n/** App-defined, JSON-serializable identity of a caller. Mapped to a record key by `createHost({ principalKey })`. */\nexport type Principal = unknown;\n\nexport interface GetOptions {\n\t/** Principal the record is created for. Defaults to the host principal. */\n\treadonly principal?: Principal;\n\t/** Host name. Only the local host in phase 1a. */\n\treadonly at?: string;\n}\n\n/**\n * The explicit call context of one root (a short Chord call tree). Calls made with it carry its root id and epoch;\n * `get` holds are released when the call that received this ctx settles.\n */\nexport interface Ctx {\n\treadonly signal: AbortSignal;\n\treadonly rootId: string;\n\treadonly epoch: number;\n\treadonly principal: Principal;\n\tget<C extends AnyContract>(type: C, input: InputOf<C>, options?: GetOptions): Handle<C>;\n}\n\nexport type StateEvent<T> =\n\t| { readonly type: \"snap\"; readonly value: T }\n\t| { readonly type: \"ops\"; readonly ops: readonly Op[]; readonly value: T }\n\t| { readonly type: \"reset\"; readonly value: T };\n\n/** A readable state source: a cell, a derivation, or a handle's state member. Values are immutable by contract. */\nexport interface Readable<T> {\n\treadonly value: T;\n\t/** Called with the current value immediately, then with every new value. */\n\tsubscribe(listener: (value: T) => void): () => void;\n\t/** Delta stream: a snapshot immediately, then ops, or a reset after a migration or rebind. */\n\tevents(listener: (event: StateEvent<T>) => void): () => void;\n}\n\n/**\n * What a behavior may expose as a state member: a cell, a derivation, or a held object's state member (whose value is\n * `undefined` only while that object is loading; a record is live only after its holds are).\n */\nexport type StateSource<T> = Readable<T> | Readable<T | undefined>;\n\ndeclare const EXPOSED: unique symbol;\n\n/** A local member backed by a resource (`self.expose(res.x)`): handles read the resource's value once live. */\nexport interface Exposed<T> {\n\treadonly [EXPOSED]: T;\n}\n\nexport type HandleStatus = \"loading\" | \"live\" | \"released\" | \"gone\";\n\nexport interface Shape {\n\treadonly kind: string | undefined;\n\treadonly members: readonly string[];\n\t/** Fingerprint of the provider contract. */\n\treadonly contract: string;\n\treadonly epoch: number;\n}\n\nexport interface HandleBase<C extends AnyContract> {\n\t/** The consumer contract token this handle was bound with. */\n\treadonly contract: C;\n\treadonly status: HandleStatus;\n\treadonly ready: Promise<void>;\n\treadonly kind: string | undefined;\n\treadonly shape: Shape | undefined;\n\t/** Why the handle is gone, if it is. */\n\treadonly error: unknown;\n\tonShape(listener: (shape: Shape) => void): () => void;\n\t/**\n\t * Called after every status change (`loading` → `live`, `live` → `loading` while a link reconnects, `released`,\n\t * `gone` with `error`). A UI watches for `gone` to `get` again.\n\t */\n\tonStatus(listener: (status: HandleStatus, error: unknown) => void): () => void;\n\trelease(): void;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { AnyContract, InputOf, Ref } from \"./contract.ts\";\nimport type { Op } from \"./delta/index.ts\";\n\n/**\n * Options of `get`. `P` is the app's principal type: a JSON-serializable identity of a caller, mapped to an object key\n * by `createHost({ principalKey })`.\n */\nexport interface GetOptions<P = unknown> {\n\t/** Principal the object is created for. Defaults to the host's own principal (`createHost({ self })`). */\n\treadonly principal?: P;\n\t/**\n\t * False: a method-only reference. It receives no state (unless another reference to the same object wants it), and\n\t * is ready once its object is live.\n\t */\n\treadonly state?: boolean;\n}\n\n/**\n * The explicit call context of one root (a short Chord call tree). Calls made with it carry its root id and code\n * version; `get` references are released when the call that received this ctx settles.\n */\nexport interface Ctx<P = unknown> {\n\treadonly signal: AbortSignal;\n\treadonly rootId: string;\n\treadonly codeVersion: number;\n\t/** Who the root acts as: the caller at ingress, the host's own principal inside objects. */\n\treadonly principal: P;\n\t/**\n\t * A reference for this call, released when the call settles. Resolves once it is ready: live, with every state\n\t * member of its variant (unless `state: false`). Rejects with the activation error, `aborted` when the ctx is\n\t * aborted or the call settles first, or `unavailable/ready_timeout` after the host's `readyTimeout`; the reference\n\t * is released then.\n\t */\n\tget<C extends AnyContract>(type: C, input: InputOf<C>, options?: GetOptions<P>): Promise<Ref<C>>;\n}\n\nexport type StateEvent<T> =\n\t| { readonly type: \"snap\"; readonly value: T }\n\t| { readonly type: \"ops\"; readonly ops: readonly Op[]; readonly value: T }\n\t| { readonly type: \"reset\"; readonly value: T };\n\n/** A readable state source: a cell, a derivation, or a reference's state member. Values are immutable by contract. */\nexport interface Readable<T> {\n\treadonly value: T;\n\t/** Called with the current value immediately, then with every new value. */\n\tsubscribe(listener: (value: T) => void): () => void;\n\t/** Delta stream: a snapshot immediately, then ops, or a reset after a migration or rebind. */\n\tevents(listener: (event: StateEvent<T>) => void): () => void;\n}\n\n/**\n * What an implementation may expose as a state member: a cell, a derivation, or a held object's state member (an\n * object goes live only once the members it exposes have their values).\n */\nexport type StateSource<T> = Readable<T>;\n\ndeclare const EXPOSED: unique symbol;\n\n/** A local member backed by a resource (`self.expose(res.x)`): references read the resource's value once live. */\nexport interface Exposed<T> {\n\treadonly [EXPOSED]: T;\n}\n\nexport type RefStatus = \"loading\" | \"live\" | \"released\" | \"gone\";\n\nexport interface Shape {\n\treadonly variant: string | undefined;\n\treadonly members: readonly string[];\n\t/** Fingerprint of the provider contract. */\n\treadonly contract: string;\n}\n\nexport interface RefBase<C extends AnyContract> {\n\t/** The consumer contract token this reference was bound with. */\n\treadonly contract: C;\n\treadonly status: RefStatus;\n\treadonly ready: Promise<void>;\n\treadonly variant: string | undefined;\n\treadonly shape: Shape | undefined;\n\t/** Why the reference is gone, if it is. */\n\treadonly error: unknown;\n\tonShape(listener: (shape: Shape) => void): () => void;\n\t/**\n\t * Called after every status change (`loading` → `live`, `live` → `loading` while a link reconnects, `released`,\n\t * `gone` with `error`). A UI watches for `gone` to `get` again.\n\t */\n\tonStatus(listener: (status: RefStatus, error: unknown) => void): () => void;\n\trelease(): void;\n}\n"]}
@@ -1,16 +1,15 @@
1
1
  import type { AcceptOptions } from "./connection.ts";
2
2
  import type { Host } from "./host.ts";
3
3
  import { type WebSocketLike } from "./link.ts";
4
- import type { Principal } from "./types.ts";
5
4
  /** A WebSocket server (e.g. `ws`'s `WebSocketServer`), structurally: Chord does not depend on `ws`. */
6
5
  export interface WebSocketServerLike<Request> {
7
6
  on(event: "connection", listener: (socket: WebSocketLike, request: Request) => void): unknown;
8
7
  }
9
- /** WebSocket peers are always accepted as clients: no roots, no epochs, no reload votes, not addressable. */
10
- export interface WebSocketAcceptOptions<Request> extends Omit<AcceptOptions, "principal" | "kind" | "name"> {
8
+ /** WebSocket peers are always accepted as clients: no roots, no code versions, no reload votes, not addressable. */
9
+ export interface WebSocketAcceptOptions<Request, P = unknown> extends Omit<AcceptOptions<P>, "principal" | "kind" | "name"> {
11
10
  /** The authenticator: the principal of the connecting client, or undefined to refuse it. */
12
- principal(request: Request): Principal | undefined | Promise<Principal | undefined>;
11
+ principal(request: Request): P | undefined | Promise<P | undefined>;
13
12
  }
14
13
  /** Accepts every connection of `server` on `host` as a client link stamped with the authenticated principal. */
15
- export declare function acceptWebSockets<Request>(server: WebSocketServerLike<Request>, host: Host, options: WebSocketAcceptOptions<Request>): void;
14
+ export declare function acceptWebSockets<Request, P = unknown>(server: WebSocketServerLike<Request>, host: Host<P>, options: WebSocketAcceptOptions<Request, P>): void;
16
15
  //# sourceMappingURL=websocket.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,WAAW,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,uGAAuG;AACvG,MAAM,WAAW,mBAAmB,CAAC,OAAO;IAC3C,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC;CAC9F;AAED,6GAA6G;AAC7G,MAAM,WAAW,sBAAsB,CAAC,OAAO,CAAE,SAAQ,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;IAC1G,4FAA4F;IAC5F,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;CACpF;AAED,gHAAgH;AAChH,wBAAgB,gBAAgB,CAAC,OAAO,EACvC,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC,EACpC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,sBAAsB,CAAC,OAAO,CAAC,GACtC,IAAI,CAYN"}
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,WAAW,CAAC;AAE9D,uGAAuG;AACvG,MAAM,WAAW,mBAAmB,CAAC,OAAO;IAC3C,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC;CAC9F;AAED,oHAAoH;AACpH,MAAM,WAAW,sBAAsB,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAC3D,SAAQ,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7D,4FAA4F;IAC5F,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;CACpE;AAED,gHAAgH;AAChH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,EACpD,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC,EACpC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EACb,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,CAAC,CAAC,GACzC,IAAI,CAaN"}
package/dist/websocket.js CHANGED
@@ -2,8 +2,9 @@ import { webSocketLink } from "./link.js";
2
2
  /** Accepts every connection of `server` on `host` as a client link stamped with the authenticated principal. */
3
3
  export function acceptWebSockets(server, host, options) {
4
4
  server.on("connection", (socket, request) => {
5
- // Wrap at once so frames sent while authenticating are queued, not lost.
6
- const link = webSocketLink(socket);
5
+ // Wrap at once so frames sent while authenticating are queued, not lost. Large payloads go out deflated; clients
6
+ // may not send packed frames (a small message could inflate to anything).
7
+ const link = webSocketLink(socket, { compress: true, acceptPacked: false });
7
8
  Promise.resolve(options.principal(request)).then((principal) => {
8
9
  if (principal === undefined)
9
10
  link.close("unauthorized");
@@ -1 +1 @@
1
- {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,aAAa,EAAE,MAAM,WAAW,CAAC;AAc9D,gHAAgH;AAChH,MAAM,UAAU,gBAAgB,CAC/B,MAAoC,EACpC,IAAU,EACV,OAAwC;IAExC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;QAC3C,yEAAyE;QACzE,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC/C,CAAC,SAAS,EAAE,EAAE;YACb,IAAI,SAAS,KAAK,SAAS;gBAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;;gBACnD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC,EACD,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,CACzC,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { AcceptOptions } from \"./connection.ts\";\nimport type { Host } from \"./host.ts\";\nimport { type WebSocketLike, webSocketLink } from \"./link.ts\";\nimport type { Principal } from \"./types.ts\";\n\n/** A WebSocket server (e.g. `ws`'s `WebSocketServer`), structurally: Chord does not depend on `ws`. */\nexport interface WebSocketServerLike<Request> {\n\ton(event: \"connection\", listener: (socket: WebSocketLike, request: Request) => void): unknown;\n}\n\n/** WebSocket peers are always accepted as clients: no roots, no epochs, no reload votes, not addressable. */\nexport interface WebSocketAcceptOptions<Request> extends Omit<AcceptOptions, \"principal\" | \"kind\" | \"name\"> {\n\t/** The authenticator: the principal of the connecting client, or undefined to refuse it. */\n\tprincipal(request: Request): Principal | undefined | Promise<Principal | undefined>;\n}\n\n/** Accepts every connection of `server` on `host` as a client link stamped with the authenticated principal. */\nexport function acceptWebSockets<Request>(\n\tserver: WebSocketServerLike<Request>,\n\thost: Host,\n\toptions: WebSocketAcceptOptions<Request>,\n): void {\n\tserver.on(\"connection\", (socket, request) => {\n\t\t// Wrap at once so frames sent while authenticating are queued, not lost.\n\t\tconst link = webSocketLink(socket);\n\t\tPromise.resolve(options.principal(request)).then(\n\t\t\t(principal) => {\n\t\t\t\tif (principal === undefined) link.close(\"unauthorized\");\n\t\t\t\telse host.accept(link, { ...options, principal, kind: \"client\" });\n\t\t\t},\n\t\t\t() => link.close(\"authentication failed\"),\n\t\t);\n\t});\n}\n"]}
1
+ {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,aAAa,EAAE,MAAM,WAAW,CAAC;AAc9D,gHAAgH;AAChH,MAAM,UAAU,gBAAgB,CAC/B,MAAoC,EACpC,IAAa,EACb,OAA2C;IAE3C,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;QAC3C,iHAAiH;QACjH,0EAA0E;QAC1E,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5E,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC/C,CAAC,SAAS,EAAE,EAAE;YACb,IAAI,SAAS,KAAK,SAAS;gBAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;;gBACnD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC,EACD,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,uBAAuB,CAAC,CACzC,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { AcceptOptions } from \"./connection.ts\";\nimport type { Host } from \"./host.ts\";\nimport { type WebSocketLike, webSocketLink } from \"./link.ts\";\n\n/** A WebSocket server (e.g. `ws`'s `WebSocketServer`), structurally: Chord does not depend on `ws`. */\nexport interface WebSocketServerLike<Request> {\n\ton(event: \"connection\", listener: (socket: WebSocketLike, request: Request) => void): unknown;\n}\n\n/** WebSocket peers are always accepted as clients: no roots, no code versions, no reload votes, not addressable. */\nexport interface WebSocketAcceptOptions<Request, P = unknown>\n\textends Omit<AcceptOptions<P>, \"principal\" | \"kind\" | \"name\"> {\n\t/** The authenticator: the principal of the connecting client, or undefined to refuse it. */\n\tprincipal(request: Request): P | undefined | Promise<P | undefined>;\n}\n\n/** Accepts every connection of `server` on `host` as a client link stamped with the authenticated principal. */\nexport function acceptWebSockets<Request, P = unknown>(\n\tserver: WebSocketServerLike<Request>,\n\thost: Host<P>,\n\toptions: WebSocketAcceptOptions<Request, P>,\n): void {\n\tserver.on(\"connection\", (socket, request) => {\n\t\t// Wrap at once so frames sent while authenticating are queued, not lost. Large payloads go out deflated; clients\n\t\t// may not send packed frames (a small message could inflate to anything).\n\t\tconst link = webSocketLink(socket, { compress: true, acceptPacked: false });\n\t\tPromise.resolve(options.principal(request)).then(\n\t\t\t(principal) => {\n\t\t\t\tif (principal === undefined) link.close(\"unauthorized\");\n\t\t\t\telse host.accept(link, { ...options, principal, kind: \"client\" });\n\t\t\t},\n\t\t\t() => link.close(\"authentication failed\"),\n\t\t);\n\t});\n}\n"]}