@opendatalabs/personal-server-ts-server 1.13.0 → 1.14.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.
@@ -1,15 +1,4 @@
1
- export interface AccessLogEntry {
2
- logId: string;
3
- grantId: string;
4
- builder: string;
5
- action: "read" | "write" | "delete";
6
- scope: string;
7
- timestamp: string;
8
- ipAddress: string;
9
- userAgent: string;
10
- }
11
- export interface AccessLogWriter {
12
- write(entry: AccessLogEntry): Promise<void>;
13
- }
1
+ import type { AccessLogEntry, AccessLogWriter } from "@opendatalabs/personal-server-ts-core/logging/access-log";
2
+ export type { AccessLogEntry, AccessLogWriter };
14
3
  export declare function createAccessLogWriter(logsDir: string): AccessLogWriter;
15
4
  //# sourceMappingURL=access-log.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"access-log.d.ts","sourceRoot":"","sources":["../../src/logging/access-log.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAUD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAiBtE"}
1
+ {"version":3,"file":"access-log.d.ts","sourceRoot":"","sources":["../../src/logging/access-log.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAChB,MAAM,0DAA0D,CAAC;AAElE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;AAUhD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAiBtE"}
@@ -1 +1 @@
1
- {"version":3,"file":"access-log.js","sourceRoot":"","sources":["../../src/logging/access-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAiBjC,SAAS,qBAAqB,CAAC,YAAoB;IACjD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;IACnC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,GAAG,IAAI,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,KAAqB;YAC/B,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1C,UAAU,GAAG,IAAI,CAAC;YACpB,CAAC;YAED,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACvD,MAAM,QAAQ,GAAG,UAAU,OAAO,MAAM,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAEzC,MAAM,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;QACpE,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"access-log.js","sourceRoot":"","sources":["../../src/logging/access-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,SAAS,qBAAqB,CAAC,YAAoB;IACjD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;IACnC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,GAAG,IAAI,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,KAAqB;YAC/B,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1C,UAAU,GAAG,IAAI,CAAC;YACpB,CAAC;YAED,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACvD,MAAM,QAAQ,GAAG,UAAU,OAAO,MAAM,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAEzC,MAAM,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;QACpE,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"question-store.d.ts","sourceRoot":"","sources":["../../src/storage/question-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,mDAAmD,CAAC;AAgE3D,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,aAAa,CAsFf"}
1
+ {"version":3,"file":"question-store.d.ts","sourceRoot":"","sources":["../../src/storage/question-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,mDAAmD,CAAC;AAgF3D,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,aAAa,CAmGf"}
@@ -15,12 +15,26 @@ CREATE TABLE IF NOT EXISTS derivative_questions (
15
15
  registered_by TEXT NOT NULL,
16
16
  status TEXT NOT NULL,
17
17
  error TEXT,
18
+ error_code TEXT,
18
19
  created_at TEXT NOT NULL,
19
20
  updated_at TEXT NOT NULL,
20
21
  last_computed_at TEXT,
21
22
  derived_version INTEGER,
22
23
  derived_collected_at TEXT
23
24
  )`;
25
+ /**
26
+ * Databases created before the column existed migrate in place. ALTER is
27
+ * guarded by a pragma check because SQLite has no ADD COLUMN IF NOT EXISTS;
28
+ * existing rows read back as null (pre-classification failures).
29
+ */
30
+ function ensureErrorCodeColumn(db) {
31
+ const columns = db
32
+ .prepare("PRAGMA table_info(derivative_questions)")
33
+ .all();
34
+ if (columns.some((column) => column.name === "error_code"))
35
+ return;
36
+ db.exec("ALTER TABLE derivative_questions ADD COLUMN error_code TEXT");
37
+ }
24
38
  const CREATE_INDEX_SQL = "CREATE INDEX IF NOT EXISTS idx_derivative_questions_derived_scope ON derivative_questions (derived_scope)";
25
39
  // Databases created before the recompute policy existed migrate in place;
26
40
  // their registrations keep the old follow-every-change behavior.
@@ -36,6 +50,7 @@ function toRegistration(row) {
36
50
  registeredBy: JSON.parse(row.registered_by),
37
51
  status: row.status,
38
52
  error: row.error,
53
+ errorCode: row.error_code ?? null,
39
54
  createdAt: row.created_at,
40
55
  updatedAt: row.updated_at,
41
56
  lastComputedAt: row.last_computed_at,
@@ -45,6 +60,7 @@ function toRegistration(row) {
45
60
  }
46
61
  export function createSqliteQuestionStore(db) {
47
62
  db.exec(CREATE_TABLE_SQL);
63
+ ensureErrorCodeColumn(db);
48
64
  db.exec(CREATE_INDEX_SQL);
49
65
  const columns = db
50
66
  .prepare("PRAGMA table_info(derivative_questions)")
@@ -53,21 +69,25 @@ export function createSqliteQuestionStore(db) {
53
69
  db.exec(ADD_RECOMPUTE_COLUMN_SQL);
54
70
  }
55
71
  const listAll = db.prepare("SELECT * FROM derivative_questions ORDER BY created_at ASC, question_id ASC");
72
+ // The status route polls list({ derivedScope }) on every reader request;
73
+ // this is the query idx_derivative_questions_derived_scope exists for.
74
+ const listByDerivedScope = db.prepare("SELECT * FROM derivative_questions WHERE derived_scope = ? ORDER BY created_at ASC, question_id ASC");
56
75
  const getOne = db.prepare("SELECT * FROM derivative_questions WHERE question_id = ?");
57
76
  const insertOne = db.prepare(`
58
77
  INSERT INTO derivative_questions (
59
78
  question_id, derived_scope, source_scopes, question, model, recompute,
60
- registered_by, status, error, created_at, updated_at,
79
+ registered_by, status, error, error_code, created_at, updated_at,
61
80
  last_computed_at, derived_version, derived_collected_at
62
81
  ) VALUES (
63
82
  @question_id, @derived_scope, @source_scopes, @question, @model,
64
- @recompute, @registered_by, @status, @error, @created_at, @updated_at,
83
+ @recompute, @registered_by, @status, @error, @error_code, @created_at, @updated_at,
65
84
  @last_computed_at, @derived_version, @derived_collected_at
66
85
  )`);
67
86
  const updateOne = db.prepare(`
68
87
  UPDATE derivative_questions SET
69
88
  status = @status,
70
89
  error = @error,
90
+ error_code = @error_code,
71
91
  updated_at = @updated_at,
72
92
  last_computed_at = @last_computed_at,
73
93
  derived_version = @derived_version,
@@ -76,7 +96,10 @@ export function createSqliteQuestionStore(db) {
76
96
  const deleteOne = db.prepare("DELETE FROM derivative_questions WHERE question_id = ?");
77
97
  return {
78
98
  async list(filter) {
79
- return listAll.all()
99
+ const rows = filter?.derivedScope !== undefined
100
+ ? listByDerivedScope.all(filter.derivedScope)
101
+ : listAll.all();
102
+ return rows
80
103
  .map(toRegistration)
81
104
  .filter((registration) => matchesQuestionFilter(registration, filter));
82
105
  },
@@ -95,6 +118,7 @@ export function createSqliteQuestionStore(db) {
95
118
  registered_by: JSON.stringify(registration.registeredBy),
96
119
  status: registration.status,
97
120
  error: registration.error,
121
+ error_code: registration.errorCode,
98
122
  created_at: registration.createdAt,
99
123
  updated_at: registration.updatedAt,
100
124
  last_computed_at: registration.lastComputedAt,
@@ -111,6 +135,7 @@ export function createSqliteQuestionStore(db) {
111
135
  question_id: questionId,
112
136
  status: merged.status,
113
137
  error: merged.error,
138
+ error_code: merged.errorCode ?? null,
114
139
  updated_at: merged.updatedAt,
115
140
  last_computed_at: merged.lastComputedAt,
116
141
  derived_version: merged.derivedVersion,
@@ -1 +1 @@
1
- {"version":3,"file":"question-store.js","sourceRoot":"","sources":["../../src/storage/question-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"question-store.js","sourceRoot":"","sources":["../../src/storage/question-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,qBAAqB,GAKtB,MAAM,mDAAmD,CAAC;AAE3D,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;EAiBvB,CAAC;AAEH;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,EAAqB;IAClD,MAAM,OAAO,GAAG,EAAE;SACf,OAAO,CAAC,yCAAyC,CAAC;SAClD,GAAG,EAA6B,CAAC;IACpC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,CAAC;QAAE,OAAO;IACnE,EAAE,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,gBAAgB,GACpB,2GAA2G,CAAC;AAE9G,0EAA0E;AAC1E,iEAAiE;AACjE,MAAM,wBAAwB,GAC5B,yFAAyF,CAAC;AAoB5F,SAAS,cAAc,CAAC,GAAQ;IAC9B,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,WAAW;QAC3B,YAAY,EAAE,GAAG,CAAC,aAAa;QAC/B,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAa;QACvD,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAyB;QACnE,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,SAAS,EAAG,GAAG,CAAC,UAAuC,IAAI,IAAI;QAC/D,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,cAAc,EAAE,GAAG,CAAC,gBAAgB;QACpC,cAAc,EAAE,GAAG,CAAC,eAAe;QACnC,kBAAkB,EAAE,GAAG,CAAC,oBAAoB;KAC7C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,EAAqB;IAErB,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC1B,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC1B,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC1B,MAAM,OAAO,GAAG,EAAE;SACf,OAAO,CAAC,yCAAyC,CAAC;SAClD,GAAG,EAA6B,CAAC;IACpC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;QAC3D,EAAE,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CACxB,6EAA6E,CAC9E,CAAC;IACF,yEAAyE;IACzE,uEAAuE;IACvE,MAAM,kBAAkB,GAAG,EAAE,CAAC,OAAO,CACnC,qGAAqG,CACtG,CAAC;IACF,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CACvB,0DAA0D,CAC3D,CAAC;IACF,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;;MASzB,CAAC,CAAC;IACN,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;;qCASM,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAC1B,wDAAwD,CACzD,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,MAAM;YACf,MAAM,IAAI,GACR,MAAM,EAAE,YAAY,KAAK,SAAS;gBAChC,CAAC,CAAE,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAW;gBACxD,CAAC,CAAE,OAAO,CAAC,GAAG,EAAY,CAAC;YAC/B,OAAO,IAAI;iBACR,GAAG,CAAC,cAAc,CAAC;iBACnB,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,qBAAqB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,UAAU;YAClB,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAoB,CAAC;YACtD,OAAO,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,YAAY;YACvB,SAAS,CAAC,GAAG,CAAC;gBACZ,WAAW,EAAE,YAAY,CAAC,UAAU;gBACpC,aAAa,EAAE,YAAY,CAAC,YAAY;gBACxC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;gBACxD,QAAQ,EAAE,YAAY,CAAC,QAAQ;gBAC/B,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,SAAS,EAAE,YAAY,CAAC,SAAS;gBACjC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;gBACxD,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,KAAK,EAAE,YAAY,CAAC,KAAK;gBACzB,UAAU,EAAE,YAAY,CAAC,SAAS;gBAClC,UAAU,EAAE,YAAY,CAAC,SAAS;gBAClC,UAAU,EAAE,YAAY,CAAC,SAAS;gBAClC,gBAAgB,EAAE,YAAY,CAAC,cAAc;gBAC7C,eAAe,EAAE,YAAY,CAAC,cAAc;gBAC5C,oBAAoB,EAAE,YAAY,CAAC,kBAAkB;aACtD,CAAC,CAAC;QACL,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK;YAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAoB,CAAC;YAC1D,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YAC1B,MAAM,MAAM,GAAG,EAAE,GAAG,cAAc,CAAC,OAAO,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;YACxD,SAAS,CAAC,GAAG,CAAC;gBACZ,WAAW,EAAE,UAAU;gBACvB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,UAAU,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;gBACpC,UAAU,EAAE,MAAM,CAAC,SAAS;gBAC5B,gBAAgB,EAAE,MAAM,CAAC,cAAc;gBACvC,eAAe,EAAE,MAAM,CAAC,cAAc;gBACtC,oBAAoB,EAAE,MAAM,CAAC,kBAAkB;aAChD,CAAC,CAAC;YACH,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,UAAU;YACrB,OAAO,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -110213,6 +110213,7 @@ function parseGrantExpiresAtSeconds(value) {
110213
110213
  const millis = Date.parse(value);
110214
110214
  return Number.isNaN(millis) ? null : Math.floor(millis / 1e3);
110215
110215
  }
110216
+ var SENTINEL_GRANT_IDS = /* @__PURE__ */ new Set(["owner", "policy-bypass"]);
110216
110217
  async function verifyDataReadPolicy(input, ports) {
110217
110218
  const available = await ports.runtimeAvailability?.isAvailable();
110218
110219
  if (available === false) {
@@ -110227,6 +110228,12 @@ async function verifyDataReadPolicy(input, ports) {
110227
110228
  reason: "No grantId in authorization payload"
110228
110229
  });
110229
110230
  }
110231
+ if (SENTINEL_GRANT_IDS.has(input.grantId)) {
110232
+ throw new GrantRequiredError({
110233
+ reason: "Reserved grantId",
110234
+ grantId: input.grantId
110235
+ });
110236
+ }
110230
110237
  const grant = await ports.grantVerifier.getGrant(input.grantId);
110231
110238
  if (!grant) {
110232
110239
  throw new GrantRequiredError({
@@ -110234,6 +110241,12 @@ async function verifyDataReadPolicy(input, ports) {
110234
110241
  grantId: input.grantId
110235
110242
  });
110236
110243
  }
110244
+ if (SENTINEL_GRANT_IDS.has(grant.id)) {
110245
+ throw new GrantRequiredError({
110246
+ reason: "Grant resolved to a reserved id",
110247
+ grantId: input.grantId
110248
+ });
110249
+ }
110237
110250
  if (grant.revokedAt !== null) {
110238
110251
  throw new GrantRevokedError({ grantId: grant.id });
110239
110252
  }
@@ -111422,6 +111435,34 @@ function resolveLineageGrantView(authResult) {
111422
111435
  }
111423
111436
  return { grantId };
111424
111437
  }
111438
+ function isOwnerView(authResult) {
111439
+ return authResult === void 0 || authResult.grantId === "owner" || authResult.grantId === "policy-bypass";
111440
+ }
111441
+ function redactEnvelopeForGrantee(envelope) {
111442
+ const { [WRITER_ATTRIBUTION_KEY]: attribution, [LINEAGE_KEY]: storedLineage, ...rest } = envelope.data;
111443
+ if (attribution === void 0 && storedLineage === void 0) {
111444
+ return envelope;
111445
+ }
111446
+ let data = rest;
111447
+ if (storedLineage !== void 0) {
111448
+ if (isBinaryEnvelope(envelope)) {
111449
+ const metadata = data["metadata"];
111450
+ if (metadata !== null && typeof metadata === "object" && !Array.isArray(metadata)) {
111451
+ const { lineage: _consumed, ...metadataRest } = metadata;
111452
+ if (Object.keys(metadataRest).length === 0) {
111453
+ const { metadata: _emptied, ...dataRest } = data;
111454
+ data = dataRest;
111455
+ } else {
111456
+ data = { ...data, metadata: metadataRest };
111457
+ }
111458
+ }
111459
+ } else {
111460
+ const { lineage: _consumed, ...dataRest } = data;
111461
+ data = dataRest;
111462
+ }
111463
+ }
111464
+ return { ...envelope, data };
111465
+ }
111425
111466
  async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111426
111467
  return withApiErrors(async () => {
111427
111468
  const url2 = new URL(request2.url);
@@ -111514,6 +111555,16 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111514
111555
  body: result.body
111515
111556
  });
111516
111557
  }
111558
+ await deps.accessLogWriter.write({
111559
+ logId: deps.createLogId?.() ?? crypto.randomUUID(),
111560
+ grantId: authResult?.grantId ?? "owner",
111561
+ builder: authResult?.builder ?? "unknown",
111562
+ action: "lineage",
111563
+ scope: scopeResult.scope,
111564
+ timestamp: (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
111565
+ ipAddress: request2.headers.get("x-forwarded-for") ?? request2.headers.get("x-real-ip") ?? "unknown",
111566
+ userAgent: request2.headers.get("user-agent") ?? "unknown"
111567
+ });
111517
111568
  return jsonResponse({ data: result.data, proof: result.proof });
111518
111569
  }
111519
111570
  if (parts.length !== 1)
@@ -111598,6 +111649,7 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111598
111649
  }
111599
111650
  return contractErrorResponse(result);
111600
111651
  }
111652
+ const servedEnvelope = isOwnerView(authResult) ? result.envelope : redactEnvelopeForGrantee(result.envelope);
111601
111653
  const logId = deps.createLogId?.() ?? crypto.randomUUID();
111602
111654
  const timestamp = (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
111603
111655
  const ipAddress = request2.headers.get("x-forwarded-for") ?? request2.headers.get("x-real-ip") ?? "unknown";
@@ -111634,13 +111686,13 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111634
111686
  }
111635
111687
  const wantsRawContent = url2.searchParams.get("content") === "raw";
111636
111688
  if (wantsRawContent) {
111637
- if (!isBinaryEnvelope(result.envelope)) {
111689
+ if (!isBinaryEnvelope(servedEnvelope)) {
111638
111690
  return jsonResponse({
111639
111691
  error: "NOT_BINARY_SCOPE",
111640
111692
  message: `Scope "${scopeResult.scope}" does not expose raw binary content.`
111641
111693
  }, { status: 400, headers });
111642
111694
  }
111643
- const decoded = decodeBinaryEnvelope(result.envelope);
111695
+ const decoded = decodeBinaryEnvelope(servedEnvelope);
111644
111696
  headers["Content-Type"] = decoded.mimeType;
111645
111697
  headers["Content-Length"] = String(decoded.bytes.length);
111646
111698
  if (decoded.filename) {
@@ -111655,7 +111707,7 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111655
111707
  });
111656
111708
  return response2;
111657
111709
  }
111658
- const response = jsonResponse(result.envelope, { headers });
111710
+ const response = jsonResponse(servedEnvelope, { headers });
111659
111711
  reportReadFulfillment();
111660
111712
  return response;
111661
111713
  }
@@ -113991,6 +114043,7 @@ function questionRegistrationView(registration) {
113991
114043
  registeredBy: registration.registeredBy,
113992
114044
  status: registration.status,
113993
114045
  error: registration.error,
114046
+ errorCode: registration.errorCode,
113994
114047
  createdAt: registration.createdAt,
113995
114048
  updatedAt: registration.updatedAt,
113996
114049
  lastComputedAt: registration.lastComputedAt,
@@ -114003,6 +114056,8 @@ function questionRegistrationView(registration) {
114003
114056
  function clone2(registration) {
114004
114057
  return {
114005
114058
  ...registration,
114059
+ // Registrations persisted before the field existed load as null.
114060
+ errorCode: registration.errorCode ?? null,
114006
114061
  sourceScopes: [...registration.sourceScopes],
114007
114062
  registeredBy: { ...registration.registeredBy }
114008
114063
  };
@@ -114189,6 +114244,7 @@ async function createQuestionRegistration(input) {
114189
114244
  registeredBy: input.registeredBy,
114190
114245
  status: "pending",
114191
114246
  error: null,
114247
+ errorCode: null,
114192
114248
  createdAt: at3,
114193
114249
  updatedAt: at3,
114194
114250
  lastComputedAt: null,
@@ -114267,10 +114323,13 @@ function trimSourceData(data, options = {}) {
114267
114323
  if (Array.isArray(data))
114268
114324
  return trimArray(data, limit2);
114269
114325
  if (isRecord5(data)) {
114326
+ const stamped = "$lineage" in data;
114270
114327
  const out = {};
114271
114328
  for (const [key, value] of Object.entries(data)) {
114272
114329
  if (RESERVED_KEYS.has(key))
114273
114330
  continue;
114331
+ if (stamped && key === "lineage")
114332
+ continue;
114274
114333
  out[key] = Array.isArray(value) ? trimArray(value, limit2) : value;
114275
114334
  }
114276
114335
  return out;
@@ -114564,11 +114623,25 @@ async function withRetries(deps, attempt, retryable) {
114564
114623
  }
114565
114624
  }
114566
114625
  var ComputeFailure = class extends Error {
114567
- constructor(message) {
114626
+ code;
114627
+ constructor(message, code) {
114568
114628
  super(message);
114569
114629
  this.name = "ComputeFailure";
114630
+ this.code = code;
114570
114631
  }
114571
114632
  };
114633
+ function classifyComputeError(err2) {
114634
+ if (err2 instanceof ComputeFailure)
114635
+ return err2.code ?? "internal";
114636
+ if (err2 instanceof InferenceRequestError) {
114637
+ return isRetryableInferenceError(err2) ? "inference_unavailable" : "internal";
114638
+ }
114639
+ if (err2 instanceof ProtocolError) {
114640
+ const grantShaped = err2.errorCode === "DERIVATIVE_SOURCE_NOT_GRANTED" || err2.errorCode === "SCOPE_MISMATCH" || err2.errorCode === "UNREGISTERED_BUILDER" || err2.errorCode.startsWith("GRANT_");
114641
+ return grantShaped ? "grant_invalid" : "internal";
114642
+ }
114643
+ return "internal";
114644
+ }
114572
114645
  function shortError(err2) {
114573
114646
  if (err2 instanceof ComputeFailure)
114574
114647
  return err2.message;
@@ -114653,10 +114726,10 @@ async function loadSource(deps, scope) {
114653
114726
  const entry = deps.storage.findEntry({ scope });
114654
114727
  const deletion = await resolveReadDeletion({ scopeDeletions: deps.scopeDeletions, serverOwner: deps.serverOwner }, scope, entry);
114655
114728
  if (deletion) {
114656
- throw new ComputeFailure(`source scope ${scope} is deleted`);
114729
+ throw new ComputeFailure(`source scope ${scope} is deleted`, "source_missing");
114657
114730
  }
114658
114731
  if (!entry) {
114659
- throw new ComputeFailure(`source scope ${scope} has no local data`);
114732
+ throw new ComputeFailure(`source scope ${scope} has no local data`, "source_missing");
114660
114733
  }
114661
114734
  let envelope;
114662
114735
  try {
@@ -114792,6 +114865,7 @@ async function computeQuestion(questionId, deps) {
114792
114865
  const updated = await deps.store.update(questionId, {
114793
114866
  status: "ready",
114794
114867
  error: null,
114868
+ errorCode: null,
114795
114869
  updatedAt: computedAt,
114796
114870
  lastComputedAt: computedAt,
114797
114871
  derivedVersion: entry?.version ?? null,
@@ -114829,28 +114903,49 @@ async function computeQuestion(questionId, deps) {
114829
114903
  };
114830
114904
  } catch (err2) {
114831
114905
  const error51 = shortError(err2);
114906
+ const errorCode = classifyComputeError(err2);
114832
114907
  const at3 = now().toISOString();
114833
114908
  const updated = await deps.store.update(questionId, {
114834
114909
  status: "failed",
114835
114910
  error: error51,
114911
+ errorCode,
114836
114912
  updatedAt: at3
114837
114913
  });
114838
114914
  deps.logger?.warn?.({ questionId, derivedScope: registration.derivedScope, error: error51 }, "Derivative question compute failed");
114839
114915
  return {
114840
114916
  status: "failed",
114841
- registration: updated ?? { ...registration, status: "failed", error: error51 },
114917
+ registration: updated ?? {
114918
+ ...registration,
114919
+ status: "failed",
114920
+ error: error51,
114921
+ errorCode
114922
+ },
114842
114923
  error: error51
114843
114924
  };
114844
114925
  }
114845
114926
  }
114846
114927
 
114847
114928
  // ../core/dist/derivatives/scheduler.js
114929
+ var DEFAULT_RETRY_DELAYS_MS2 = [6e4, 3e5, 18e5];
114930
+ function isRuntimeSkipOutcome(outcome) {
114931
+ if (typeof outcome !== "object" || outcome === null)
114932
+ return false;
114933
+ const shaped = outcome;
114934
+ return shaped.status === "skipped" && shaped.reason === "runtime-unavailable";
114935
+ }
114936
+ function isTransientFailureOutcome(outcome) {
114937
+ if (typeof outcome !== "object" || outcome === null)
114938
+ return false;
114939
+ const shaped = outcome;
114940
+ return shaped.status === "failed" && shaped.registration?.errorCode === "inference_unavailable";
114941
+ }
114848
114942
  var defaultTimers = {
114849
114943
  setTimeout: (callback, ms3) => setTimeout(callback, ms3),
114850
114944
  clearTimeout: (handle) => clearTimeout(handle)
114851
114945
  };
114852
114946
  function createRecomputeScheduler(options) {
114853
114947
  const debounceMs = options.debounceMs ?? 5e3;
114948
+ const retryDelaysMs = options.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS2;
114854
114949
  const timers = options.timers ?? defaultTimers;
114855
114950
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
114856
114951
  const states = /* @__PURE__ */ new Map();
@@ -114869,7 +114964,15 @@ function createRecomputeScheduler(options) {
114869
114964
  function stateFor(questionId) {
114870
114965
  let state = states.get(questionId);
114871
114966
  if (!state) {
114872
- state = { timer: null, running: null, rerun: false };
114967
+ state = {
114968
+ timer: null,
114969
+ running: null,
114970
+ rerun: false,
114971
+ retryAttempts: 0,
114972
+ retryAtMs: null,
114973
+ retryScheduled: false,
114974
+ retryRunning: false
114975
+ };
114873
114976
  states.set(questionId, state);
114874
114977
  }
114875
114978
  return state;
@@ -114882,17 +114985,42 @@ function createRecomputeScheduler(options) {
114882
114985
  state.rerun = true;
114883
114986
  return;
114884
114987
  }
114885
- state.running = track(Promise.resolve().then(() => options.compute(questionId)).then(() => void 0, (err2) => warn({
114886
- questionId,
114887
- error: err2 instanceof Error ? err2.name : String(err2)
114888
- }, "Derivative compute threw")).then(async () => {
114988
+ state.running = track(Promise.resolve().then(() => options.compute(questionId)).then((outcome) => outcome, (err2) => {
114989
+ warn({
114990
+ questionId,
114991
+ error: err2 instanceof Error ? err2.name : String(err2)
114992
+ }, "Derivative compute threw");
114993
+ return void 0;
114994
+ }).then(async (outcome) => {
114889
114995
  state.running = null;
114996
+ state.retryAtMs = null;
114997
+ state.retryRunning = false;
114998
+ const retryable = isTransientFailureOutcome(outcome) || // A runtime-unavailable skip DURING a chain consumes an attempt
114999
+ // instead of ending the chain; on a fresh compute it keeps the
115000
+ // pre-retry behavior (pending/stale, reswept by start()).
115001
+ isRuntimeSkipOutcome(outcome) && state.retryAttempts > 0;
114890
115002
  if (state.rerun) {
114891
115003
  state.rerun = false;
115004
+ state.retryAttempts = 0;
114892
115005
  await markStale(questionId);
114893
115006
  schedule(questionId, 0);
114894
- } else if (!states.get(questionId)?.timer) {
114895
- states.delete(questionId);
115007
+ } else if (retryable && // A pending timer means a source change or explicit recompute
115008
+ // arrived during the run and already scheduled a fresher run;
115009
+ // replacing its 5s debounce with a 60s retry would delay the
115010
+ // recompute of data this compute never saw.
115011
+ state.timer === null && // After stop() nothing may be scheduled; without this a compute
115012
+ // that settles late would record a retryAtMs no timer backs.
115013
+ !stopped && state.retryAttempts < retryDelaysMs.length) {
115014
+ const delayMs = retryDelaysMs[state.retryAttempts];
115015
+ state.retryAttempts += 1;
115016
+ state.retryAtMs = now().getTime() + delayMs;
115017
+ schedule(questionId, delayMs);
115018
+ state.retryScheduled = true;
115019
+ } else {
115020
+ state.retryAttempts = 0;
115021
+ if (!states.get(questionId)?.timer) {
115022
+ states.delete(questionId);
115023
+ }
114896
115024
  }
114897
115025
  }));
114898
115026
  }
@@ -114904,6 +115032,9 @@ function createRecomputeScheduler(options) {
114904
115032
  timers.clearTimeout(state.timer);
114905
115033
  state.timer = timers.setTimeout(() => {
114906
115034
  state.timer = null;
115035
+ state.retryAtMs = null;
115036
+ state.retryRunning = state.retryScheduled;
115037
+ state.retryScheduled = false;
114907
115038
  run(questionId);
114908
115039
  }, delayMs);
114909
115040
  }
@@ -114914,11 +115045,29 @@ function createRecomputeScheduler(options) {
114914
115045
  if (registration.status === "ready" || registration.status === "failed") {
114915
115046
  await options.store.update(questionId, {
114916
115047
  status: "stale",
115048
+ // The reader contract says errorCode is null unless failed; a stale
115049
+ // question is a recompute in progress, not a terminal failure.
115050
+ errorCode: null,
114917
115051
  updatedAt: now().toISOString()
114918
115052
  });
114919
115053
  }
114920
115054
  }
115055
+ function resetRetry(questionId) {
115056
+ const state = states.get(questionId);
115057
+ if (!state)
115058
+ return;
115059
+ state.retryAttempts = 0;
115060
+ state.retryAtMs = null;
115061
+ state.retryScheduled = false;
115062
+ }
114921
115063
  return {
115064
+ nextRetryAt(questionId) {
115065
+ const retryAtMs = states.get(questionId)?.retryAtMs;
115066
+ return retryAtMs == null ? null : new Date(retryAtMs).toISOString();
115067
+ },
115068
+ retryInFlight(questionId) {
115069
+ return states.get(questionId)?.retryRunning ?? false;
115070
+ },
114922
115071
  markSourceChanged(scope, opts) {
114923
115072
  if (stopped)
114924
115073
  return;
@@ -114933,6 +115082,7 @@ function createRecomputeScheduler(options) {
114933
115082
  continue;
114934
115083
  }
114935
115084
  await markStale(registration.questionId);
115085
+ resetRetry(registration.questionId);
114936
115086
  schedule(registration.questionId, debounceMs);
114937
115087
  }
114938
115088
  })().catch((err2) => warn({ scope, error: err2 instanceof Error ? err2.name : String(err2) }, "Could not mark derivative questions stale")));
@@ -114943,7 +115093,10 @@ function createRecomputeScheduler(options) {
114943
115093
  void track(markStale(questionId).catch((err2) => warn({
114944
115094
  questionId,
114945
115095
  error: err2 instanceof Error ? err2.name : String(err2)
114946
- }, "Could not mark derivative question stale")).then(() => schedule(questionId, opts?.immediate ? 0 : debounceMs)));
115096
+ }, "Could not mark derivative question stale")).then(() => {
115097
+ resetRetry(questionId);
115098
+ schedule(questionId, opts?.immediate ? 0 : debounceMs);
115099
+ }));
114947
115100
  },
114948
115101
  async whenIdle() {
114949
115102
  const waitForTimers = !options.timers;
@@ -114963,6 +115116,9 @@ function createRecomputeScheduler(options) {
114963
115116
  if (state.timer !== null)
114964
115117
  timers.clearTimeout(state.timer);
114965
115118
  state.timer = null;
115119
+ state.retryAttempts = 0;
115120
+ state.retryAtMs = null;
115121
+ state.retryScheduled = false;
114966
115122
  }
114967
115123
  },
114968
115124
  start() {
@@ -114983,6 +115139,7 @@ function createRecomputeScheduler(options) {
114983
115139
 
114984
115140
  // ../core/dist/derivatives/api.js
114985
115141
  var MAX_QUESTION_BODY_BYTES = 16 * 1024;
115142
+ var RETRY_IN_FLIGHT_POLL_SECONDS = 5;
114986
115143
  function jsonResponse3(body, init) {
114987
115144
  const headers = new Headers(init?.headers);
114988
115145
  headers.set("Content-Type", "application/json");
@@ -115035,12 +115192,63 @@ async function loadForCaller(deps, request2, store, questionId) {
115035
115192
  }
115036
115193
  return { registration, writer };
115037
115194
  }
115195
+ async function handleStatusRoute(request2, url2, deps, store, scheduler, now) {
115196
+ if (request2.method !== "GET") {
115197
+ return errorResponse2(405, "METHOD_NOT_ALLOWED", "Method not allowed");
115198
+ }
115199
+ const derivedScopeParam = url2.searchParams.get("derivedScope");
115200
+ if (!derivedScopeParam) {
115201
+ throw new DerivativeDerivedScopeRequiredError();
115202
+ }
115203
+ const scopeResult = parseDataScopeContract(derivedScopeParam);
115204
+ if (!scopeResult.ok) {
115205
+ return errorResponse2(scopeResult.status, scopeResult.body.error, scopeResult.body.message);
115206
+ }
115207
+ const derivedScope = scopeResult.scope;
115208
+ const auth = await deps.auth.authorizeBuilderRead({
115209
+ request: request2,
115210
+ scope: derivedScope,
115211
+ grantId: selectedGrantId(request2, url2)
115212
+ }) ?? void 0;
115213
+ const registrations = await store.list({ derivedScope });
115214
+ if (registrations.length === 0) {
115215
+ throw new DerivativeQuestionNotFoundError({ derivedScope });
115216
+ }
115217
+ const STATUS_PRECEDENCE = {
115218
+ ready: 0,
115219
+ stale: 1,
115220
+ pending: 2,
115221
+ failed: 3
115222
+ };
115223
+ const registration = registrations.reduce((best, candidate) => {
115224
+ const byStatus = STATUS_PRECEDENCE[candidate.status] - STATUS_PRECEDENCE[best.status];
115225
+ if (byStatus !== 0)
115226
+ return byStatus < 0 ? candidate : best;
115227
+ return candidate.updatedAt >= best.updatedAt ? candidate : best;
115228
+ });
115229
+ const nextRetryAt = scheduler.nextRetryAt?.(registration.questionId) ?? null;
115230
+ const retryAfterSeconds = nextRetryAt !== null ? Math.max(1, Math.ceil((Date.parse(nextRetryAt) - now().getTime()) / 1e3)) : scheduler.retryInFlight?.(registration.questionId) ? RETRY_IN_FLIGHT_POLL_SECONDS : null;
115231
+ const registrarView = auth === void 0 || auth.grantId === "owner" || auth.grantId === "policy-bypass" || registration.registeredBy.kind === "builder" && typeof auth.builder === "string" && sameBuilder(registration.registeredBy.builder, auth.builder);
115232
+ const disclosedErrorCode = registration.errorCode === "grant_invalid" && !registrarView ? "internal" : registration.errorCode;
115233
+ return jsonResponse3({
115234
+ derivedScope: registration.derivedScope,
115235
+ status: registration.status,
115236
+ lastComputedAt: registration.lastComputedAt,
115237
+ derivedVersion: registration.derivedVersion,
115238
+ derivedCollectedAt: registration.derivedCollectedAt,
115239
+ // Null unless failed, whatever an old store row holds: a stale question
115240
+ // is a recompute in progress, not a terminal failure.
115241
+ errorCode: registration.status === "failed" ? disclosedErrorCode : null,
115242
+ retryAfterSeconds
115243
+ });
115244
+ }
115038
115245
  async function handlePersonalServerDerivativesRequest(request2, deps, options = {}) {
115039
115246
  try {
115040
115247
  const url2 = new URL(request2.url);
115041
115248
  const pathname = stripBasePath2(url2.pathname, options.basePath);
115042
115249
  const parts = pathname.split("/").filter(Boolean);
115043
- if (parts[0] !== "questions" || parts.length > 3) {
115250
+ const isStatusRoute = parts[0] === "status" && parts.length === 1;
115251
+ if (!isStatusRoute && (parts[0] !== "questions" || parts.length > 3)) {
115044
115252
  return errorResponse2(404, "NOT_FOUND", "Not found");
115045
115253
  }
115046
115254
  const compute = deps.compute;
@@ -115048,6 +115256,9 @@ async function handlePersonalServerDerivativesRequest(request2, deps, options =
115048
115256
  throw new DerivativeComputeUnavailableError();
115049
115257
  const { store, scheduler } = compute;
115050
115258
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
115259
+ if (isStatusRoute) {
115260
+ return await handleStatusRoute(request2, url2, deps, store, scheduler, now);
115261
+ }
115051
115262
  if (parts.length === 1) {
115052
115263
  if (request2.method === "GET") {
115053
115264
  const derivedScope = url2.searchParams.get("derivedScope") ?? void 0;
@@ -115719,6 +115930,140 @@ function createInMemoryMcpOAuthAuthorizationStore() {
115719
115930
  }
115720
115931
 
115721
115932
  // ../core/dist/mcp/read-client.js
115933
+ var FAIL_CLOSED_CONTEXT = {
115934
+ dropTopLevelLineage: true,
115935
+ dropMetadataLineage: true
115936
+ };
115937
+ function pathUnder(path, prefix) {
115938
+ return path === prefix || path.startsWith(prefix) && /[.[{]/.test(path.charAt(prefix.length));
115939
+ }
115940
+ function groupLabelSegments(path) {
115941
+ const match = /^\$\.data(?:\.metadata)?\.\{(.+):(.+)\}$/.exec(path);
115942
+ return match ? [match[1], match[2]] : [];
115943
+ }
115944
+ function servedLineageShaped(blocks) {
115945
+ return blocks.some((block) => {
115946
+ if (pathUnder(block.path, "$.data.lineage") || pathUnder(block.path, "$.data.metadata.lineage")) {
115947
+ return true;
115948
+ }
115949
+ if (groupLabelSegments(block.path).some((segment) => segment === "lineage" || segment === LINEAGE_KEY)) {
115950
+ return true;
115951
+ }
115952
+ if (!("value" in block) || !isPlainObject3(block.value))
115953
+ return false;
115954
+ const data = block.path === "$" ? block.value["data"] ?? null : block.value;
115955
+ return isPlainObject3(data) && ("lineage" in data || isPlainObject3(data["metadata"]) && "lineage" in data["metadata"]);
115956
+ });
115957
+ }
115958
+ function visibleStampEvidence(blocks) {
115959
+ for (const block of blocks) {
115960
+ if (pathUnder(block.path, `$.data.${LINEAGE_KEY}`) || groupLabelSegments(block.path).includes(LINEAGE_KEY)) {
115961
+ return { dropTopLevelLineage: true, dropMetadataLineage: false };
115962
+ }
115963
+ if ("value" in block && isPlainObject3(block.value)) {
115964
+ const data = block.path === "$" ? block.value["data"] ?? null : block.value;
115965
+ if (isPlainObject3(data) && LINEAGE_KEY in data) {
115966
+ return { dropTopLevelLineage: true, dropMetadataLineage: false };
115967
+ }
115968
+ }
115969
+ }
115970
+ return null;
115971
+ }
115972
+ async function resolveBlockRedactionContext(storage, scope, collectedAt2, blocks) {
115973
+ if (!servedLineageShaped(blocks)) {
115974
+ return { dropTopLevelLineage: false, dropMetadataLineage: false };
115975
+ }
115976
+ const visible = visibleStampEvidence(blocks);
115977
+ if (visible)
115978
+ return visible;
115979
+ try {
115980
+ const envelope = await storage.readEnvelope(scope, collectedAt2);
115981
+ if (!(LINEAGE_KEY in envelope.data)) {
115982
+ return { dropTopLevelLineage: false, dropMetadataLineage: false };
115983
+ }
115984
+ return isBinaryEnvelope(envelope) ? { dropTopLevelLineage: false, dropMetadataLineage: true } : { dropTopLevelLineage: true, dropMetadataLineage: false };
115985
+ } catch {
115986
+ return FAIL_CLOSED_CONTEXT;
115987
+ }
115988
+ }
115989
+ function redactedBlockPathPrefixes(ctx) {
115990
+ return [
115991
+ "$.data.$writtenBy",
115992
+ "$.data.$lineage",
115993
+ ...ctx.dropTopLevelLineage ? ["$.data.lineage"] : [],
115994
+ ...ctx.dropMetadataLineage ? ["$.data.metadata.lineage"] : []
115995
+ ];
115996
+ }
115997
+ function isRedactedBlockPath(path, ctx) {
115998
+ return redactedBlockPathPrefixes(ctx).some((prefix) => path === prefix || path.startsWith(prefix) && /[.[{]/.test(path.charAt(prefix.length)));
115999
+ }
116000
+ function isPlainObject3(value) {
116001
+ return value !== null && typeof value === "object" && !Array.isArray(value);
116002
+ }
116003
+ function isRedactedKeyName(parent, key, ctx) {
116004
+ if (parent === "data") {
116005
+ return key === "$writtenBy" || key === "$lineage" || ctx.dropTopLevelLineage && key === "lineage";
116006
+ }
116007
+ return ctx.dropMetadataLineage && key === "lineage";
116008
+ }
116009
+ function sanitizeGroupLabel(path, ctx) {
116010
+ const match = /^(\$\.data(?:\.metadata)?)\.\{(.+):(.+)\}$/.exec(path);
116011
+ if (!match)
116012
+ return path;
116013
+ const parent = match[1] === "$.data" ? "data" : "metadata";
116014
+ const first = isRedactedKeyName(parent, match[2], ctx) ? "\u2026" : match[2];
116015
+ const last2 = isRedactedKeyName(parent, match[3], ctx) ? "\u2026" : match[3];
116016
+ return `${match[1]}.{${first}:${last2}}`;
116017
+ }
116018
+ function stripMetadataLineage(value, ctx) {
116019
+ if (!ctx.dropMetadataLineage || !isPlainObject3(value["metadata"])) {
116020
+ return value;
116021
+ }
116022
+ const { lineage: _metadataLineage, ...metadataRest } = value["metadata"];
116023
+ if (Object.keys(metadataRest).length === 0) {
116024
+ const { metadata: _emptied, ...rest } = value;
116025
+ return rest;
116026
+ }
116027
+ return { ...value, metadata: metadataRest };
116028
+ }
116029
+ function stripDataLevelKeys(value, ctx) {
116030
+ const { $writtenBy: _writtenBy, $lineage: _lineage, ...rest } = value;
116031
+ let data = rest;
116032
+ if (ctx.dropTopLevelLineage) {
116033
+ const { lineage: _callerLineage, ...dataRest } = data;
116034
+ data = dataRest;
116035
+ }
116036
+ return stripMetadataLineage(data, ctx);
116037
+ }
116038
+ function redactBlockValue(path, value, ctx) {
116039
+ if (!isPlainObject3(value))
116040
+ return value;
116041
+ if (path === "$.data" || /^\$\.data\.\{.*\}$/.test(path)) {
116042
+ return stripDataLevelKeys(value, ctx);
116043
+ }
116044
+ if (path === "$.data.metadata" || /^\$\.data\.metadata\.\{.*\}$/.test(path)) {
116045
+ if (!ctx.dropMetadataLineage)
116046
+ return value;
116047
+ const { lineage: _metadataLineage, ...rest } = value;
116048
+ return rest;
116049
+ }
116050
+ if (path === "$" && isPlainObject3(value["data"])) {
116051
+ return { ...value, data: stripDataLevelKeys(value["data"], ctx) };
116052
+ }
116053
+ return value;
116054
+ }
116055
+ function redactBlockRefsForGrantee(blocks, ctx) {
116056
+ return blocks.filter((block) => !isRedactedBlockPath(block.path, ctx)).map((block) => ({ ...block, path: sanitizeGroupLabel(block.path, ctx) }));
116057
+ }
116058
+ function redactBlockPayloadsForGrantee(blocks, ctx) {
116059
+ return blocks.filter((block) => !isRedactedBlockPath(block.path, ctx)).flatMap((block) => {
116060
+ const value = redactBlockValue(block.path, block.value, ctx);
116061
+ if (isPlainObject3(block.value) && Object.keys(block.value).length > 0 && isPlainObject3(value) && Object.keys(value).length === 0) {
116062
+ return [];
116063
+ }
116064
+ return [{ ...block, path: sanitizeGroupLabel(block.path, ctx), value }];
116065
+ });
116066
+ }
115722
116067
  var McpDataReadError = class extends Error {
115723
116068
  status;
115724
116069
  body;
@@ -115887,7 +116232,11 @@ function createMcpDataReadClient(options) {
115887
116232
  userAgent
115888
116233
  });
115889
116234
  }
115890
- return { status: 200, ...result };
116235
+ return isOwnerView(authResult) ? { status: 200, ...result } : {
116236
+ status: 200,
116237
+ ...result,
116238
+ blocks: redactBlockPayloadsForGrantee(result.blocks, await resolveBlockRedactionContext(storage, scope, selectedEntry.collectedAt, result.blocks))
116239
+ };
115891
116240
  } catch (err2) {
115892
116241
  if (err2 instanceof ProtocolError) {
115893
116242
  throw new McpDataReadError(err2.code, err2.toJSON());
@@ -115924,6 +116273,12 @@ function createMcpDataReadClient(options) {
115924
116273
  });
115925
116274
  const manifest = await storage.readBlockManifest(scope, selectedEntry.collectedAt);
115926
116275
  await writeReadAccessLog(request2, { scope, grantId, authResult });
116276
+ if (manifest && !isOwnerView(authResult)) {
116277
+ return {
116278
+ ...manifest,
116279
+ blocks: redactBlockRefsForGrantee(manifest.blocks, await resolveBlockRedactionContext(storage, scope, selectedEntry.collectedAt, manifest.blocks))
116280
+ };
116281
+ }
115927
116282
  return manifest;
115928
116283
  },
115929
116284
  async readRawScopeFile({ scope, grantId, at: at3, fileId, payment }) {
@@ -127072,7 +127427,7 @@ var Protocol = class {
127072
127427
  };
127073
127428
  }
127074
127429
  };
127075
- function isPlainObject3(value) {
127430
+ function isPlainObject4(value) {
127076
127431
  return value !== null && typeof value === "object" && !Array.isArray(value);
127077
127432
  }
127078
127433
  function mergeCapabilities(base, additional) {
@@ -127083,7 +127438,7 @@ function mergeCapabilities(base, additional) {
127083
127438
  if (addValue === void 0)
127084
127439
  continue;
127085
127440
  const baseValue = result[k10];
127086
- if (isPlainObject3(baseValue) && isPlainObject3(addValue)) {
127441
+ if (isPlainObject4(baseValue) && isPlainObject4(addValue)) {
127087
127442
  result[k10] = { ...baseValue, ...addValue };
127088
127443
  } else {
127089
127444
  result[k10] = addValue;
@@ -130256,6 +130611,12 @@ function createBearerTokenPsLiteAuth(options) {
130256
130611
  reason: "No grantId in request"
130257
130612
  });
130258
130613
  }
130614
+ if (input.grantId === "owner" || input.grantId === "policy-bypass") {
130615
+ throw new GrantRequiredError({
130616
+ reason: "Reserved grantId",
130617
+ grantId: input.grantId
130618
+ });
130619
+ }
130259
130620
  return { grantId: input.grantId };
130260
130621
  }
130261
130622
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opendatalabs/personal-server-ts-server",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "Hono HTTP server for the Vana Personal Server — routes, middleware, composition root",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -44,8 +44,8 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@hono/node-server": "^1.19.13",
47
- "@opendatalabs/personal-server-ts-core": "1.13.0",
48
- "@opendatalabs/personal-server-ts-lite": "1.13.0",
47
+ "@opendatalabs/personal-server-ts-core": "1.14.0",
48
+ "@opendatalabs/personal-server-ts-lite": "1.14.0",
49
49
  "@opendatalabs/vana-sdk": "3.14.0",
50
50
  "better-sqlite3": "^12.11.1",
51
51
  "hono": "^4.12.27",