solid-objects 0.12.0 → 0.13.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 (99) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +228 -914
  3. package/dist/actor.d.ts +12 -0
  4. package/dist/actor.d.ts.map +1 -1
  5. package/dist/actor.js +28 -5
  6. package/dist/actor.js.map +1 -1
  7. package/dist/browser/components.d.ts.map +1 -1
  8. package/dist/browser/components.js +4 -1
  9. package/dist/browser/components.js.map +1 -1
  10. package/dist/browser/index.d.ts +1 -0
  11. package/dist/browser/index.d.ts.map +1 -1
  12. package/dist/browser/index.js +8 -0
  13. package/dist/browser/index.js.map +1 -1
  14. package/dist/cli.d.ts.map +1 -1
  15. package/dist/cli.js +13 -1
  16. package/dist/cli.js.map +1 -1
  17. package/dist/configuration.d.ts +1 -0
  18. package/dist/configuration.d.ts.map +1 -1
  19. package/dist/configuration.js.map +1 -1
  20. package/dist/doctor.d.ts.map +1 -1
  21. package/dist/doctor.js +12 -3
  22. package/dist/doctor.js.map +1 -1
  23. package/dist/errors.d.ts +2 -0
  24. package/dist/errors.d.ts.map +1 -1
  25. package/dist/errors.js +2 -0
  26. package/dist/errors.js.map +1 -1
  27. package/dist/examples/sqlite-quickstart.js +83 -0
  28. package/dist/examples/sqlite-quickstart.js.map +1 -0
  29. package/dist/index.d.ts +3 -3
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -2
  32. package/dist/index.js.map +1 -1
  33. package/dist/records.d.ts +1 -0
  34. package/dist/records.d.ts.map +1 -1
  35. package/dist/reminder-scheduler.d.ts +3 -1
  36. package/dist/reminder-scheduler.d.ts.map +1 -1
  37. package/dist/reminder-scheduler.js +11 -3
  38. package/dist/reminder-scheduler.js.map +1 -1
  39. package/dist/repository.d.ts +10 -3
  40. package/dist/repository.d.ts.map +1 -1
  41. package/dist/repository.js +24 -14
  42. package/dist/repository.js.map +1 -1
  43. package/dist/runtime.d.ts +3 -1
  44. package/dist/runtime.d.ts.map +1 -1
  45. package/dist/runtime.js +39 -8
  46. package/dist/runtime.js.map +1 -1
  47. package/dist/schema.d.ts.map +1 -1
  48. package/dist/schema.js +15 -4
  49. package/dist/schema.js.map +1 -1
  50. package/dist/test-helper.d.ts +5 -0
  51. package/dist/test-helper.d.ts.map +1 -1
  52. package/dist/test-helper.js +24 -0
  53. package/dist/test-helper.js.map +1 -1
  54. package/dist/version.d.ts +1 -1
  55. package/dist/version.js +1 -1
  56. package/dist/web/assets.d.ts +4 -0
  57. package/dist/web/assets.d.ts.map +1 -0
  58. package/dist/web/assets.js +11 -0
  59. package/dist/web/assets.js.map +1 -0
  60. package/dist/web/index.d.ts +28 -0
  61. package/dist/web/index.d.ts.map +1 -0
  62. package/dist/web/index.js +642 -0
  63. package/dist/web/index.js.map +1 -0
  64. package/dist/web/node.d.ts +3 -0
  65. package/dist/web/node.d.ts.map +1 -0
  66. package/dist/web/node.js +109 -0
  67. package/dist/web/node.js.map +1 -0
  68. package/dist/web/render.d.ts +64 -0
  69. package/dist/web/render.d.ts.map +1 -0
  70. package/dist/web/render.js +331 -0
  71. package/dist/web/render.js.map +1 -0
  72. package/dist/web/store.d.ts +65 -0
  73. package/dist/web/store.d.ts.map +1 -0
  74. package/dist/web/store.js +303 -0
  75. package/dist/web/store.js.map +1 -0
  76. package/dist/web/types.d.ts +82 -0
  77. package/dist/web/types.d.ts.map +1 -0
  78. package/dist/web/types.js +2 -0
  79. package/dist/web/types.js.map +1 -0
  80. package/docs/api.md +99 -4
  81. package/docs/architecture.md +16 -10
  82. package/docs/authorization.md +12 -3
  83. package/docs/benchmarks.md +123 -0
  84. package/docs/browser-protocol.md +16 -2
  85. package/docs/comparisons.md +36 -0
  86. package/docs/configuration.md +22 -1
  87. package/docs/correctness.md +23 -0
  88. package/docs/dashboard.md +196 -0
  89. package/docs/errors-and-recovery.md +16 -1
  90. package/docs/fit.md +58 -0
  91. package/docs/parity.md +39 -36
  92. package/docs/releasing.md +7 -4
  93. package/docs/state-and-lifecycle.md +14 -4
  94. package/docs/support.md +39 -0
  95. package/examples/failure-recovery/actor.ts +51 -0
  96. package/examples/failure-recovery/demo.ts +233 -0
  97. package/examples/failure-recovery/worker.ts +46 -0
  98. package/examples/sqlite-quickstart.ts +109 -0
  99. package/package.json +25 -4
@@ -0,0 +1,65 @@
1
+ import type { SolidObjectsRuntime } from "../runtime.js";
2
+ export type DashboardRecord = Record<string, unknown>;
3
+ export interface DashboardPageResult {
4
+ readonly records: readonly DashboardRecord[];
5
+ readonly page: number;
6
+ readonly perPage: number;
7
+ readonly total: number;
8
+ readonly lastPage: number;
9
+ }
10
+ export interface DashboardStatistics extends DashboardRecord {
11
+ readonly instances: DashboardRecord;
12
+ readonly mailbox: DashboardRecord;
13
+ readonly effects: DashboardRecord;
14
+ readonly broadcasts: DashboardRecord;
15
+ readonly reminders: DashboardRecord;
16
+ readonly deadLetters: DashboardRecord;
17
+ readonly processes: DashboardRecord;
18
+ readonly serverTime: string;
19
+ }
20
+ export interface DashboardInstanceDetail {
21
+ readonly instance: DashboardRecord;
22
+ readonly readyMessages: readonly DashboardRecord[];
23
+ readonly claimedMessages: readonly DashboardRecord[];
24
+ readonly recentMessages: readonly DashboardRecord[];
25
+ readonly reminders: readonly DashboardRecord[];
26
+ readonly effects: readonly DashboardRecord[];
27
+ readonly broadcasts: readonly DashboardRecord[];
28
+ readonly deadLetters: readonly DashboardRecord[];
29
+ }
30
+ interface PageOptions {
31
+ readonly page?: string | null;
32
+ readonly perPage?: string | null;
33
+ readonly status?: string | null;
34
+ readonly actorType?: string | null;
35
+ readonly actorId?: string | null;
36
+ readonly membership?: string | null;
37
+ }
38
+ export declare class DashboardStore {
39
+ private readonly runtime;
40
+ constructor(runtime: SolidObjectsRuntime);
41
+ statistics(): Promise<DashboardStatistics>;
42
+ instances(options: PageOptions): Promise<DashboardPageResult>;
43
+ mailbox(options: PageOptions): Promise<DashboardPageResult>;
44
+ reminders(options: PageOptions): Promise<DashboardPageResult>;
45
+ effects(options: PageOptions): Promise<DashboardPageResult>;
46
+ broadcasts(options: PageOptions): Promise<DashboardPageResult>;
47
+ deadLetters(options: PageOptions): Promise<DashboardPageResult>;
48
+ processes(options: PageOptions): Promise<DashboardPageResult>;
49
+ instance(id: string): Promise<DashboardInstanceDetail | undefined>;
50
+ message(id: string): Promise<DashboardRecord | undefined>;
51
+ deadLetter(id: string): Promise<DashboardRecord | undefined>;
52
+ dashboard(): Promise<DashboardRecord>;
53
+ setPaused(options: {
54
+ id: string;
55
+ paused: boolean;
56
+ }): Promise<boolean>;
57
+ healthy(): Promise<void>;
58
+ private page;
59
+ private statusPage;
60
+ private grouped;
61
+ private substringExpression;
62
+ private table;
63
+ }
64
+ export {};
65
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/web/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,303 @@
1
+ const EFFECT_STATUSES = ["pending", "processing", "completed", "dead"];
2
+ const BROADCAST_STATUSES = ["pending", "processing", "delivered", "dead"];
3
+ const REMINDER_STATUSES = ["scheduled", "paused", "completed"];
4
+ const PROCESS_STATUSES = ["running", "draining", "stopped"];
5
+ export class DashboardStore {
6
+ runtime;
7
+ constructor(runtime) {
8
+ this.runtime = runtime;
9
+ }
10
+ async statistics() {
11
+ return this.runtime.settings.database.connection(async (connection) => {
12
+ const now = await connection.nowMilliseconds();
13
+ const [instances, mailbox, effects, broadcasts, reminders, deadLetters, processes] = await Promise.all([
14
+ connection.get(`SELECT COUNT(*) AS total,
15
+ SUM(CASE WHEN paused = 1 THEN 1 ELSE 0 END) AS paused,
16
+ SUM(CASE WHEN activation_expires_at_ms >= ? THEN 1 ELSE 0 END) AS activated
17
+ FROM ${this.table("instances")}`, [now]),
18
+ connection.get(`SELECT COUNT(*) AS ready,
19
+ SUM(CASE WHEN available_at_ms <= ? THEN 1 ELSE 0 END) AS due,
20
+ MIN(CASE WHEN available_at_ms <= ? THEN available_at_ms END) AS oldest_due
21
+ FROM ${this.table("ready_messages")}`, [now, now]),
22
+ this.grouped({
23
+ connection,
24
+ table: "effects",
25
+ column: "status",
26
+ statuses: EFFECT_STATUSES,
27
+ }),
28
+ this.grouped({
29
+ connection,
30
+ table: "broadcasts",
31
+ column: "status",
32
+ statuses: BROADCAST_STATUSES,
33
+ }),
34
+ this.grouped({
35
+ connection,
36
+ table: "reminders",
37
+ column: "status",
38
+ statuses: REMINDER_STATUSES,
39
+ }),
40
+ connection.get(`SELECT COUNT(*) AS total FROM ${this.table("dead_letters")}`),
41
+ this.grouped({
42
+ connection,
43
+ table: "processes",
44
+ column: "shutdown_state",
45
+ statuses: PROCESS_STATUSES,
46
+ }),
47
+ ]);
48
+ const claimed = await connection.get(`SELECT COUNT(*) AS total FROM ${this.table("claimed_messages")}`);
49
+ const reminderDue = await connection.get(`SELECT COUNT(*) AS total FROM ${this.table("reminders")}
50
+ WHERE status = 'scheduled' AND run_at_ms <= ?`, [now]);
51
+ const oldestDue = numeric(mailbox?.oldest_due);
52
+ return freezeRecord({
53
+ instances: freezeRecord({
54
+ total: numeric(instances?.total),
55
+ paused: numeric(instances?.paused),
56
+ activated: numeric(instances?.activated),
57
+ }),
58
+ mailbox: freezeRecord({
59
+ ready: numeric(mailbox?.ready),
60
+ due: numeric(mailbox?.due),
61
+ claimed: numeric(claimed?.total),
62
+ latency: oldestDue === 0 ? 0 : Math.max(0, (now - oldestDue) / 1_000),
63
+ }),
64
+ effects,
65
+ broadcasts,
66
+ reminders: freezeRecord({ ...reminders, due: numeric(reminderDue?.total) }),
67
+ deadLetters: freezeRecord({ total: numeric(deadLetters?.total) }),
68
+ processes,
69
+ serverTime: new Date(now).toISOString(),
70
+ });
71
+ });
72
+ }
73
+ instances(options) {
74
+ const conditions = [];
75
+ const parameters = [];
76
+ if (options.actorType) {
77
+ conditions.push("actor_type = ?");
78
+ parameters.push(options.actorType);
79
+ }
80
+ if (options.actorId) {
81
+ const expression = this.substringExpression("actor_id");
82
+ conditions.push(expression);
83
+ parameters.push(options.actorId);
84
+ }
85
+ return this.page({
86
+ from: this.table("instances"),
87
+ ...(conditions.length === 0 ? {} : { where: conditions.join(" AND ") }),
88
+ parameters,
89
+ order: "updated_at_ms DESC, id DESC",
90
+ }, options);
91
+ }
92
+ mailbox(options) {
93
+ const membership = options.membership === "claimed" ? "claimed_messages" : "ready_messages";
94
+ const timeColumn = membership === "claimed_messages" ? "membership.claimed_at_ms" : "membership.available_at_ms";
95
+ return this.page({
96
+ from: `${this.table("messages")} messages
97
+ INNER JOIN ${this.table(membership)} membership ON membership.message_id = messages.id`,
98
+ order: `${timeColumn} ASC, messages.id ASC`,
99
+ }, options);
100
+ }
101
+ reminders(options) {
102
+ return this.statusPage({
103
+ table: "reminders",
104
+ statuses: REMINDER_STATUSES,
105
+ order: "run_at_ms ASC, id ASC",
106
+ options,
107
+ });
108
+ }
109
+ effects(options) {
110
+ return this.statusPage({
111
+ table: "effects",
112
+ statuses: EFFECT_STATUSES,
113
+ order: "available_at_ms DESC, id DESC",
114
+ options,
115
+ });
116
+ }
117
+ broadcasts(options) {
118
+ return this.statusPage({
119
+ table: "broadcasts",
120
+ statuses: BROADCAST_STATUSES,
121
+ order: "available_at_ms DESC, id DESC",
122
+ options,
123
+ });
124
+ }
125
+ deadLetters(options) {
126
+ return this.page({
127
+ from: `${this.table("dead_letters")} dead_letters
128
+ INNER JOIN ${this.table("messages")} messages ON messages.id = dead_letters.message_id`,
129
+ select: "dead_letters.id, dead_letters.message_id, dead_letters.instance_id, dead_letters.attempts, dead_letters.error, dead_letters.created_at_ms, dead_letters.retried_message_id, messages.actor_type, messages.actor_id, messages.operation, messages.delivery_mode, messages.arguments",
130
+ order: "dead_letters.created_at_ms DESC, dead_letters.id DESC",
131
+ }, options);
132
+ }
133
+ processes(options) {
134
+ return this.statusPage({
135
+ table: "processes",
136
+ statusColumn: "shutdown_state",
137
+ statuses: PROCESS_STATUSES,
138
+ order: "heartbeat_at_ms DESC, id DESC",
139
+ options,
140
+ });
141
+ }
142
+ async instance(id) {
143
+ return this.runtime.settings.database.connection(async (connection) => {
144
+ const instance = await connection.get(`SELECT * FROM ${this.table("instances")} WHERE id = ?`, [id]);
145
+ if (!instance)
146
+ return undefined;
147
+ const related = { instanceId: id, limit: 10 };
148
+ const [readyMessages, claimedMessages, recentMessages, reminders, effects, broadcasts, deadLetters,] = await Promise.all([
149
+ connection.all(`SELECT messages.*, membership.available_at_ms
150
+ FROM ${this.table("messages")} messages
151
+ INNER JOIN ${this.table("ready_messages")} membership ON membership.message_id = messages.id
152
+ WHERE messages.instance_id = ? ORDER BY messages.sequence ASC LIMIT ?`, [related.instanceId, related.limit]),
153
+ connection.all(`SELECT messages.*, membership.claimed_at_ms
154
+ FROM ${this.table("messages")} messages
155
+ INNER JOIN ${this.table("claimed_messages")} membership ON membership.message_id = messages.id
156
+ WHERE messages.instance_id = ? ORDER BY messages.sequence ASC LIMIT ?`, [related.instanceId, related.limit]),
157
+ connection.all(`SELECT * FROM ${this.table("messages")} WHERE instance_id = ?
158
+ ORDER BY sequence DESC LIMIT ?`, [related.instanceId, related.limit]),
159
+ connection.all(`SELECT * FROM ${this.table("reminders")} WHERE instance_id = ?
160
+ ORDER BY run_at_ms ASC LIMIT ?`, [related.instanceId, related.limit]),
161
+ connection.all(`SELECT * FROM ${this.table("effects")} WHERE instance_id = ?
162
+ ORDER BY available_at_ms DESC LIMIT ?`, [related.instanceId, related.limit]),
163
+ connection.all(`SELECT * FROM ${this.table("broadcasts")} WHERE instance_id = ?
164
+ ORDER BY available_at_ms DESC LIMIT ?`, [related.instanceId, related.limit]),
165
+ connection.all(`SELECT dead_letters.*, messages.actor_type, messages.actor_id, messages.operation,
166
+ messages.delivery_mode, messages.arguments
167
+ FROM ${this.table("dead_letters")} dead_letters
168
+ INNER JOIN ${this.table("messages")} messages ON messages.id = dead_letters.message_id
169
+ WHERE dead_letters.instance_id = ? ORDER BY dead_letters.created_at_ms DESC LIMIT ?`, [related.instanceId, related.limit]),
170
+ ]);
171
+ return Object.freeze({
172
+ instance: freezeRecord(instance),
173
+ readyMessages: freezeRecords(readyMessages),
174
+ claimedMessages: freezeRecords(claimedMessages),
175
+ recentMessages: freezeRecords(recentMessages),
176
+ reminders: freezeRecords(reminders),
177
+ effects: freezeRecords(effects),
178
+ broadcasts: freezeRecords(broadcasts),
179
+ deadLetters: freezeRecords(deadLetters),
180
+ });
181
+ });
182
+ }
183
+ message(id) {
184
+ return this.runtime.settings.database.connection(async (connection) => {
185
+ const record = await connection.get(`SELECT messages.*,
186
+ CASE WHEN ready.message_id IS NOT NULL THEN 'ready'
187
+ WHEN claimed.message_id IS NOT NULL THEN 'claimed'
188
+ WHEN messages.completed_at_ms IS NOT NULL THEN 'completed'
189
+ ELSE 'history' END AS membership
190
+ FROM ${this.table("messages")} messages
191
+ LEFT JOIN ${this.table("ready_messages")} ready ON ready.message_id = messages.id
192
+ LEFT JOIN ${this.table("claimed_messages")} claimed ON claimed.message_id = messages.id
193
+ WHERE messages.id = ?`, [id]);
194
+ return record ? freezeRecord(record) : undefined;
195
+ });
196
+ }
197
+ deadLetter(id) {
198
+ return this.runtime.settings.database.connection(async (connection) => {
199
+ const record = await connection.get(`SELECT dead_letters.*, messages.actor_type, messages.actor_id, messages.operation,
200
+ messages.delivery_mode, messages.arguments
201
+ FROM ${this.table("dead_letters")} dead_letters
202
+ INNER JOIN ${this.table("messages")} messages ON messages.id = dead_letters.message_id
203
+ WHERE dead_letters.id = ?`, [id]);
204
+ return record ? freezeRecord(record) : undefined;
205
+ });
206
+ }
207
+ async dashboard() {
208
+ return this.runtime.settings.database.connection(async (connection) => {
209
+ const [processes, deadLetters, instancesByType] = await Promise.all([
210
+ connection.all(`SELECT * FROM ${this.table("processes")} ORDER BY heartbeat_at_ms DESC LIMIT 10`),
211
+ connection.all(`SELECT dead_letters.*, messages.actor_type, messages.actor_id, messages.operation
212
+ FROM ${this.table("dead_letters")} dead_letters
213
+ INNER JOIN ${this.table("messages")} messages ON messages.id = dead_letters.message_id
214
+ ORDER BY dead_letters.created_at_ms DESC LIMIT 10`),
215
+ connection.all(`SELECT actor_type, COUNT(*) AS count FROM ${this.table("instances")}
216
+ GROUP BY actor_type ORDER BY count DESC LIMIT 12`),
217
+ ]);
218
+ return freezeRecord({
219
+ processes: freezeRecords(processes),
220
+ deadLetters: freezeRecords(deadLetters),
221
+ instancesByType: freezeRecords(instancesByType),
222
+ });
223
+ });
224
+ }
225
+ async setPaused(options) {
226
+ const result = await this.runtime.settings.database.transaction(async (connection) => {
227
+ const now = await connection.nowMilliseconds();
228
+ return connection.run(`UPDATE ${this.table("instances")} SET paused = ?, updated_at_ms = ? WHERE id = ?`, [options.paused, now, options.id]);
229
+ });
230
+ return result.changes > 0;
231
+ }
232
+ async healthy() {
233
+ await this.runtime.settings.database.connection((connection) => connection.get(`SELECT 1 AS healthy FROM ${this.table("schema_migrations")} LIMIT 1`));
234
+ }
235
+ async page(query, options) {
236
+ const perPage = boundedInteger(options.perPage, { fallback: 25, maximum: 200 });
237
+ return this.runtime.settings.database.connection(async (connection) => {
238
+ const where = query.where ? ` WHERE ${query.where}` : "";
239
+ const parameters = [...(query.parameters ?? [])];
240
+ const count = await connection.get(`SELECT COUNT(*) AS count FROM ${query.from}${where}`, parameters);
241
+ const total = numeric(count?.count);
242
+ const lastPage = Math.max(Math.ceil(total / perPage), 1);
243
+ const page = Math.min(boundedInteger(options.page, { fallback: 1, maximum: lastPage }), lastPage);
244
+ const records = await connection.all(`SELECT ${query.select ?? "*"} FROM ${query.from}${where} ORDER BY ${query.order} LIMIT ? OFFSET ?`, [...parameters, perPage, (page - 1) * perPage]);
245
+ return Object.freeze({
246
+ records: freezeRecords(records),
247
+ page,
248
+ perPage,
249
+ total,
250
+ lastPage,
251
+ });
252
+ });
253
+ }
254
+ statusPage(options) {
255
+ const status = options.statuses.includes(options.options.status ?? "")
256
+ ? options.options.status
257
+ : undefined;
258
+ const statusColumn = options.statusColumn ?? "status";
259
+ return this.page({
260
+ from: this.table(options.table),
261
+ ...(status ? { where: `${statusColumn} = ?`, parameters: [status] } : {}),
262
+ order: options.order,
263
+ }, options.options);
264
+ }
265
+ async grouped(options) {
266
+ const { connection, table, column, statuses } = options;
267
+ const rows = await connection.all(`SELECT ${column} AS status, COUNT(*) AS count FROM ${this.table(table)} GROUP BY ${column}`);
268
+ const counts = new Map(rows.map((row) => [row.status, numeric(row.count)]));
269
+ return freezeRecord(Object.fromEntries(statuses.map((status) => [status, counts.get(status) ?? 0])));
270
+ }
271
+ substringExpression(column) {
272
+ if (this.runtime.settings.database.family === "sqlite")
273
+ return `instr(${column}, ?) > 0`;
274
+ if (this.runtime.settings.database.family === "postgresql")
275
+ return `POSITION(? IN ${column}) > 0`;
276
+ return `LOCATE(?, ${column}) > 0`;
277
+ }
278
+ table(name) {
279
+ return this.runtime.repository.table(name);
280
+ }
281
+ }
282
+ function boundedInteger(value, options) {
283
+ const parsed = Number.parseInt(value ?? "", 10);
284
+ if (!Number.isSafeInteger(parsed) || parsed < 1)
285
+ return options.fallback;
286
+ return Math.min(parsed, options.maximum);
287
+ }
288
+ function numeric(value) {
289
+ if (typeof value === "number")
290
+ return value;
291
+ if (typeof value === "bigint")
292
+ return Number(value);
293
+ if (typeof value === "string")
294
+ return Number(value);
295
+ return 0;
296
+ }
297
+ function freezeRecord(record) {
298
+ return Object.freeze(record);
299
+ }
300
+ function freezeRecords(records) {
301
+ return Object.freeze(records.map(freezeRecord));
302
+ }
303
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/web/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { SolidObjectsRuntime } from "../runtime.js";
3
+ export interface DashboardSession {
4
+ read(key: string): string | undefined | Promise<string | undefined>;
5
+ write(key: string, value: string): void | Promise<void>;
6
+ }
7
+ export interface DashboardRequestContext {
8
+ readonly authorizationContext?: unknown;
9
+ readonly session?: DashboardSession;
10
+ }
11
+ export type DashboardAccess = "authorized" | "authorized-read-only" | "public-read-only";
12
+ export interface DashboardPolicy {
13
+ readonly action: string;
14
+ readonly resource: string;
15
+ }
16
+ export interface DashboardPage {
17
+ readonly title: string;
18
+ readonly content: string;
19
+ readonly status?: number;
20
+ }
21
+ export interface DashboardRenderInput {
22
+ readonly name: string;
23
+ readonly model: Readonly<Record<string, unknown>>;
24
+ readonly defaultHtml: string;
25
+ }
26
+ export type DashboardRenderer = (input: DashboardRenderInput) => string;
27
+ export interface DashboardRouteContext {
28
+ readonly request: Request;
29
+ readonly requestContext: DashboardRequestContext;
30
+ readonly params: Readonly<Record<string, string>>;
31
+ readonly runtime: SolidObjectsRuntime;
32
+ path(path: string): string;
33
+ render(page: DashboardPage): Response;
34
+ escape(value: unknown): string;
35
+ }
36
+ export interface DashboardRoute {
37
+ readonly method: "GET" | "HEAD" | "POST";
38
+ readonly path: string;
39
+ readonly policy: DashboardPolicy;
40
+ handle(context: DashboardRouteContext): DashboardPage | Response | Promise<DashboardPage | Response>;
41
+ }
42
+ export interface DashboardTab {
43
+ readonly label: string;
44
+ readonly path: string;
45
+ }
46
+ export interface DashboardExtension {
47
+ readonly tab?: DashboardTab;
48
+ readonly routes?: readonly DashboardRoute[];
49
+ readonly renderers?: Readonly<Record<string, DashboardRenderer>>;
50
+ readonly middleware?: readonly DashboardMiddleware[];
51
+ }
52
+ export interface DashboardMiddlewareInput {
53
+ readonly request: Request;
54
+ readonly requestContext: DashboardRequestContext;
55
+ }
56
+ export type DashboardMiddleware = (input: DashboardMiddlewareInput, next: () => Promise<Response>) => Promise<Response>;
57
+ export interface DashboardChartLibrary {
58
+ readonly url: string | null;
59
+ readonly integrity?: string | null;
60
+ }
61
+ export interface DashboardOptions {
62
+ readonly runtime: SolidObjectsRuntime;
63
+ readonly mountPath?: string;
64
+ readonly access?: DashboardAccess;
65
+ readonly chartLibrary?: DashboardChartLibrary;
66
+ readonly extensions?: readonly DashboardExtension[];
67
+ readonly middleware?: readonly DashboardMiddleware[];
68
+ }
69
+ export interface NodeDashboardRequestContextResolver {
70
+ (request: IncomingMessage): DashboardRequestContext | Promise<DashboardRequestContext>;
71
+ }
72
+ export interface NodeDashboardHandlerOptions {
73
+ readonly dashboard: SolidObjectsDashboardContract;
74
+ readonly resolveContext: NodeDashboardRequestContextResolver;
75
+ readonly maximumBodyBytes?: number;
76
+ }
77
+ export interface SolidObjectsDashboardContract {
78
+ readonly mountPath: string;
79
+ fetch(request: Request, context: DashboardRequestContext): Promise<Response>;
80
+ }
81
+ export type NodeDashboardHandler = (...argumentsValue: [IncomingMessage, ServerResponse, ((error?: unknown) => void)?]) => void;
82
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/web/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/web/types.ts"],"names":[],"mappings":""}
package/docs/api.md CHANGED
@@ -16,6 +16,11 @@ generic signatures; this index explains the supported role of every export.
16
16
  - `Actor`: base class providing `ref()`, `actorId`, `currentMessage`,
17
17
  `observables()`, `reject()`, `emit()`, `commitAction()`, `schedule()`,
18
18
  `sendTo()`, and protected lifecycle hooks.
19
+ - `broadcastValue(value)`: mark an observable so its changed value enters the
20
+ durable invalidation envelope.
21
+ - `broadcastInvalidation(value)`: compare the real observable value but put
22
+ only its name in the durable envelope when it changes.
23
+ - `ObservableBroadcast`: the immutable marker type returned by either helper.
19
24
  - `VERSION`: running package version.
20
25
  - `ActorClass`, `ActorReference`, `ActorMessageSender`, `ActorSnapshot`,
21
26
  `ActorOperationNames`, `ActorQueryNames`, `StagedOperations`, and
@@ -31,6 +36,49 @@ generic signatures; this index explains the supported role of every export.
31
36
  `PayloadBroadcasts`, and `PayloadBroadcastValue` describe actor-declared
32
37
  transactional work and typed personalized projections.
33
38
 
39
+ `observables()` returns a flat object. Unwrapped values are invalidation-only:
40
+ their real values participate in change detection, but only their names enter
41
+ the durable envelope. Use an explicit marker when wire behavior matters:
42
+
43
+ ```typescript
44
+ override observables(): Record<string, unknown> {
45
+ return {
46
+ version: broadcastValue(this.document.version),
47
+ sidebar: broadcastInvalidation(this.sidebarForCurrentState()),
48
+ }
49
+ }
50
+ ```
51
+
52
+ Both values must be JSON-compatible and are evaluated after each successful
53
+ turn. An invalidation-only value participates in change detection but is never
54
+ written to the broadcast outbox or invalidation envelope. The envelope carries
55
+ its name in `invalidations`, allowing component registries to refresh a
56
+ reauthorized endpoint without exposing the value.
57
+
58
+ `MessageReference` does not retain an invocation's authorization context.
59
+ Supply `authorizationContext` to each `status()`, `result()`, and `wait()` call;
60
+ the runtime reauthorizes the persisted operation every time. Durable results
61
+ are JSON, so an operation that returns `undefined` or is declared `void`
62
+ resolves as `null`.
63
+
64
+ Declare named payload return shapes with a `type` alias rather than an
65
+ `interface`. `PayloadBroadcastValue` requires the implicit string index
66
+ signature of a JSON object, which TypeScript gives object type aliases but not
67
+ interfaces.
68
+
69
+ Snapshots return `DeepReadonly`, so application helpers should accept readonly
70
+ structure rather than cast it away. A helper that only needs a session ID can
71
+ preserve its useful result type with a generic boundary:
72
+
73
+ ```typescript
74
+ function playerForSession<PlayerType extends { sessionId: string }>(options: {
75
+ room: { readonly players: readonly PlayerType[] }
76
+ sessionId: string | null
77
+ }): PlayerType | undefined {
78
+ return options.room.players.find((player) => player.sessionId === options.sessionId)
79
+ }
80
+ ```
81
+
34
82
  ### Runtime managers
35
83
 
36
84
  Every manager below is available as a property on `SolidObjectsRuntime`; the
@@ -48,7 +96,7 @@ class and result types are also exported for integration typing.
48
96
  - `runtime.doctor` / `Doctor`: `run({ roundTrip })` structured installation
49
97
  report.
50
98
  - `runtime.testing` / `SolidObjectsTestHelper`: deterministic `drain()` and
51
- dependency-ordered `reset()`.
99
+ explicit-time `runDueReminders()`, plus dependency-ordered `reset()`.
52
100
  - `runtime.realtime` / `RealtimeManager`: `connect()`, process-local
53
101
  `publish()`, and `close()`.
54
102
 
@@ -60,11 +108,20 @@ The manager types are `DeadLetter`; `ReminderPage`, `ReminderPageOptions`,
60
108
  `QuietReconciliationOptions`, `ReconciliationInstance`, `ReconciliationPage`,
61
109
  `ReconciliationPageOptions`, and `ReconciliationStatesOptions`;
62
110
  `RetentionOptions`, `RetentionResult`, and `RetentionTarget`; and
63
- `TestDrainOptions` and `TestHelperRole`. `RealtimeConnectionOptions`,
111
+ `RunDueRemindersOptions`, `TestDrainOptions`, and `TestHelperRole`.
112
+ `RealtimeConnectionOptions`,
64
113
  `RealtimeSession`, and `SubscriptionRequest` define the server session API.
65
114
  `AdministrationOptions` carries the application-owned authorization context
66
115
  for administration calls.
67
116
 
117
+ The packaged `solid-objects quickstart` command is config-free and runs the
118
+ SQLite example shipped in the npm artifact. Every other CLI command loads the
119
+ application runtime configured through `--config`.
120
+
121
+ `ProcessRecord.shutdownState` is `"running"`, `"draining"`, or `"stopped"`;
122
+ there is no separate `running` field. `RetentionResult.count` means eligible
123
+ rows for `preview()` and rows actually deleted for `prune()`.
124
+
68
125
  ### Registration and integration
69
126
 
70
127
  - `runtime.register(ActorClass)`: validate and register an actor definition.
@@ -72,7 +129,9 @@ for administration calls.
72
129
  isolated runtime.
73
130
  - `runtime.registerEffect(name, handler)`: register an at-least-once external
74
131
  effect handler. `EffectContext` carries the stable effect ID and source
75
- identity.
132
+ identity. Success operations receive `{ effectId, arguments, result }` and
133
+ failure operations receive `{ effectId, arguments, error }`; `arguments` is
134
+ the JSON object originally staged by `emit()`.
76
135
  - `runtime.registerCommitAction(name, handler)`: register a same-database
77
136
  fenced transaction handler. `CommitActionContext` includes the active
78
137
  `DatabaseConnection`.
@@ -93,6 +152,11 @@ for administration calls.
93
152
  `DatabaseConnection`, `DatabaseFamily`, and `RunResult` support custom database
94
153
  and commit-action integration.
95
154
 
155
+ `BroadcastEvent.observables` contains changed value-broadcast projections.
156
+ `BroadcastEvent.invalidations` contains changed invalidation-only names. The
157
+ runtime always supplies the array; consumers should treat its absence from an
158
+ older or application-produced event as an empty array.
159
+
96
160
  ### Runtime extensions and manual workers
97
161
 
98
162
  `runtime.registerComponent(factory, { count = 1 })` adds application-owned
@@ -134,7 +198,8 @@ The root exports `SolidObjectsError` and its supported subclasses:
134
198
  - admission and payload failures: `MailboxFull`, `InvalidPayload`,
135
199
  `PayloadTooLarge`, `IdempotencyConflict`, `InvalidPayloadBroadcast`, and
136
200
  `UnknownPayloadBroadcast`;
137
- - definition and execution failures: `InvalidActor`, `UnknownActorType`,
201
+ - definition and execution failures: `InvalidActor`, `InvalidRejectionCode`,
202
+ `UnknownActorType`,
138
203
  `UnknownOperation`, `ActorCallCycle`, `QueryMutatedState`,
139
204
  `StateMigrationError`, `ApplicationWriteForbidden`, `UnknownEffect`, and
140
205
  `UnknownCommitAction`;
@@ -193,5 +258,35 @@ and `SyncTimeoutWaitingOn` type timeout diagnostics. See
193
258
  `ComponentRefreshFailure`, and `ComponentRegistryOptions`: framework-neutral
194
259
  refresh contract types.
195
260
 
261
+ `InvalidationEnvelope.observables` contains values and
262
+ `InvalidationEnvelope.invalidations` contains names without values. The
263
+ component registry reacts to names in either location.
264
+
196
265
  The wire format, trust boundary, revision rules, and component semantics are in
197
266
  [Browser protocol](browser-protocol.md).
267
+
268
+ ## `solid-objects/web`
269
+
270
+ - `createDashboard(options)` creates an immutable `SolidObjectsDashboard` with
271
+ a standard `fetch(request, context)` entry point.
272
+ - `createNodeDashboardHandler(options)` adapts the Fetch entry point to
273
+ `node:http` and Connect-compatible middleware.
274
+ - `DashboardOptions` selects the runtime, mount path, `DashboardAccess`, chart library,
275
+ `DashboardExtension` objects, and `DashboardMiddleware` functions.
276
+ - `DashboardRequestContext` supplies the existing administration authorization
277
+ context and an optional `DashboardSession`. Read/write access requires the
278
+ session so its `read()` and `write()` methods can hold the masked CSRF token
279
+ across requests; read-only modes do not create CSRF state.
280
+ - `DashboardRoute`, `DashboardRouteContext`, `DashboardPolicy`, `DashboardPage`,
281
+ and `DashboardTab` define extension pages. Every route requires a policy.
282
+ - `DashboardRenderer`, `DashboardRenderInput`, and `DashboardMiddlewareInput`
283
+ define immutable view overrides and middleware inputs.
284
+ - `DashboardChartLibrary` selects the CDN, a self-hosted script, or disabled
285
+ charts.
286
+ - `NodeDashboardHandler`, `NodeDashboardHandlerOptions`, and
287
+ `NodeDashboardRequestContextResolver` describe the Node adapter.
288
+ - `SolidObjectsDashboardContract` is the minimal Fetch contract accepted by the
289
+ Node adapter.
290
+
291
+ Mounting, authorization actions, CSRF behavior, pages, and extensions are in
292
+ [Operator dashboard](dashboard.md).