or3-provider-sqlite 0.0.14 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -291,6 +291,10 @@ The canonical-history qualification lane defaults to a sibling `../or3-chat` che
291
291
 
292
292
  ## Workspace Files and Trash admission
293
293
 
294
+ Persistent Projects uses this same capability for opaque `or3:project-settings`, `or3:project-memory`, and `or3:project-source` posts. Preserve their JSON, metadata, and every original/extraction `file_hashes` reference. The project-aware canonical reader resolves `threads.project_id` or a single legacy membership in its authorized SQLite snapshot, returning `project_ownership: resolved | conflict`. String entries and JSON-encoded membership arrays remain supported; malformed or ambiguous memberships do not grant server execution. Hosts without this result must refuse project-sensitive server admission rather than infer ownership from the visible UI.
295
+
296
+ Version 0.0.15 declares `projectOwnership: 'v1'` on the native canonical-history adapter. D1 does not advertise this contract. Projects qualification: `OR3_PROJECT_HOST_ROOT=/absolute/path/to/or3-chat bun x vitest run src/runtime/__tests__/sqlite-sync-gateway-adapter.test.ts`. This explicit lane uses the host's canonical-reader query contract while retaining the pinned standalone fixture for existing contracts. Qualify the published exact version with the disposable host cloud journey.
297
+
294
298
  Native synchronous adapters advertise workspace-item capability v1. Canonical
295
299
  posts/projects with catalog, logical Trash, or file-membership semantics require
296
300
  a current writer even when the incoming update omits those fields. Admission is
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "or3-provider-sqlite",
3
3
  "configKey": "or3-provider-sqlite",
4
- "version": "0.0.14",
4
+ "version": "0.0.15",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -17,12 +17,14 @@ export declare class SqliteSyncGatewayAdapter implements SyncGatewayAdapter {
17
17
  readonly historyRetention: "snapshot-v1";
18
18
  readonly backgroundGenerationHistory?: undefined;
19
19
  readonly canonicalChatHistory?: undefined;
20
+ readonly projectOwnership?: undefined;
20
21
  readonly workspaceItems?: undefined;
21
22
  } | {
22
23
  readonly snapshotBootstrap: "snapshot-v1";
23
24
  readonly historyRetention: "snapshot-v1";
24
25
  readonly backgroundGenerationHistory: "v1";
25
26
  readonly canonicalChatHistory: "v1";
27
+ readonly projectOwnership: "v1";
26
28
  readonly workspaceItems: "v1";
27
29
  };
28
30
  private get db();
@@ -433,6 +433,7 @@ export class SqliteSyncGatewayAdapter {
433
433
  historyRetention: "snapshot-v1",
434
434
  backgroundGenerationHistory: "v1",
435
435
  canonicalChatHistory: "v1",
436
+ projectOwnership: "v1",
436
437
  workspaceItems: "v1"
437
438
  };
438
439
  }
@@ -458,7 +459,26 @@ export class SqliteSyncGatewayAdapter {
458
459
  if (query.kind === "thread") {
459
460
  const threadRevision = raw.prepare("SELECT value FROM chat_history_revisions WHERE workspace_id = ? AND thread_id = ?").get(actor.workspaceId, query.thread_id);
460
461
  const row = raw.prepare("SELECT id, data_json, clock, deleted FROM s_threads WHERE workspace_id = ? AND id = ?").get(actor.workspaceId, query.thread_id);
461
- return { status: "ok", revision: String(threadRevision?.value ?? 0), thread: row ? parse(row) : void 0 };
462
+ const thread = row ? parse(row) : void 0;
463
+ if (!thread || thread.project_id) return {
464
+ status: "ok",
465
+ project_ownership: "resolved",
466
+ revision: String(threadRevision?.value ?? 0),
467
+ thread
468
+ };
469
+ const projects = raw.prepare("SELECT id, data_json FROM s_projects WHERE workspace_id = ? AND COALESCE(deleted, 0) = 0").all(actor.workspaceId);
470
+ const owners = projects.filter((project) => {
471
+ const payload = JSON.parse(project.data_json);
472
+ const entries = typeof payload.data === "string" ? JSON.parse(payload.data) : payload.data ?? [];
473
+ if (!Array.isArray(entries)) throw new Error("Canonical project membership is unresolved.");
474
+ return entries.some((entry) => typeof entry === "string" ? entry === query.thread_id : entry && typeof entry === "object" && !Array.isArray(entry) && (entry.kind === void 0 || entry.kind === "chat") && entry.id === query.thread_id);
475
+ });
476
+ return {
477
+ status: "ok",
478
+ project_ownership: owners.length > 1 ? "conflict" : "resolved",
479
+ revision: String(threadRevision?.value ?? 0),
480
+ thread: { ...thread, project_id: owners[0]?.id ?? null }
481
+ };
462
482
  }
463
483
  if (query.kind === "messages") {
464
484
  if (!query.message_ids.length) return { status: "ok", revision, messages: [] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "or3-provider-sqlite",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Saluana/or3-provider-sqlite.git"