@substrat-run/adapter-sqlite 0.149.0 → 0.151.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/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +152 -17
- package/dist/index.js.map +1 -1
- package/dist/trace.d.ts +42 -0
- package/dist/trace.d.ts.map +1 -0
- package/dist/trace.js +91 -0
- package/dist/trace.js.map +1 -0
- package/package.json +7 -7
package/dist/trace.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The scope host's half of a request trace (#2358): what only the host sees.
|
|
3
|
+
*
|
|
4
|
+
* Every function here is a no-op until something installs a sink (`installedTraceSink`), and
|
|
5
|
+
* `substrat dev` is the only thing that does. The hosted adapter never loads this package, and
|
|
6
|
+
* a deploy that installs none records nothing, so the cost of tracing on any other path is one
|
|
7
|
+
* `globalThis` read per invocation.
|
|
8
|
+
*
|
|
9
|
+
* Two rules for everything below. A hook never changes what the host does: it reads the
|
|
10
|
+
* value the host already computed, and a sink that throws is swallowed rather than allowed to
|
|
11
|
+
* fail a request. And nothing is invented: a deny's `requires` and `callerHas` come from the
|
|
12
|
+
* role table and the checker's own `holdings`, the same sources a console would read.
|
|
13
|
+
*/
|
|
14
|
+
import { type EntityRef, type RelationTuple, type TraceHeadPatch, type TraceStep } from '@substrat-run/contracts';
|
|
15
|
+
import type { ScopedSql } from '@substrat-run/kernel';
|
|
16
|
+
/** A step as a hook writes it: the host stamps `atMs`. */
|
|
17
|
+
export type TraceStepInput = TraceStep extends infer S ? (S extends TraceStep ? Omit<S, 'atMs'> : never) : never;
|
|
18
|
+
/** One invocation's handle on the installed sink. */
|
|
19
|
+
export interface InvocationTrace {
|
|
20
|
+
/** Whether the sink asked for the values bound to a statement. */
|
|
21
|
+
readonly sqlParams: boolean;
|
|
22
|
+
step(step: TraceStepInput): void;
|
|
23
|
+
head(patch: TraceHeadPatch): void;
|
|
24
|
+
/** Milliseconds on the same clock a step's `atMs` reads, for timing a span. */
|
|
25
|
+
now(): number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The handle for an invocation, or `undefined` when tracing is off or the call has no id.
|
|
29
|
+
* Steps are stamped on the time axis the request layer started (`traceOffsetMs`), so a check
|
|
30
|
+
* here and an outbound call there sort in the order they happened.
|
|
31
|
+
*/
|
|
32
|
+
export declare function invocationTrace(invocationId: string | null | undefined): InvocationTrace | undefined;
|
|
33
|
+
/** The invocation is over on this host: release its start. (The sink's `end` is the HTTP layer's.) */
|
|
34
|
+
export declare function forgetInvocationTrace(invocationId: string | null | undefined): void;
|
|
35
|
+
export declare const entityString: (entity: EntityRef | undefined | null) => string | null;
|
|
36
|
+
/**
|
|
37
|
+
* Which path an ALLOW took, read off the proof tuples: a role (`role:<key>`), a system module
|
|
38
|
+
* (`system:<module>`), or a direct / entity-narrowed grant (`grant:<object>`).
|
|
39
|
+
*/
|
|
40
|
+
export declare function decidedByOf(proof: readonly RelationTuple[]): string | null;
|
|
41
|
+
export declare function tracedSql(sql: ScopedSql, trace: InvocationTrace | undefined, redactText: (text: string) => string, redactValue: <T>(value: T) => T): ScopedSql;
|
|
42
|
+
//# sourceMappingURL=trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../src/trace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,0DAA0D;AAC1D,MAAM,MAAM,cAAc,GAAG,SAAS,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,SAAS,GAAG,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;AAEjH,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,+EAA+E;IAC/E,GAAG,IAAI,MAAM,CAAC;CACf;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CAiBpG;AAED,sGAAsG;AACtG,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAEnF;AAED,eAAO,MAAM,YAAY,WAAY,SAAS,GAAG,SAAS,GAAG,IAAI,KAAG,MAAM,GAAG,IAClB,CAAC;AAE5D;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,GAAG,IAAI,CAK1E;AAUD,wBAAgB,SAAS,CACvB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,eAAe,GAAG,SAAS,EAClC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACpC,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,GAC9B,SAAS,CA4BX"}
|
package/dist/trace.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The scope host's half of a request trace (#2358): what only the host sees.
|
|
3
|
+
*
|
|
4
|
+
* Every function here is a no-op until something installs a sink (`installedTraceSink`), and
|
|
5
|
+
* `substrat dev` is the only thing that does. The hosted adapter never loads this package, and
|
|
6
|
+
* a deploy that installs none records nothing, so the cost of tracing on any other path is one
|
|
7
|
+
* `globalThis` read per invocation.
|
|
8
|
+
*
|
|
9
|
+
* Two rules for everything below. A hook never changes what the host does: it reads the
|
|
10
|
+
* value the host already computed, and a sink that throws is swallowed rather than allowed to
|
|
11
|
+
* fail a request. And nothing is invented: a deny's `requires` and `callerHas` come from the
|
|
12
|
+
* role table and the checker's own `holdings`, the same sources a console would read.
|
|
13
|
+
*/
|
|
14
|
+
import { forgetTraceStart, installedTraceSink, traceOffsetMs, } from '@substrat-run/contracts';
|
|
15
|
+
const clock = () => performance.now();
|
|
16
|
+
/**
|
|
17
|
+
* The handle for an invocation, or `undefined` when tracing is off or the call has no id.
|
|
18
|
+
* Steps are stamped on the time axis the request layer started (`traceOffsetMs`), so a check
|
|
19
|
+
* here and an outbound call there sort in the order they happened.
|
|
20
|
+
*/
|
|
21
|
+
export function invocationTrace(invocationId) {
|
|
22
|
+
const sink = installedTraceSink();
|
|
23
|
+
if (!sink || !invocationId)
|
|
24
|
+
return undefined;
|
|
25
|
+
const guard = (fn) => {
|
|
26
|
+
try {
|
|
27
|
+
fn();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
/* a trace must never fail the request it describes */
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
sqlParams: sink.capture?.sqlParams === true,
|
|
35
|
+
step: (step) => guard(() => sink.step(invocationId, { ...step, atMs: traceOffsetMs(invocationId) })),
|
|
36
|
+
head: (patch) => guard(() => sink.head(invocationId, patch)),
|
|
37
|
+
now: clock,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** The invocation is over on this host: release its start. (The sink's `end` is the HTTP layer's.) */
|
|
41
|
+
export function forgetInvocationTrace(invocationId) {
|
|
42
|
+
if (invocationId)
|
|
43
|
+
forgetTraceStart(invocationId);
|
|
44
|
+
}
|
|
45
|
+
export const entityString = (entity) => entity ? `${entity.entityType}:${entity.entityId}` : null;
|
|
46
|
+
/**
|
|
47
|
+
* Which path an ALLOW took, read off the proof tuples: a role (`role:<key>`), a system module
|
|
48
|
+
* (`system:<module>`), or a direct / entity-narrowed grant (`grant:<object>`).
|
|
49
|
+
*/
|
|
50
|
+
export function decidedByOf(proof) {
|
|
51
|
+
for (const t of proof)
|
|
52
|
+
if (String(t.subject).startsWith('role:'))
|
|
53
|
+
return String(t.subject);
|
|
54
|
+
for (const t of proof)
|
|
55
|
+
if (String(t.subject).startsWith('system:'))
|
|
56
|
+
return String(t.subject);
|
|
57
|
+
for (const t of proof)
|
|
58
|
+
if (String(t.relation).startsWith('granted:'))
|
|
59
|
+
return `grant:${String(t.object)}`;
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
export function tracedSql(sql, trace, redactText, redactValue) {
|
|
63
|
+
if (!trace)
|
|
64
|
+
return sql;
|
|
65
|
+
const run = (operation, statement, params, call, rows) => {
|
|
66
|
+
const started = trace.now();
|
|
67
|
+
const at = (error) => ({
|
|
68
|
+
type: 'sql',
|
|
69
|
+
operation,
|
|
70
|
+
statement: redactText(statement),
|
|
71
|
+
// Only what the sink asked for: a bound value is as likely a person's data as an id.
|
|
72
|
+
...(trace.sqlParams ? { params: redactValue([...params]) } : {}),
|
|
73
|
+
durationMs: Math.max(0, Math.round(trace.now() - started)),
|
|
74
|
+
...(error === undefined ? {} : { error }),
|
|
75
|
+
});
|
|
76
|
+
try {
|
|
77
|
+
const result = call();
|
|
78
|
+
trace.step({ ...at(), ...rows(result) });
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
trace.step(at(redactText(err instanceof Error ? err.message : String(err))));
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
query: ((statement, params = []) => run('query', statement, params, () => sql.query(statement, params), (r) => ({ rowsRead: r.length }))),
|
|
88
|
+
exec: ((statement, params = []) => run('exec', statement, params, () => sql.exec(statement, params), (r) => ({ rowsWritten: r.changes }))),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.js","sourceRoot":"","sources":["../src/trace.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/adapter-sqlite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.151.0",
|
|
4
4
|
"description": "Pure-SQLite scope host — real kernel semantics with no Cloudflare dependency (D-14): local dev, CI, self-host/escrow",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -39,17 +39,17 @@
|
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"better-sqlite3": "^13.0.3",
|
|
42
|
-
"@substrat-run/contracts": "^0.
|
|
43
|
-
"@substrat-run/kernel": "^0.
|
|
42
|
+
"@substrat-run/contracts": "^0.151.0",
|
|
43
|
+
"@substrat-run/kernel": "^0.151.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/better-sqlite3": "^9.6.0",
|
|
47
47
|
"hono": "^4.13.13",
|
|
48
48
|
"typescript": "^7.0.0",
|
|
49
|
-
"vitest": "^5.0.
|
|
50
|
-
"@substrat-run/attachment-extractors": "^0.2.
|
|
51
|
-
"@substrat-run/contract-tests": "^0.
|
|
52
|
-
"@substrat-run/vertical-auth": "^0.
|
|
49
|
+
"vitest": "^5.0.5",
|
|
50
|
+
"@substrat-run/attachment-extractors": "^0.2.12",
|
|
51
|
+
"@substrat-run/contract-tests": "^0.151.0",
|
|
52
|
+
"@substrat-run/vertical-auth": "^0.25.0"
|
|
53
53
|
},
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public"
|