@earendil-works/pi-durable 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 (142) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +128 -3
  3. package/dist/codemode/codemode.d.ts.map +1 -1
  4. package/dist/codemode/codemode.js +12 -4
  5. package/dist/codemode/codemode.js.map +1 -1
  6. package/dist/codemode/models.d.ts.map +1 -1
  7. package/dist/codemode/models.js +2 -0
  8. package/dist/codemode/models.js.map +1 -1
  9. package/dist/documents.d.ts +1 -1
  10. package/dist/documents.d.ts.map +1 -1
  11. package/dist/documents.js.map +1 -1
  12. package/dist/env/index.d.ts +1 -0
  13. package/dist/env/index.d.ts.map +1 -1
  14. package/dist/env/index.js.map +1 -1
  15. package/dist/env/node.d.ts.map +1 -1
  16. package/dist/env/node.js +11 -3
  17. package/dist/env/node.js.map +1 -1
  18. package/dist/harness/agent.d.ts +13 -2
  19. package/dist/harness/agent.d.ts.map +1 -1
  20. package/dist/harness/agent.js +39 -5
  21. package/dist/harness/agent.js.map +1 -1
  22. package/dist/harness/compaction.d.ts +3 -1
  23. package/dist/harness/compaction.d.ts.map +1 -1
  24. package/dist/harness/compaction.js +19 -4
  25. package/dist/harness/compaction.js.map +1 -1
  26. package/dist/harness/context.d.ts +5 -0
  27. package/dist/harness/context.d.ts.map +1 -1
  28. package/dist/harness/context.js +46 -12
  29. package/dist/harness/context.js.map +1 -1
  30. package/dist/harness/generation.d.ts.map +1 -1
  31. package/dist/harness/generation.js +67 -27
  32. package/dist/harness/generation.js.map +1 -1
  33. package/dist/harness/harness.d.ts +5 -2
  34. package/dist/harness/harness.d.ts.map +1 -1
  35. package/dist/harness/harness.js +78 -13
  36. package/dist/harness/harness.js.map +1 -1
  37. package/dist/harness/inbox.d.ts +2 -2
  38. package/dist/harness/inbox.d.ts.map +1 -1
  39. package/dist/harness/inbox.js +3 -3
  40. package/dist/harness/inbox.js.map +1 -1
  41. package/dist/harness/prompt.d.ts +1 -1
  42. package/dist/harness/prompt.d.ts.map +1 -1
  43. package/dist/harness/prompt.js +1 -1
  44. package/dist/harness/prompt.js.map +1 -1
  45. package/dist/harness/scheduler.d.ts +55 -10
  46. package/dist/harness/scheduler.d.ts.map +1 -1
  47. package/dist/harness/scheduler.js +617 -124
  48. package/dist/harness/scheduler.js.map +1 -1
  49. package/dist/harness/submissions.d.ts +7 -2
  50. package/dist/harness/submissions.d.ts.map +1 -1
  51. package/dist/harness/submissions.js +48 -17
  52. package/dist/harness/submissions.js.map +1 -1
  53. package/dist/harness/task-graph.d.ts +18 -1
  54. package/dist/harness/task-graph.d.ts.map +1 -1
  55. package/dist/harness/task-graph.js +50 -11
  56. package/dist/harness/task-graph.js.map +1 -1
  57. package/dist/harness/telemetry.d.ts +307 -0
  58. package/dist/harness/telemetry.d.ts.map +1 -0
  59. package/dist/harness/telemetry.js +136 -0
  60. package/dist/harness/telemetry.js.map +1 -0
  61. package/dist/harness/tool.d.ts.map +1 -1
  62. package/dist/harness/tool.js +54 -8
  63. package/dist/harness/tool.js.map +1 -1
  64. package/dist/harness/types.d.ts +110 -15
  65. package/dist/harness/types.d.ts.map +1 -1
  66. package/dist/harness/types.js.map +1 -1
  67. package/dist/harness/util.d.ts +4 -0
  68. package/dist/harness/util.d.ts.map +1 -1
  69. package/dist/harness/util.js +4 -0
  70. package/dist/harness/util.js.map +1 -1
  71. package/dist/index.d.ts +6 -4
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +3 -2
  74. package/dist/index.js.map +1 -1
  75. package/dist/session/session.d.ts +17 -6
  76. package/dist/session/session.d.ts.map +1 -1
  77. package/dist/session/session.js +64 -32
  78. package/dist/session/session.js.map +1 -1
  79. package/dist/session/transaction.d.ts +5 -1
  80. package/dist/session/transaction.d.ts.map +1 -1
  81. package/dist/session/transaction.js +26 -1
  82. package/dist/session/transaction.js.map +1 -1
  83. package/dist/storage/indexeddb.d.ts +60 -0
  84. package/dist/storage/indexeddb.d.ts.map +1 -0
  85. package/dist/storage/indexeddb.js +831 -0
  86. package/dist/storage/indexeddb.js.map +1 -0
  87. package/dist/storage/jsonl/storage.d.ts +16 -0
  88. package/dist/storage/jsonl/storage.d.ts.map +1 -1
  89. package/dist/storage/memory.js +1 -1
  90. package/dist/storage/memory.js.map +1 -1
  91. package/dist/storage/sqlite/cloudflare.d.ts +6 -43
  92. package/dist/storage/sqlite/cloudflare.d.ts.map +1 -1
  93. package/dist/storage/sqlite/cloudflare.js +6 -101
  94. package/dist/storage/sqlite/cloudflare.js.map +1 -1
  95. package/dist/storage/sqlite/database.d.ts +1 -36
  96. package/dist/storage/sqlite/database.d.ts.map +1 -1
  97. package/dist/storage/sqlite/database.js.map +1 -1
  98. package/dist/storage/sqlite/index.d.ts +2 -2
  99. package/dist/storage/sqlite/index.d.ts.map +1 -1
  100. package/dist/storage/sqlite/index.js.map +1 -1
  101. package/dist/storage/sqlite/migrations.d.ts +7 -6
  102. package/dist/storage/sqlite/migrations.d.ts.map +1 -1
  103. package/dist/storage/sqlite/migrations.js +116 -106
  104. package/dist/storage/sqlite/migrations.js.map +1 -1
  105. package/dist/storage/sqlite/node.d.ts +6 -39
  106. package/dist/storage/sqlite/node.d.ts.map +1 -1
  107. package/dist/storage/sqlite/node.js +8 -175
  108. package/dist/storage/sqlite/node.js.map +1 -1
  109. package/dist/storage/sqlite/schema.d.ts +45 -0
  110. package/dist/storage/sqlite/schema.d.ts.map +1 -0
  111. package/dist/storage/sqlite/schema.js +50 -0
  112. package/dist/storage/sqlite/schema.js.map +1 -0
  113. package/dist/storage/sqlite/storage.d.ts +10 -2
  114. package/dist/storage/sqlite/storage.d.ts.map +1 -1
  115. package/dist/storage/sqlite/storage.js +46 -43
  116. package/dist/storage/sqlite/storage.js.map +1 -1
  117. package/dist/testing/storage-conformance.d.ts.map +1 -1
  118. package/dist/testing/storage-conformance.js +17 -0
  119. package/dist/testing/storage-conformance.js.map +1 -1
  120. package/dist/timers.d.ts +21 -0
  121. package/dist/timers.d.ts.map +1 -0
  122. package/dist/timers.js +72 -0
  123. package/dist/timers.js.map +1 -0
  124. package/dist/tools/image-processor.d.ts +4 -1
  125. package/dist/tools/image-processor.d.ts.map +1 -1
  126. package/dist/tools/image-processor.js +8 -18
  127. package/dist/tools/image-processor.js.map +1 -1
  128. package/dist/tools/read.d.ts.map +1 -1
  129. package/dist/tools/read.js +1 -1
  130. package/dist/tools/read.js.map +1 -1
  131. package/dist/truncate.d.ts +3 -2
  132. package/dist/truncate.d.ts.map +1 -1
  133. package/dist/truncate.js +4 -34
  134. package/dist/truncate.js.map +1 -1
  135. package/dist/types.d.ts +130 -9
  136. package/dist/types.d.ts.map +1 -1
  137. package/dist/types.js.map +1 -1
  138. package/package.json +15 -5
  139. package/dist/harness/output.d.ts +0 -69
  140. package/dist/harness/output.d.ts.map +0 -1
  141. package/dist/harness/output.js +0 -318
  142. package/dist/harness/output.js.map +0 -1
@@ -0,0 +1,45 @@
1
+ export { validateSqliteSchemaPrefix } from "@earendil-works/chord/sqlite";
2
+ /**
3
+ * Immutable identifier history for migrations and runtime queries. Never change or remove an existing value; a
4
+ * rename adds a new entry so historical migrations keep rendering their original object names.
5
+ */
6
+ declare const TABLE_NAMES: {
7
+ readonly durableSchema: "durable_schema";
8
+ readonly durableMetadata: "durable_metadata";
9
+ readonly recordIds: "record_ids";
10
+ readonly conversations: "conversations";
11
+ readonly entries: "entries";
12
+ readonly tasks: "tasks";
13
+ readonly submissions: "submissions";
14
+ readonly documents: "documents";
15
+ readonly documentRevisions: "document_revisions";
16
+ };
17
+ declare const INDEX_NAMES: {
18
+ readonly conversationsByOwnerConversation: "conversations_by_owner_conversation";
19
+ readonly conversationsByOwnerTask: "conversations_by_owner_task";
20
+ readonly entriesByConversation: "entries_by_conversation";
21
+ readonly entryHeadsByConversation: "entry_heads_by_conversation";
22
+ readonly tasksByStatus: "tasks_by_status";
23
+ readonly tasksByConversation: "tasks_by_conversation";
24
+ readonly tasksByKind: "tasks_by_kind";
25
+ readonly tasksByAbortRequested: "tasks_by_abort_requested";
26
+ readonly tasksByBackground: "tasks_by_background";
27
+ readonly submissionsByRequest: "submissions_by_request";
28
+ readonly submissionsByConversation: "submissions_by_conversation";
29
+ readonly submissionsByStatus: "submissions_by_status";
30
+ readonly documentsByAddress: "documents_by_address";
31
+ readonly documentsByScope: "documents_by_scope";
32
+ readonly documentsByScopeKind: "documents_by_scope_kind";
33
+ readonly documentRevisionsByKind: "document_revisions_by_kind";
34
+ };
35
+ type SqliteIdentifiers<T extends Record<string, string>> = {
36
+ readonly [K in keyof T]: string;
37
+ };
38
+ export type SqliteSchema = {
39
+ readonly tables: SqliteIdentifiers<typeof TABLE_NAMES>;
40
+ readonly indexes: SqliteIdentifiers<typeof INDEX_NAMES>;
41
+ };
42
+ /** Build the identifiers used by every migration and storage query. */
43
+ export declare function createSqliteSchema(prefix?: string): SqliteSchema;
44
+ export declare const DEFAULT_SQLITE_SCHEMA: SqliteSchema;
45
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/storage/sqlite/schema.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE1E;;;GAGG;AACH,QAAA,MAAM,WAAW;aAChB,aAAa,EAAE,gBAAgB;aAC/B,eAAe,EAAE,kBAAkB;aACnC,SAAS,EAAE,YAAY;aACvB,aAAa,EAAE,eAAe;aAC9B,OAAO,EAAE,SAAS;aAClB,KAAK,EAAE,OAAO;aACd,WAAW,EAAE,aAAa;aAC1B,SAAS,EAAE,WAAW;aACtB,iBAAiB,EAAE,oBAAoB;CAC9B,CAAC;AAEX,QAAA,MAAM,WAAW;aAChB,gCAAgC,EAAE,qCAAqC;aACvE,wBAAwB,EAAE,6BAA6B;aACvD,qBAAqB,EAAE,yBAAyB;aAChD,wBAAwB,EAAE,6BAA6B;aACvD,aAAa,EAAE,iBAAiB;aAChC,mBAAmB,EAAE,uBAAuB;aAC5C,WAAW,EAAE,eAAe;aAC5B,qBAAqB,EAAE,0BAA0B;aACjD,iBAAiB,EAAE,qBAAqB;aACxC,oBAAoB,EAAE,wBAAwB;aAC9C,yBAAyB,EAAE,6BAA6B;aACxD,mBAAmB,EAAE,uBAAuB;aAC5C,kBAAkB,EAAE,sBAAsB;aAC1C,gBAAgB,EAAE,oBAAoB;aACtC,oBAAoB,EAAE,yBAAyB;aAC/C,uBAAuB,EAAE,4BAA4B;CAC5C,CAAC;AAEX,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI;IAAE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM;CAAE,CAAC;AAE/F,MAAM,MAAM,YAAY,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,OAAO,WAAW,CAAC,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC,OAAO,WAAW,CAAC,CAAC;CACxD,CAAC;AAQF,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAOhE;AAED,eAAO,MAAM,qBAAqB,cAAuB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { validateSqliteSchemaPrefix } from "@earendil-works/chord/sqlite";
2
+ export { validateSqliteSchemaPrefix } from "@earendil-works/chord/sqlite";
3
+ /**
4
+ * Immutable identifier history for migrations and runtime queries. Never change or remove an existing value; a
5
+ * rename adds a new entry so historical migrations keep rendering their original object names.
6
+ */
7
+ const TABLE_NAMES = {
8
+ durableSchema: "durable_schema",
9
+ durableMetadata: "durable_metadata",
10
+ recordIds: "record_ids",
11
+ conversations: "conversations",
12
+ entries: "entries",
13
+ tasks: "tasks",
14
+ submissions: "submissions",
15
+ documents: "documents",
16
+ documentRevisions: "document_revisions",
17
+ };
18
+ const INDEX_NAMES = {
19
+ conversationsByOwnerConversation: "conversations_by_owner_conversation",
20
+ conversationsByOwnerTask: "conversations_by_owner_task",
21
+ entriesByConversation: "entries_by_conversation",
22
+ entryHeadsByConversation: "entry_heads_by_conversation",
23
+ tasksByStatus: "tasks_by_status",
24
+ tasksByConversation: "tasks_by_conversation",
25
+ tasksByKind: "tasks_by_kind",
26
+ tasksByAbortRequested: "tasks_by_abort_requested",
27
+ tasksByBackground: "tasks_by_background",
28
+ submissionsByRequest: "submissions_by_request",
29
+ submissionsByConversation: "submissions_by_conversation",
30
+ submissionsByStatus: "submissions_by_status",
31
+ documentsByAddress: "documents_by_address",
32
+ documentsByScope: "documents_by_scope",
33
+ documentsByScopeKind: "documents_by_scope_kind",
34
+ documentRevisionsByKind: "document_revisions_by_kind",
35
+ };
36
+ function prefixIdentifiers(names, prefix) {
37
+ return Object.fromEntries(Object.entries(names).map(([key, name]) => [key, `${prefix}${name}`]));
38
+ }
39
+ /** Build the identifiers used by every migration and storage query. */
40
+ export function createSqliteSchema(prefix) {
41
+ if (prefix !== undefined)
42
+ validateSqliteSchemaPrefix(prefix);
43
+ const actualPrefix = prefix ?? "";
44
+ return {
45
+ tables: prefixIdentifiers(TABLE_NAMES, actualPrefix),
46
+ indexes: prefixIdentifiers(INDEX_NAMES, actualPrefix),
47
+ };
48
+ }
49
+ export const DEFAULT_SQLITE_SCHEMA = createSqliteSchema();
50
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/storage/sqlite/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE1E;;;GAGG;AACH,MAAM,WAAW,GAAG;IACnB,aAAa,EAAE,gBAAgB;IAC/B,eAAe,EAAE,kBAAkB;IACnC,SAAS,EAAE,YAAY;IACvB,aAAa,EAAE,eAAe;IAC9B,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,aAAa;IAC1B,SAAS,EAAE,WAAW;IACtB,iBAAiB,EAAE,oBAAoB;CAC9B,CAAC;AAEX,MAAM,WAAW,GAAG;IACnB,gCAAgC,EAAE,qCAAqC;IACvE,wBAAwB,EAAE,6BAA6B;IACvD,qBAAqB,EAAE,yBAAyB;IAChD,wBAAwB,EAAE,6BAA6B;IACvD,aAAa,EAAE,iBAAiB;IAChC,mBAAmB,EAAE,uBAAuB;IAC5C,WAAW,EAAE,eAAe;IAC5B,qBAAqB,EAAE,0BAA0B;IACjD,iBAAiB,EAAE,qBAAqB;IACxC,oBAAoB,EAAE,wBAAwB;IAC9C,yBAAyB,EAAE,6BAA6B;IACxD,mBAAmB,EAAE,uBAAuB;IAC5C,kBAAkB,EAAE,sBAAsB;IAC1C,gBAAgB,EAAE,oBAAoB;IACtC,oBAAoB,EAAE,yBAAyB;IAC/C,uBAAuB,EAAE,4BAA4B;CAC5C,CAAC;AASX,SAAS,iBAAiB,CAAmC,KAAQ,EAAE,MAAc;IACpF,OAAO,MAAM,CAAC,WAAW,CACxB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC,CAC7C,CAAC;AAC3B,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,kBAAkB,CAAC,MAAe;IACjD,IAAI,MAAM,KAAK,SAAS;QAAE,0BAA0B,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,YAAY,GAAG,MAAM,IAAI,EAAE,CAAC;IAClC,OAAO;QACN,MAAM,EAAE,iBAAiB,CAAC,WAAW,EAAE,YAAY,CAAC;QACpD,OAAO,EAAE,iBAAiB,CAAC,WAAW,EAAE,YAAY,CAAC;KACrD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,EAAE,CAAC","sourcesContent":["import { validateSqliteSchemaPrefix } from \"@earendil-works/chord/sqlite\";\n\nexport { validateSqliteSchemaPrefix } from \"@earendil-works/chord/sqlite\";\n\n/**\n * Immutable identifier history for migrations and runtime queries. Never change or remove an existing value; a\n * rename adds a new entry so historical migrations keep rendering their original object names.\n */\nconst TABLE_NAMES = {\n\tdurableSchema: \"durable_schema\",\n\tdurableMetadata: \"durable_metadata\",\n\trecordIds: \"record_ids\",\n\tconversations: \"conversations\",\n\tentries: \"entries\",\n\ttasks: \"tasks\",\n\tsubmissions: \"submissions\",\n\tdocuments: \"documents\",\n\tdocumentRevisions: \"document_revisions\",\n} as const;\n\nconst INDEX_NAMES = {\n\tconversationsByOwnerConversation: \"conversations_by_owner_conversation\",\n\tconversationsByOwnerTask: \"conversations_by_owner_task\",\n\tentriesByConversation: \"entries_by_conversation\",\n\tentryHeadsByConversation: \"entry_heads_by_conversation\",\n\ttasksByStatus: \"tasks_by_status\",\n\ttasksByConversation: \"tasks_by_conversation\",\n\ttasksByKind: \"tasks_by_kind\",\n\ttasksByAbortRequested: \"tasks_by_abort_requested\",\n\ttasksByBackground: \"tasks_by_background\",\n\tsubmissionsByRequest: \"submissions_by_request\",\n\tsubmissionsByConversation: \"submissions_by_conversation\",\n\tsubmissionsByStatus: \"submissions_by_status\",\n\tdocumentsByAddress: \"documents_by_address\",\n\tdocumentsByScope: \"documents_by_scope\",\n\tdocumentsByScopeKind: \"documents_by_scope_kind\",\n\tdocumentRevisionsByKind: \"document_revisions_by_kind\",\n} as const;\n\ntype SqliteIdentifiers<T extends Record<string, string>> = { readonly [K in keyof T]: string };\n\nexport type SqliteSchema = {\n\treadonly tables: SqliteIdentifiers<typeof TABLE_NAMES>;\n\treadonly indexes: SqliteIdentifiers<typeof INDEX_NAMES>;\n};\n\nfunction prefixIdentifiers<T extends Record<string, string>>(names: T, prefix: string): SqliteIdentifiers<T> {\n\treturn Object.fromEntries(\n\t\tObject.entries(names).map(([key, name]) => [key, `${prefix}${name}`]),\n\t) as SqliteIdentifiers<T>;\n}\n\n/** Build the identifiers used by every migration and storage query. */\nexport function createSqliteSchema(prefix?: string): SqliteSchema {\n\tif (prefix !== undefined) validateSqliteSchemaPrefix(prefix);\n\tconst actualPrefix = prefix ?? \"\";\n\treturn {\n\t\ttables: prefixIdentifiers(TABLE_NAMES, actualPrefix),\n\t\tindexes: prefixIdentifiers(INDEX_NAMES, actualPrefix),\n\t};\n}\n\nexport const DEFAULT_SQLITE_SCHEMA = createSqliteSchema();\n"]}
@@ -1,10 +1,18 @@
1
1
  import type { Context, JsonValue } from "@earendil-works/chord";
2
+ import type { SqliteDatabase } from "@earendil-works/chord/sqlite";
2
3
  import type { ConversationId, ConversationQuery, ConversationRecord, Cursor, DocumentAddress, DocumentId, DocumentPoint, DocumentQuery, DocumentRecord, EntryId, EntryQuery, EntryRecord, Id, Page, Seq, Storage, StorageWrite, StoredDocument, SubmissionId, SubmissionQuery, SubmissionRecord, TaskId, TaskQuery, TaskRecord } from "../../types.ts";
3
- import type { SqliteDatabase } from "./database.ts";
4
4
  type StoredTask = TaskRecord<JsonValue, JsonValue, JsonValue>;
5
+ export type SqliteStorageOptions = {
6
+ /**
7
+ * Prefix for every table and index in the durable schema. It must be a SQLite identifier and must not use
8
+ * SQLite's reserved `sqlite_` prefix. Existing data is not migrated when this changes.
9
+ */
10
+ readonly prefix?: string;
11
+ };
5
12
  /** Portable SQLite implementation of the Pico storage contract. */
6
13
  export declare class SqliteStorage implements Storage {
7
14
  private readonly db;
15
+ private readonly schema;
8
16
  private nextId;
9
17
  private closed;
10
18
  private closing;
@@ -12,7 +20,7 @@ export declare class SqliteStorage implements Storage {
12
20
  private readsDrained;
13
21
  private constructor();
14
22
  /** Initialize storage over an owned SQLite database facade. */
15
- static open(db: SqliteDatabase): Promise<SqliteStorage>;
23
+ static open(db: SqliteDatabase, options?: SqliteStorageOptions): Promise<SqliteStorage>;
16
24
  commit(writes: readonly StorageWrite[], _context: Context): Promise<Seq>;
17
25
  mintId<I extends Id<string>>(): Promise<I>;
18
26
  conversation(id: ConversationId, _context: Context): Promise<ConversationRecord | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/storage/sqlite/storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/storage/sqlite/storage.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,8 @@ import { apply } from "@earendil-works/chord/delta";
2
2
  import { StorageRequestError } from "../../errors.js";
3
3
  import { idFromNumber, seqFromNumber } from "../../ids.js";
4
4
  import { nextCursor, scanStart } from "../scan.js";
5
- import { applySqliteMigrations } from "./migrations.js";
5
+ import { applySqliteMigrationsForSchema } from "./migrations.js";
6
+ import { createSqliteSchema } from "./schema.js";
6
7
  const parseJson = (value) => JSON.parse(value);
7
8
  const encodeJson = (value) => JSON.stringify(value);
8
9
  // Some SQLite bindings replace lone UTF-16 surrogates. JSON encoding keeps indexed identities lossless.
@@ -72,23 +73,26 @@ const writeId = (write) => {
72
73
  /** Portable SQLite implementation of the Pico storage contract. */
73
74
  export class SqliteStorage {
74
75
  db;
76
+ schema;
75
77
  nextId;
76
78
  closed = false;
77
79
  closing;
78
80
  admittedReads = 0;
79
81
  readsDrained;
80
- constructor(db, nextId) {
82
+ constructor(db, schema, nextId) {
81
83
  this.db = db;
84
+ this.schema = schema;
82
85
  this.nextId = nextId;
83
86
  }
84
87
  /** Initialize storage over an owned SQLite database facade. */
85
- static async open(db) {
88
+ static async open(db, options = {}) {
86
89
  try {
87
- await applySqliteMigrations(db);
88
- const metadata = await db.get("SELECT next_id, next_seq FROM durable_metadata WHERE singleton = 1");
90
+ const schema = createSqliteSchema(options.prefix);
91
+ await applySqliteMigrationsForSchema(db, schema);
92
+ const metadata = await db.get(`SELECT next_id, next_seq FROM ${schema.tables.durableMetadata} WHERE singleton = 1`);
89
93
  if (metadata === undefined)
90
94
  throw new Error("Durable SQLite metadata is missing");
91
- return new SqliteStorage(db, Number(metadata.next_id));
95
+ return new SqliteStorage(db, schema, Number(metadata.next_id));
92
96
  }
93
97
  catch (error) {
94
98
  try {
@@ -105,7 +109,7 @@ export class SqliteStorage {
105
109
  const documentActions = this.prepareDocumentActions(writes);
106
110
  const candidateNextId = this.candidateNextId(writes);
107
111
  const seq = await this.db.transaction(async (transaction) => {
108
- const metadata = await transaction.get("SELECT next_id, next_seq FROM durable_metadata WHERE singleton = 1");
112
+ const metadata = await transaction.get(`SELECT next_id, next_seq FROM ${this.schema.tables.durableMetadata} WHERE singleton = 1`);
109
113
  if (metadata === undefined)
110
114
  throw new Error("Durable SQLite metadata is missing");
111
115
  const committedSeq = seqFromNumber(metadata.next_seq);
@@ -114,7 +118,7 @@ export class SqliteStorage {
114
118
  for (const write of writes)
115
119
  await this.applyTableWrite(transaction, write, committedSeq);
116
120
  await this.applyDocumentActions(transaction, documentActions, committedSeq);
117
- await transaction.run("UPDATE durable_metadata SET next_id = ?, next_seq = ? WHERE singleton = 1", String(Math.max(Number(metadata.next_id), candidateNextId)), committedSeq + 1);
121
+ await transaction.run(`UPDATE ${this.schema.tables.durableMetadata} SET next_id = ?, next_seq = ? WHERE singleton = 1`, String(Math.max(Number(metadata.next_id), candidateNextId)), committedSeq + 1);
118
122
  return committedSeq;
119
123
  });
120
124
  this.nextId = Math.max(this.nextId, candidateNextId);
@@ -128,7 +132,7 @@ export class SqliteStorage {
128
132
  }
129
133
  async conversation(id, _context) {
130
134
  this.assertOpen();
131
- const row = await this.db.get("SELECT record FROM conversations WHERE id = ?", id);
135
+ const row = await this.db.get(`SELECT record FROM ${this.schema.tables.conversations} WHERE id = ?`, id);
132
136
  return row === undefined ? undefined : parseJson(row.record);
133
137
  }
134
138
  async scanConversations(query, limit, cursor, _context) {
@@ -146,7 +150,7 @@ export class SqliteStorage {
146
150
  params.push(query.ownerTaskId);
147
151
  }
148
152
  params.push(limit + 1);
149
- const rows = await this.db.all(`SELECT record FROM conversations WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
153
+ const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.conversations} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
150
154
  return page(rows.map((row) => parseJson(row.record)), limit, start.order);
151
155
  }
152
156
  entry(idOrConversationId, idOrContext, context) {
@@ -173,7 +177,7 @@ export class SqliteStorage {
173
177
  if (conversation === undefined)
174
178
  throw new StorageRequestError(`Unknown conversation: ${conversationId}`);
175
179
  }
176
- const row = await this.db.get("SELECT record, commit_seq FROM entries WHERE id = ?", id);
180
+ const row = await this.db.get(`SELECT record, commit_seq FROM ${this.schema.tables.entries} WHERE id = ?`, id);
177
181
  if (row === undefined)
178
182
  return undefined;
179
183
  const entry = parseJson(row.record);
@@ -197,8 +201,8 @@ export class SqliteStorage {
197
201
  let upper = atOrBeforeEntryId;
198
202
  while (true) {
199
203
  const row = upper === undefined
200
- ? await this.db.get("SELECT record FROM entries WHERE conversation_id = ? AND head IS NOT NULL ORDER BY id DESC LIMIT 1", conversation.id)
201
- : await this.db.get("SELECT record FROM entries WHERE conversation_id = ? AND head IS NOT NULL AND id <= ? ORDER BY id DESC LIMIT 1", conversation.id, upper);
204
+ ? await this.db.get(`SELECT record FROM ${this.schema.tables.entries} WHERE conversation_id = ? AND head IS NOT NULL ORDER BY id DESC LIMIT 1`, conversation.id)
205
+ : await this.db.get(`SELECT record FROM ${this.schema.tables.entries} WHERE conversation_id = ? AND head IS NOT NULL AND id <= ? ORDER BY id DESC LIMIT 1`, conversation.id, upper);
202
206
  if (row !== undefined)
203
207
  return parseJson(row.record);
204
208
  if (conversation.parent === undefined)
@@ -230,7 +234,7 @@ export class SqliteStorage {
230
234
  params.push(upper);
231
235
  }
232
236
  params.push(limit + 1 - values.length);
233
- const rows = await this.db.all(`SELECT record FROM entries WHERE ${clauses.join(" AND ")} ORDER BY id DESC LIMIT ?`, ...params);
237
+ const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.entries} WHERE ${clauses.join(" AND ")} ORDER BY id DESC LIMIT ?`, ...params);
234
238
  values.push(...rows.map((row) => parseJson(row.record)));
235
239
  if (values.length > limit || conversation.parent === undefined)
236
240
  break;
@@ -273,7 +277,7 @@ export class SqliteStorage {
273
277
  params.push(segment.upper);
274
278
  }
275
279
  params.push(limit + 1 - values.length);
276
- const rows = await this.db.all(`SELECT record FROM entries WHERE ${clauses.join(" AND ")} ORDER BY id ASC LIMIT ?`, ...params);
280
+ const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.entries} WHERE ${clauses.join(" AND ")} ORDER BY id ASC LIMIT ?`, ...params);
277
281
  values.push(...rows.map((row) => parseJson(row.record)));
278
282
  if (values.length > limit)
279
283
  break;
@@ -282,7 +286,7 @@ export class SqliteStorage {
282
286
  }
283
287
  async task(id, _context) {
284
288
  this.assertOpen();
285
- const row = await this.db.get("SELECT record FROM tasks WHERE id = ?", id);
289
+ const row = await this.db.get(`SELECT record FROM ${this.schema.tables.tasks} WHERE id = ?`, id);
286
290
  return row === undefined ? undefined : parseJson(row.record);
287
291
  }
288
292
  async scanTasks(query, limit, cursor, _context) {
@@ -312,12 +316,12 @@ export class SqliteStorage {
312
316
  params.push(query.background ? 1 : 0);
313
317
  }
314
318
  params.push(limit + 1);
315
- const rows = await this.db.all(`SELECT record FROM tasks WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
319
+ const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.tasks} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
316
320
  return page(rows.map((row) => parseJson(row.record)), limit, start.order);
317
321
  }
318
322
  async submission(id, _context) {
319
323
  this.assertOpen();
320
- const row = await this.db.get("SELECT record FROM submissions WHERE id = ?", id);
324
+ const row = await this.db.get(`SELECT record FROM ${this.schema.tables.submissions} WHERE id = ?`, id);
321
325
  return row === undefined ? undefined : parseJson(row.record);
322
326
  }
323
327
  async scanSubmissions(query, limit, cursor, _context) {
@@ -335,22 +339,22 @@ export class SqliteStorage {
335
339
  params.push(query.status);
336
340
  }
337
341
  params.push(limit + 1);
338
- const rows = await this.db.all(`SELECT record FROM submissions WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
342
+ const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.submissions} WHERE ${clauses.join(" AND ")} ORDER BY id ${scan.direction} LIMIT ?`, ...params);
339
343
  return page(rows.map((row) => parseJson(row.record)), limit, start.order);
340
344
  }
341
345
  async submissionByRequest(conversationId, requestId, _context) {
342
346
  this.assertOpen();
343
- const row = await this.db.get("SELECT record FROM submissions WHERE conversation_id = ? AND request_id = ?", conversationId, encodeIndexedString(requestId));
347
+ const row = await this.db.get(`SELECT record FROM ${this.schema.tables.submissions} WHERE conversation_id = ? AND request_id = ?`, conversationId, encodeIndexedString(requestId));
344
348
  return row === undefined ? undefined : parseJson(row.record);
345
349
  }
346
350
  async findDocument(address, at, _context) {
347
351
  this.assertOpen();
348
352
  const parts = addressParts(address);
349
353
  const sql = at === "current"
350
- ? `SELECT record FROM documents
354
+ ? `SELECT record FROM ${this.schema.tables.documents}
351
355
  WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ?
352
356
  AND retired_at IS NULL ORDER BY created_at DESC LIMIT 1`
353
- : `SELECT record FROM documents
357
+ : `SELECT record FROM ${this.schema.tables.documents}
354
358
  WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ?
355
359
  AND created_at <= ? AND (retired_at IS NULL OR retired_at > ?)
356
360
  ORDER BY created_at DESC LIMIT 1`;
@@ -382,7 +386,7 @@ export class SqliteStorage {
382
386
  params.push(query.at, query.at);
383
387
  }
384
388
  params.push(limit + 1);
385
- const rows = await this.db.all(`SELECT record FROM documents WHERE ${clauses.join(" AND ")} ORDER BY id LIMIT ?`, ...params);
389
+ const rows = await this.db.all(`SELECT record FROM ${this.schema.tables.documents} WHERE ${clauses.join(" AND ")} ORDER BY id LIMIT ?`, ...params);
386
390
  return page(rows.map((row) => parseJson(row.record)), limit);
387
391
  }
388
392
  close(_context) {
@@ -416,11 +420,11 @@ export class SqliteStorage {
416
420
  }
417
421
  }
418
422
  async readConversation(id) {
419
- const row = await this.db.get("SELECT record FROM conversations WHERE id = ?", id);
423
+ const row = await this.db.get(`SELECT record FROM ${this.schema.tables.conversations} WHERE id = ?`, id);
420
424
  return row === undefined ? undefined : parseJson(row.record);
421
425
  }
422
426
  async materializeDocument(executor, id, at) {
423
- const row = await executor.get("SELECT record FROM documents WHERE id = ?", id);
427
+ const row = await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id);
424
428
  if (row === undefined)
425
429
  return undefined;
426
430
  const record = parseJson(row.record);
@@ -430,12 +434,12 @@ export class SqliteStorage {
430
434
  if (!isAliveAt(record, at))
431
435
  return undefined;
432
436
  const upper = at === "current" ? Number.MAX_SAFE_INTEGER : at;
433
- const base = await executor.get(`SELECT seq, kind, version, content FROM document_revisions
437
+ const base = await executor.get(`SELECT seq, kind, version, content FROM ${this.schema.tables.documentRevisions}
434
438
  WHERE document_id = ? AND kind = 'base' AND seq <= ? ORDER BY seq DESC LIMIT 1`, id, upper);
435
439
  if (base === undefined)
436
440
  throw new Error(`Document ${id} is missing a required base`);
437
441
  let value = parseJson(base.content);
438
- const tail = await executor.all(`SELECT seq, kind, version, content FROM document_revisions
442
+ const tail = await executor.all(`SELECT seq, kind, version, content FROM ${this.schema.tables.documentRevisions}
439
443
  WHERE document_id = ? AND seq > ? AND seq <= ? ORDER BY seq`, id, base.seq, upper);
440
444
  for (const revision of tail) {
441
445
  if (revision.kind !== "delta" || revision.version !== base.version) {
@@ -462,8 +466,7 @@ export class SqliteStorage {
462
466
  const document = write.type === "document.create" || write.type === "document.copy";
463
467
  const table = document ? "document" : write.type;
464
468
  const id = document ? write.record.id : write.value.id;
465
- const existing = (await executor.get("SELECT record_type FROM record_ids WHERE id = ?", id))
466
- ?.record_type;
469
+ const existing = (await executor.get(`SELECT record_type FROM ${this.schema.tables.recordIds} WHERE id = ?`, id))?.record_type;
467
470
  const earlier = claimed.get(id);
468
471
  if (table === "conversation" || table === "entry" || table === "document") {
469
472
  if (existing !== undefined)
@@ -531,7 +534,7 @@ export class SqliteStorage {
531
534
  if (action.copy !== undefined && actions.has(action.copy.id)) {
532
535
  throw new Error(`Document copy ${id} source is changed in the copy batch`);
533
536
  }
534
- const row = await executor.get("SELECT record FROM documents WHERE id = ?", id);
537
+ const row = await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id);
535
538
  const existing = row === undefined ? undefined : parseJson(row.record);
536
539
  if (action.create === undefined && existing === undefined)
537
540
  throw new Error(`Unknown document: ${id}`);
@@ -540,7 +543,7 @@ export class SqliteStorage {
540
543
  if (existing?.retiredAt !== undefined)
541
544
  throw new Error(`Document ${id} is retired`);
542
545
  if (action.content?.kind === "delta") {
543
- const previous = await executor.get("SELECT version FROM document_revisions WHERE document_id = ? ORDER BY seq DESC LIMIT 1", id);
546
+ const previous = await executor.get(`SELECT version FROM ${this.schema.tables.documentRevisions} WHERE document_id = ? ORDER BY seq DESC LIMIT 1`, id);
544
547
  if (previous === undefined)
545
548
  throw new Error(`Document ${id} delta has no base`);
546
549
  if (previous.version !== action.content.version) {
@@ -565,7 +568,7 @@ export class SqliteStorage {
565
568
  }
566
569
  async currentDocumentId(executor, address) {
567
570
  const parts = addressParts(address);
568
- const id = (await executor.get(`SELECT id FROM documents
571
+ const id = (await executor.get(`SELECT id FROM ${this.schema.tables.documents}
569
572
  WHERE kind = ? AND scope_kind = ? AND owner_id = ? AND family = ? AND key_value = ? AND retired_at IS NULL
570
573
  LIMIT 1`, parts.kind, parts.scopeKind, parts.ownerId, parts.family, parts.keyValue))?.id;
571
574
  return id === undefined ? undefined : idFromNumber(id);
@@ -574,15 +577,15 @@ export class SqliteStorage {
574
577
  switch (write.type) {
575
578
  case "conversation":
576
579
  await this.claimId(executor, write.value.id, "conversation");
577
- await executor.run("INSERT INTO conversations (id, owner_conversation_id, owner_task_id, record) VALUES (?, ?, ?, ?)", write.value.id, write.value.owner?.conversationId ?? null, write.value.owner?.taskId ?? null, encodeJson(write.value));
580
+ await executor.run(`INSERT INTO ${this.schema.tables.conversations} (id, owner_conversation_id, owner_task_id, record) VALUES (?, ?, ?, ?)`, write.value.id, write.value.owner?.conversationId ?? null, write.value.owner?.taskId ?? null, encodeJson(write.value));
578
581
  break;
579
582
  case "entry":
580
583
  await this.claimId(executor, write.value.id, "entry");
581
- await executor.run("INSERT INTO entries (id, conversation_id, head, commit_seq, record) VALUES (?, ?, ?, ?, ?)", write.value.id, write.value.conversationId, write.value.head ?? null, seq, encodeJson(write.value));
584
+ await executor.run(`INSERT INTO ${this.schema.tables.entries} (id, conversation_id, head, commit_seq, record) VALUES (?, ?, ?, ?, ?)`, write.value.id, write.value.conversationId, write.value.head ?? null, seq, encodeJson(write.value));
582
585
  break;
583
586
  case "task":
584
587
  await this.claimId(executor, write.value.id, "task");
585
- await executor.run(`INSERT INTO tasks (id, conversation_id, kind, status, abort_requested, background, record)
588
+ await executor.run(`INSERT INTO ${this.schema.tables.tasks} (id, conversation_id, kind, status, abort_requested, background, record)
586
589
  VALUES (?, ?, ?, ?, ?, ?, ?)
587
590
  ON CONFLICT(id) DO UPDATE SET conversation_id = excluded.conversation_id, kind = excluded.kind,
588
591
  status = excluded.status, abort_requested = excluded.abort_requested,
@@ -590,7 +593,7 @@ export class SqliteStorage {
590
593
  break;
591
594
  case "submission":
592
595
  await this.claimId(executor, write.value.id, "submission");
593
- await executor.run(`INSERT INTO submissions (id, conversation_id, request_id, status, record) VALUES (?, ?, ?, ?, ?)
596
+ await executor.run(`INSERT INTO ${this.schema.tables.submissions} (id, conversation_id, request_id, status, record) VALUES (?, ?, ?, ?, ?)
594
597
  ON CONFLICT(id) DO UPDATE SET conversation_id = excluded.conversation_id,
595
598
  request_id = excluded.request_id, status = excluded.status, record = excluded.record`, write.value.id, write.value.conversationId, write.value.requestId === undefined ? null : encodeIndexedString(write.value.requestId), write.value.status, encodeJson(write.value));
596
599
  break;
@@ -602,7 +605,7 @@ export class SqliteStorage {
602
605
  }
603
606
  }
604
607
  async claimId(executor, id, table) {
605
- await executor.run("INSERT OR IGNORE INTO record_ids (id, record_type) VALUES (?, ?)", id, table);
608
+ await executor.run(`INSERT OR IGNORE INTO ${this.schema.tables.recordIds} (id, record_type) VALUES (?, ?)`, id, table);
606
609
  }
607
610
  async applyDocumentActions(executor, actions, seq) {
608
611
  for (const [id, action] of actions) {
@@ -636,28 +639,28 @@ export class SqliteStorage {
636
639
  };
637
640
  const parts = addressParts(record);
638
641
  await this.claimId(executor, id, "document");
639
- await executor.run(`INSERT INTO documents
642
+ await executor.run(`INSERT INTO ${this.schema.tables.documents}
640
643
  (id, kind, family, key_value, scope_kind, owner_id, created_at, retired_at, record)
641
644
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, id, parts.kind, parts.family, parts.keyValue, parts.scopeKind, parts.ownerId, seq, action.retire ? seq : null, encodeJson(record));
642
645
  }
643
646
  else {
644
- const row = (await executor.get("SELECT record FROM documents WHERE id = ?", id));
647
+ const row = (await executor.get(`SELECT record FROM ${this.schema.tables.documents} WHERE id = ?`, id));
645
648
  record = parseJson(row.record);
646
649
  }
647
650
  if (content !== undefined) {
648
651
  if (content.kind === "base" && isCurrentOnly(record)) {
649
- await executor.run("DELETE FROM document_revisions WHERE document_id = ?", id);
652
+ await executor.run(`DELETE FROM ${this.schema.tables.documentRevisions} WHERE document_id = ?`, id);
650
653
  }
651
654
  const encodedContent = content.kind === "base" ? encodeJson(content.value) : encodeJson(content.ops);
652
- await executor.run("INSERT INTO document_revisions (document_id, seq, kind, version, content) VALUES (?, ?, ?, ?, ?)", id, seq, content.kind, content.version, encodedContent);
655
+ await executor.run(`INSERT INTO ${this.schema.tables.documentRevisions} (document_id, seq, kind, version, content) VALUES (?, ?, ?, ?, ?)`, id, seq, content.kind, content.version, encodedContent);
653
656
  }
654
657
  if (action.retire) {
655
658
  if (action.create === undefined) {
656
659
  record = { ...record, retiredAt: seq };
657
- await executor.run("UPDATE documents SET retired_at = ?, record = ? WHERE id = ?", seq, encodeJson(record), id);
660
+ await executor.run(`UPDATE ${this.schema.tables.documents} SET retired_at = ?, record = ? WHERE id = ?`, seq, encodeJson(record), id);
658
661
  }
659
662
  if (isCurrentOnly(record)) {
660
- await executor.run("DELETE FROM document_revisions WHERE document_id = ?", id);
663
+ await executor.run(`DELETE FROM ${this.schema.tables.documentRevisions} WHERE document_id = ?`, id);
661
664
  }
662
665
  }
663
666
  }