@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.
- package/dist/logging/access-log.d.ts +2 -13
- package/dist/logging/access-log.d.ts.map +1 -1
- package/dist/logging/access-log.js.map +1 -1
- package/dist/storage/question-store.d.ts.map +1 -1
- package/dist/storage/question-store.js +28 -3
- package/dist/storage/question-store.js.map +1 -1
- package/dist/ui/ps-lite-debug.js +380 -19
- package/package.json +3 -3
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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":"
|
|
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;
|
|
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,
|
|
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
|
-
|
|
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":"AAAA;;;;GAIG;AAGH,OAAO,EACL,qBAAqB,
|
|
1
|
+
{"version":3,"file":"question-store.js","sourceRoot":"","sources":["../../src/storage/question-store.ts"],"names":[],"mappings":"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"}
|
package/dist/ui/ps-lite-debug.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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 ?? {
|
|
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 = {
|
|
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(() =>
|
|
114886
|
-
|
|
114887
|
-
|
|
114888
|
-
|
|
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 (
|
|
114895
|
-
|
|
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(() =>
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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.
|
|
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.
|
|
48
|
-
"@opendatalabs/personal-server-ts-lite": "1.
|
|
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",
|