@fuzdev/fuz_app 0.146.1 → 0.147.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/auth/CLAUDE.md +1 -1
- package/dist/auth/bootstrap_account.d.ts +2 -1
- package/dist/auth/bootstrap_account.d.ts.map +1 -1
- package/dist/auth/bootstrap_account.js +17 -6
- package/dist/auth/keyring.d.ts +35 -38
- package/dist/auth/keyring.d.ts.map +1 -1
- package/dist/auth/keyring.js +43 -50
- package/dist/auth/password_argon2.d.ts.map +1 -1
- package/dist/auth/password_argon2.js +11 -8
- package/dist/auth/session_cookie.d.ts.map +1 -1
- package/dist/auth/session_cookie.js +5 -2
- package/dist/db/CLAUDE.md +18 -16
- package/dist/db/cell_queries.d.ts +3 -2
- package/dist/db/cell_queries.d.ts.map +1 -1
- package/dist/db/cell_queries.js +3 -2
- package/dist/db/fact_disk_storage.d.ts +15 -15
- package/dist/db/fact_disk_storage.d.ts.map +1 -1
- package/dist/db/fact_disk_storage.js +22 -28
- package/dist/db/fact_queries.d.ts +2 -3
- package/dist/db/fact_queries.d.ts.map +1 -1
- package/dist/db/fact_queries.js +2 -3
- package/dist/db/fact_store.d.ts +20 -18
- package/dist/db/fact_store.d.ts.map +1 -1
- package/dist/db/fact_store.js +30 -44
- package/dist/db/file_fact_url.d.ts +19 -4
- package/dist/db/file_fact_url.d.ts.map +1 -1
- package/dist/db/file_fact_url.js +19 -4
- package/dist/server/env.d.ts.map +1 -1
- package/dist/server/env.js +2 -2
- package/dist/server/serve_fact_route.d.ts +9 -5
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +15 -7
- package/dist/testing/CLAUDE.md +19 -2
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +2 -2
- package/dist/testing/cross_backend/bootstrap_backend.d.ts +11 -1
- package/dist/testing/cross_backend/bootstrap_backend.d.ts.map +1 -1
- package/dist/testing/cross_backend/bootstrap_backend.js +2 -1
- package/dist/testing/cross_backend/fact_serving.d.ts +5 -0
- package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
- package/dist/testing/cross_backend/fact_serving.js +25 -1
- package/dist/testing/cross_backend/session_cookie_codec.d.ts +19 -0
- package/dist/testing/cross_backend/session_cookie_codec.d.ts.map +1 -0
- package/dist/testing/cross_backend/session_cookie_codec.js +128 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +7 -3
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +13 -8
- package/package.json +6 -6
package/dist/auth/CLAUDE.md
CHANGED
|
@@ -31,7 +31,7 @@ over the pool so rows persist when request transactions roll back. See root
|
|
|
31
31
|
|
|
32
32
|
### Crypto primitives (pure, I/O-free)
|
|
33
33
|
|
|
34
|
-
- `auth/keyring.ts` — `Keyring`, `create_keyring
|
|
34
|
+
- `auth/keyring.ts` — `Keyring`, `create_keyring` (validates — the one way to build a `Keyring`), `validate_keyring`.
|
|
35
35
|
- `auth/session_cookie.ts` — `SessionOptions<T>`, `parse_session`, `process_session_cookie` (`'none' | 'clear'` — no refresh action; the 30-day lifetime is an absolute cap signed once at mint), `create_session_config`, `fuz_session_config`, `SESSION_AGE_MAX`.
|
|
36
36
|
- `auth/password.ts` — `Password`, `PasswordProvided`, `PasswordHashDeps`, `PASSWORD_LENGTH_MIN` (12, OWASP), `PASSWORD_LENGTH_MAX` (300).
|
|
37
37
|
- `auth/password_argon2.ts` — `hash_password`, `verify_password`, `verify_dummy`, `argon2_password_deps`.
|
|
@@ -72,7 +72,8 @@ export interface BootstrapAccountDeps {
|
|
|
72
72
|
* Uses an atomic `bootstrap_lock` UPDATE to prevent concurrent bootstrap
|
|
73
73
|
* attempts (TOCTOU). The full flow runs in a single transaction:
|
|
74
74
|
*
|
|
75
|
-
* 1. Read and verify the bootstrap token (before transaction)
|
|
75
|
+
* 1. Read and verify the bootstrap token (before transaction) — the file's
|
|
76
|
+
* raw bytes less one optional trailing LF, compared in constant time
|
|
76
77
|
* 2. Hash the password (CPU-intensive, before transaction)
|
|
77
78
|
* 3. Acquire the bootstrap lock atomically (inside transaction)
|
|
78
79
|
* 4. Create account + actor
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap_account.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bootstrap_account.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EACN,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEtC,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,6DAA6D;AAC7D,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC;IACrD,wFAAwF;IACxF,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAED,gCAAgC;AAChC,MAAM,MAAM,uBAAuB,GAChC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,0BAA0B,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,GACpE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,wBAAwB,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,GAClE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,mBAAmB,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,CAAC;AAEjE,qFAAqF;AACrF,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG,uBAAuB,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,EAAE,EAAE,EAAE,CAAC;IACP,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACxD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,6EAA6E;IAC7E,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;IAClD,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;CACZ;
|
|
1
|
+
{"version":3,"file":"bootstrap_account.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/bootstrap_account.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EACN,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEtC,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,6DAA6D;AAC7D,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,IAAI,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC;IACrD,wFAAwF;IACxF,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAED,gCAAgC;AAChC,MAAM,MAAM,uBAAuB,GAChC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,0BAA0B,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,GACpE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,wBAAwB,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,GAClE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,mBAAmB,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,CAAC;AAEjE,qFAAqF;AACrF,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG,uBAAuB,CAAC;AAEvF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,EAAE,EAAE,EAAE,CAAC;IACP,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACxD,qBAAqB;IACrB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,6EAA6E;IAC7E,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;IAClD,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;CACZ;AAcD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,oBAAoB,EAC1B,gBAAgB,MAAM,EACtB,OAAO,qBAAqB,KAC1B,OAAO,CAAC,sBAAsB,CA6EhC,CAAC"}
|
|
@@ -12,13 +12,24 @@ import { ERROR_INVALID_TOKEN, ERROR_ALREADY_BOOTSTRAPPED, ERROR_TOKEN_FILE_MISSI
|
|
|
12
12
|
import { ROLE_ADMIN, ROLE_KEEPER } from './role_schema.js';
|
|
13
13
|
import { query_create_account_with_actor } from './account_queries.js';
|
|
14
14
|
import { query_create_role_grant } from './role_grant_queries.js';
|
|
15
|
+
/**
|
|
16
|
+
* Strip exactly one trailing `\n` from the operator-written token bytes.
|
|
17
|
+
*
|
|
18
|
+
* Not `trim()`: trimming widens the set of accepted tokens — `tok\r\n`,
|
|
19
|
+
* `tok \n`, or a leading newline would all pass. One trailing LF is the
|
|
20
|
+
* newline a POSIX editor appends; anything else stays in the bytes and fails
|
|
21
|
+
* the compare, so operators write the token exactly. Twin of the Rust
|
|
22
|
+
* `strip_one_trailing_newline` (`fuz_auth`).
|
|
23
|
+
*/
|
|
24
|
+
const strip_one_trailing_newline = (bytes) => bytes.at(-1) === 0x0a ? bytes.subarray(0, -1) : bytes;
|
|
15
25
|
/**
|
|
16
26
|
* Bootstrap the first account with keeper and admin privileges.
|
|
17
27
|
*
|
|
18
28
|
* Uses an atomic `bootstrap_lock` UPDATE to prevent concurrent bootstrap
|
|
19
29
|
* attempts (TOCTOU). The full flow runs in a single transaction:
|
|
20
30
|
*
|
|
21
|
-
* 1. Read and verify the bootstrap token (before transaction)
|
|
31
|
+
* 1. Read and verify the bootstrap token (before transaction) — the file's
|
|
32
|
+
* raw bytes less one optional trailing LF, compared in constant time
|
|
22
33
|
* 2. Hash the password (CPU-intensive, before transaction)
|
|
23
34
|
* 3. Acquire the bootstrap lock atomically (inside transaction)
|
|
24
35
|
* 4. Create account + actor
|
|
@@ -41,17 +52,17 @@ export const bootstrap_account = async (deps, provided_token, input) => {
|
|
|
41
52
|
// wire always carried, with the specific reason logged for the operator.
|
|
42
53
|
let expected_token;
|
|
43
54
|
try {
|
|
44
|
-
expected_token =
|
|
55
|
+
expected_token = strip_one_trailing_newline(await read_secure_file(token_path));
|
|
45
56
|
}
|
|
46
57
|
catch (err) {
|
|
47
58
|
log.warn(`bootstrap token file rejected: ${to_error_message(err)}`);
|
|
48
59
|
return { ok: false, error: ERROR_TOKEN_FILE_MISSING, status: 404 };
|
|
49
60
|
}
|
|
50
|
-
//
|
|
51
|
-
//
|
|
61
|
+
// raw bytes on both sides, nothing trimmed — the provided token must be the
|
|
62
|
+
// file's bytes exactly, less the one newline an editor appends
|
|
52
63
|
const provided_buf = Buffer.from(provided_token);
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
if (provided_buf.length !== expected_token.length ||
|
|
65
|
+
!timingSafeEqual(provided_buf, expected_token)) {
|
|
55
66
|
return { ok: false, error: ERROR_INVALID_TOKEN, status: 401 };
|
|
56
67
|
}
|
|
57
68
|
// 2. Hash password (CPU-intensive, before transaction)
|
package/dist/auth/keyring.d.ts
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```ts
|
|
10
|
-
* const
|
|
11
|
-
* if (!
|
|
10
|
+
* const result = create_keyring(process.env.SECRET_FUZ_COOKIE_KEYS);
|
|
11
|
+
* if (!result.ok) throw new Error(`SECRET_FUZ_COOKIE_KEYS: ${result.errors.join('; ')}`);
|
|
12
12
|
*
|
|
13
|
-
* const signed = await keyring.sign('user:123:1700000000');
|
|
14
|
-
* const
|
|
15
|
-
* //
|
|
13
|
+
* const signed = await result.keyring.sign('user:123:1700000000');
|
|
14
|
+
* const verified = await result.keyring.verify(signed);
|
|
15
|
+
* // verified = { value: 'user:123:1700000000', key_index: 0 }
|
|
16
16
|
* ```
|
|
17
17
|
*
|
|
18
18
|
* @module
|
|
@@ -38,24 +38,42 @@ export interface Keyring {
|
|
|
38
38
|
} | null>;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* Result of `create_keyring`.
|
|
42
|
+
* Discriminated union — callers handle the error case their own way.
|
|
43
|
+
*/
|
|
44
|
+
export type CreateKeyringResult = {
|
|
45
|
+
ok: true;
|
|
46
|
+
keyring: Keyring;
|
|
47
|
+
} | {
|
|
48
|
+
ok: false;
|
|
49
|
+
errors: Array<string>;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Validate a keys value and create a keyring from it — the one way to build a
|
|
53
|
+
* `Keyring`.
|
|
42
54
|
*
|
|
43
|
-
* Keys are separated by `__` for rotation support
|
|
44
|
-
*
|
|
55
|
+
* Keys are separated by `__` for rotation support; empty entries are skipped.
|
|
56
|
+
* The first key signs, every key verifies. A value with no key, or with any key
|
|
57
|
+
* shorter than `MIN_KEY_LENGTH` characters, is refused with every reason
|
|
58
|
+
* (`validate_keyring`), so a weak key fails loud at startup rather than signing
|
|
59
|
+
* cookies. Twin of the Rust `Keyring::new`.
|
|
45
60
|
*
|
|
46
|
-
*
|
|
61
|
+
* Returns a discriminated union so callers handle exit/logging their own way
|
|
62
|
+
* (e.g. `Deno.exit(1)` vs `runtime.exit(1)`). CryptoKeys are cached on first use.
|
|
47
63
|
*
|
|
48
|
-
* **
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
64
|
+
* **Key rotation is an operational concern.** Put the new key first and keep
|
|
65
|
+
* the old one after it: new cookies are signed with the new key, and cookies
|
|
66
|
+
* the old key signed keep verifying. Nothing re-signs a cookie, so an old key
|
|
67
|
+
* stays live until the last cookie it signed expires — `SESSION_AGE_MAX` after
|
|
68
|
+
* the rotation — and dropping it sooner signs out every session it still
|
|
69
|
+
* carries. A key that leaked is dropped at once, since it can forge cookies for
|
|
70
|
+
* as long as it is listed. Treat `SECRET_FUZ_COOKIE_KEYS` changes as
|
|
71
|
+
* security-critical deploys.
|
|
54
72
|
*
|
|
55
73
|
* @param env_value - the SECRET_FUZ_COOKIE_KEYS environment variable
|
|
56
|
-
* @returns keyring or
|
|
74
|
+
* @returns `{ok: true, keyring}` or `{ok: false, errors}`
|
|
57
75
|
*/
|
|
58
|
-
export declare const create_keyring: (env_value: string | undefined) =>
|
|
76
|
+
export declare const create_keyring: (env_value: string | undefined) => CreateKeyringResult;
|
|
59
77
|
/**
|
|
60
78
|
* Validate key ring configuration.
|
|
61
79
|
*
|
|
@@ -67,25 +85,4 @@ export declare const create_keyring: (env_value: string | undefined) => Keyring
|
|
|
67
85
|
* @returns array of validation errors (empty if valid)
|
|
68
86
|
*/
|
|
69
87
|
export declare const validate_keyring: (env_value: string | undefined) => Array<string>;
|
|
70
|
-
/**
|
|
71
|
-
* Result of `create_validated_keyring`.
|
|
72
|
-
* Discriminated union — callers handle the error case their own way.
|
|
73
|
-
*/
|
|
74
|
-
export type ValidatedKeyringResult = {
|
|
75
|
-
ok: true;
|
|
76
|
-
keyring: Keyring;
|
|
77
|
-
} | {
|
|
78
|
-
ok: false;
|
|
79
|
-
errors: Array<string>;
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* Validate and create a keyring in one step.
|
|
83
|
-
*
|
|
84
|
-
* Returns a discriminated union so callers handle exit/logging their own way
|
|
85
|
-
* (e.g. `Deno.exit(1)` vs `runtime.exit(1)`).
|
|
86
|
-
*
|
|
87
|
-
* @param env_value - the SECRET_FUZ_COOKIE_KEYS environment variable
|
|
88
|
-
* @returns `{ok: true, keyring}` or `{ok: false, errors}`
|
|
89
|
-
*/
|
|
90
|
-
export declare const create_validated_keyring: (env_value: string | undefined) => ValidatedKeyringResult;
|
|
91
88
|
//# sourceMappingURL=keyring.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyring.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/keyring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"keyring.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/keyring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAiBH;;;GAGG;AACH,MAAM,WAAW,OAAO;IACvB;;;OAGG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzC;;;;OAIG;IACH,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CACvF;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC9B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,cAAc,GAAI,WAAW,MAAM,GAAG,SAAS,KAAG,mBAmC9D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,MAAM,GAAG,SAAS,KAAG,KAAK,CAAC,MAAM,CAc5E,CAAC"}
|
package/dist/auth/keyring.js
CHANGED
|
@@ -7,41 +7,58 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```ts
|
|
10
|
-
* const
|
|
11
|
-
* if (!
|
|
10
|
+
* const result = create_keyring(process.env.SECRET_FUZ_COOKIE_KEYS);
|
|
11
|
+
* if (!result.ok) throw new Error(`SECRET_FUZ_COOKIE_KEYS: ${result.errors.join('; ')}`);
|
|
12
12
|
*
|
|
13
|
-
* const signed = await keyring.sign('user:123:1700000000');
|
|
14
|
-
* const
|
|
15
|
-
* //
|
|
13
|
+
* const signed = await result.keyring.sign('user:123:1700000000');
|
|
14
|
+
* const verified = await result.keyring.verify(signed);
|
|
15
|
+
* // verified = { value: 'user:123:1700000000', key_index: 0 }
|
|
16
16
|
* ```
|
|
17
17
|
*
|
|
18
18
|
* @module
|
|
19
19
|
*/
|
|
20
20
|
const KEY_SEPARATOR = '__';
|
|
21
21
|
const MIN_KEY_LENGTH = 32;
|
|
22
|
+
/**
|
|
23
|
+
* The one spelling of an HMAC-SHA256 signature the keyring accepts: 32 bytes as
|
|
24
|
+
* padded standard base64 — 43 characters, the last holding the final 2 bits
|
|
25
|
+
* with zero low bits, then one `=`. Stricter than `atob`, which skips
|
|
26
|
+
* whitespace, accepts missing padding, and ignores trailing bits, so several
|
|
27
|
+
* strings would otherwise verify as one signature. Matches the Rust twin's
|
|
28
|
+
* strict decode.
|
|
29
|
+
*/
|
|
30
|
+
const SIGNATURE_BASE64_PATTERN = /^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/;
|
|
22
31
|
const encoder = new TextEncoder();
|
|
23
32
|
/**
|
|
24
|
-
*
|
|
33
|
+
* Validate a keys value and create a keyring from it — the one way to build a
|
|
34
|
+
* `Keyring`.
|
|
25
35
|
*
|
|
26
|
-
* Keys are separated by `__` for rotation support
|
|
27
|
-
*
|
|
36
|
+
* Keys are separated by `__` for rotation support; empty entries are skipped.
|
|
37
|
+
* The first key signs, every key verifies. A value with no key, or with any key
|
|
38
|
+
* shorter than `MIN_KEY_LENGTH` characters, is refused with every reason
|
|
39
|
+
* (`validate_keyring`), so a weak key fails loud at startup rather than signing
|
|
40
|
+
* cookies. Twin of the Rust `Keyring::new`.
|
|
28
41
|
*
|
|
29
|
-
*
|
|
42
|
+
* Returns a discriminated union so callers handle exit/logging their own way
|
|
43
|
+
* (e.g. `Deno.exit(1)` vs `runtime.exit(1)`). CryptoKeys are cached on first use.
|
|
30
44
|
*
|
|
31
|
-
* **
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
45
|
+
* **Key rotation is an operational concern.** Put the new key first and keep
|
|
46
|
+
* the old one after it: new cookies are signed with the new key, and cookies
|
|
47
|
+
* the old key signed keep verifying. Nothing re-signs a cookie, so an old key
|
|
48
|
+
* stays live until the last cookie it signed expires — `SESSION_AGE_MAX` after
|
|
49
|
+
* the rotation — and dropping it sooner signs out every session it still
|
|
50
|
+
* carries. A key that leaked is dropped at once, since it can forge cookies for
|
|
51
|
+
* as long as it is listed. Treat `SECRET_FUZ_COOKIE_KEYS` changes as
|
|
52
|
+
* security-critical deploys.
|
|
37
53
|
*
|
|
38
54
|
* @param env_value - the SECRET_FUZ_COOKIE_KEYS environment variable
|
|
39
|
-
* @returns keyring or
|
|
55
|
+
* @returns `{ok: true, keyring}` or `{ok: false, errors}`
|
|
40
56
|
*/
|
|
41
57
|
export const create_keyring = (env_value) => {
|
|
58
|
+
const errors = validate_keyring(env_value);
|
|
59
|
+
if (errors.length > 0)
|
|
60
|
+
return { ok: false, errors };
|
|
42
61
|
const secrets = parse_keys(env_value);
|
|
43
|
-
if (secrets.length === 0)
|
|
44
|
-
return null;
|
|
45
62
|
// Cache CryptoKey promises - imported once on first use
|
|
46
63
|
const key_cache = [];
|
|
47
64
|
const get_key = (index) => {
|
|
@@ -51,7 +68,7 @@ export const create_keyring = (env_value) => {
|
|
|
51
68
|
return key_cache[index];
|
|
52
69
|
};
|
|
53
70
|
// Create the opaque key ring - secrets captured in closure, never exposed
|
|
54
|
-
|
|
71
|
+
const keyring = {
|
|
55
72
|
async sign(value) {
|
|
56
73
|
const key = await get_key(0);
|
|
57
74
|
return sign_with_crypto_key(value, key);
|
|
@@ -67,6 +84,7 @@ export const create_keyring = (env_value) => {
|
|
|
67
84
|
return null;
|
|
68
85
|
}
|
|
69
86
|
};
|
|
87
|
+
return { ok: true, keyring };
|
|
70
88
|
};
|
|
71
89
|
/**
|
|
72
90
|
* Validate key ring configuration.
|
|
@@ -105,41 +123,16 @@ const verify_with_crypto_key = async (signed_value, key) => {
|
|
|
105
123
|
return false;
|
|
106
124
|
const value = signed_value.slice(0, dot_index);
|
|
107
125
|
const signature_base64 = signed_value.slice(dot_index + 1);
|
|
108
|
-
|
|
109
|
-
try {
|
|
110
|
-
const decoded = atob(signature_base64);
|
|
111
|
-
const bytes = new Uint8Array(decoded.length);
|
|
112
|
-
for (let i = 0; i < decoded.length; i++) {
|
|
113
|
-
bytes[i] = decoded.charCodeAt(i);
|
|
114
|
-
}
|
|
115
|
-
signature = bytes.buffer;
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
126
|
+
if (!SIGNATURE_BASE64_PATTERN.test(signature_base64))
|
|
118
127
|
return false;
|
|
128
|
+
const decoded = atob(signature_base64);
|
|
129
|
+
const bytes = new Uint8Array(decoded.length);
|
|
130
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
131
|
+
bytes[i] = decoded.charCodeAt(i);
|
|
119
132
|
}
|
|
120
|
-
const valid = await crypto.subtle.verify('HMAC', key,
|
|
133
|
+
const valid = await crypto.subtle.verify('HMAC', key, bytes, encoder.encode(value));
|
|
121
134
|
return valid ? value : false;
|
|
122
135
|
};
|
|
123
|
-
/**
|
|
124
|
-
* Validate and create a keyring in one step.
|
|
125
|
-
*
|
|
126
|
-
* Returns a discriminated union so callers handle exit/logging their own way
|
|
127
|
-
* (e.g. `Deno.exit(1)` vs `runtime.exit(1)`).
|
|
128
|
-
*
|
|
129
|
-
* @param env_value - the SECRET_FUZ_COOKIE_KEYS environment variable
|
|
130
|
-
* @returns `{ok: true, keyring}` or `{ok: false, errors}`
|
|
131
|
-
*/
|
|
132
|
-
export const create_validated_keyring = (env_value) => {
|
|
133
|
-
const errors = validate_keyring(env_value);
|
|
134
|
-
if (errors.length > 0) {
|
|
135
|
-
return { ok: false, errors };
|
|
136
|
-
}
|
|
137
|
-
const keyring = create_keyring(env_value);
|
|
138
|
-
if (!keyring) {
|
|
139
|
-
return { ok: false, errors: ['SECRET_FUZ_COOKIE_KEYS is required'] };
|
|
140
|
-
}
|
|
141
|
-
return { ok: true, keyring };
|
|
142
|
-
};
|
|
143
136
|
const parse_keys = (env_value) => {
|
|
144
137
|
if (!env_value)
|
|
145
138
|
return [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password_argon2.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/password_argon2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"password_argon2.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/password_argon2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AA2BtD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAEpE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC3B,UAAU,MAAM,EAChB,eAAe,MAAM,KACnB,OAAO,CAAC,OAAO,CAMjB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,OAAO,CAGpE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,gBAIlC,CAAC"}
|
|
@@ -9,19 +9,27 @@
|
|
|
9
9
|
* @module
|
|
10
10
|
*/
|
|
11
11
|
import { hash, verify } from '@node-rs/argon2';
|
|
12
|
+
/** @node-rs/argon2 `Algorithm.Argon2id` — const enum, cannot import with isolatedModules. */
|
|
13
|
+
const ARGON2ID = 2;
|
|
12
14
|
/**
|
|
13
15
|
* Argon2id options following OWASP recommendations.
|
|
14
16
|
*
|
|
15
17
|
* @see https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
|
|
16
18
|
*/
|
|
17
|
-
/** @node-rs/argon2 `Algorithm.Argon2id` — const enum, cannot import with isolatedModules. */
|
|
18
|
-
const ARGON2ID = 2;
|
|
19
19
|
const ARGON2_OPTIONS = {
|
|
20
20
|
algorithm: ARGON2ID,
|
|
21
21
|
memoryCost: 19456, // 19 MiB
|
|
22
22
|
timeCost: 2,
|
|
23
23
|
parallelism: 1
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* A fixed Argon2id PHC string with the production parameters, verified against
|
|
27
|
+
* on an account-lookup miss so that path does the same work as a real
|
|
28
|
+
* verification. No password matches it in practice (its digest is all zero
|
|
29
|
+
* bytes). Precomputed, so the first miss costs no hash either. Byte-identical
|
|
30
|
+
* with the Rust `DUMMY_HASH` (`fuz_auth`).
|
|
31
|
+
*/
|
|
32
|
+
const DUMMY_HASH = '$argon2id$v=19$m=19456,t=2,p=1$AAAAAAAAAAAAAAAAAAAAAA$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
|
25
33
|
/**
|
|
26
34
|
* Hash a password using Argon2id.
|
|
27
35
|
*
|
|
@@ -46,8 +54,6 @@ export const verify_password = async (password, password_hash) => {
|
|
|
46
54
|
return false;
|
|
47
55
|
}
|
|
48
56
|
};
|
|
49
|
-
/** Cached dummy hash for timing attack resistance. */
|
|
50
|
-
let dummy_hash = null;
|
|
51
57
|
/**
|
|
52
58
|
* Verify a password against a dummy hash for timing attack resistance.
|
|
53
59
|
*
|
|
@@ -58,10 +64,7 @@ let dummy_hash = null;
|
|
|
58
64
|
* @returns always `false`
|
|
59
65
|
*/
|
|
60
66
|
export const verify_dummy = async (password) => {
|
|
61
|
-
|
|
62
|
-
dummy_hash = await hash_password('dummy_password_for_timing_resistance');
|
|
63
|
-
}
|
|
64
|
-
await verify_password(password, dummy_hash);
|
|
67
|
+
await verify_password(password, DUMMY_HASH);
|
|
65
68
|
return false;
|
|
66
69
|
};
|
|
67
70
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session_cookie.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/session_cookie.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,QAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"session_cookie.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/session_cookie.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,QAAoB,CAAC;AAWjD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,oBAMpC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,cAAc,CAAC,SAAS;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/D,iFAAiF;IACjF,eAAe,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,MAAM,CAAC;IACjD,mEAAmE;IACnE,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,GAAG,IAAI,CAAC;CACvD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,SAAS;IACvC,4BAA4B;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,UAAU,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GAAU,SAAS,EAC5C,cAAc,MAAM,GAAG,SAAS,EAChC,SAAS,OAAO,EAChB,SAAS,cAAc,CAAC,SAAS,CAAC,EAClC,cAAc,MAAM,KAClB,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,CAiCrD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,GAAU,SAAS,EAC1D,SAAS,OAAO,EAChB,UAAU,SAAS,EACnB,SAAS,cAAc,CAAC,SAAS,CAAC,EAClC,cAAc,MAAM,KAClB,OAAO,CAAC,MAAM,CAMhB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,oBAAoB,CAAC,SAAS;IAC9C,oCAAoC;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,sCAAsC;IACtC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GAAI,aAAa,MAAM,KAAG,cAAc,CAAC,MAAM,CAK/E,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,MAAM,CAAwC,CAAC;AAE/F;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,sBAAsB,GAAU,SAAS,EACrD,cAAc,MAAM,GAAG,SAAS,EAChC,SAAS,OAAO,EAChB,SAAS,cAAc,CAAC,SAAS,CAAC,EAClC,cAAc,MAAM,KAClB,OAAO,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAgBzC,CAAC"}
|
|
@@ -22,6 +22,8 @@ export const SESSION_AGE_MAX = 60 * 60 * 24 * 30;
|
|
|
22
22
|
const VALUE_SEPARATOR = ':';
|
|
23
23
|
/** Strict integer matcher for the embedded `expires_at` field. */
|
|
24
24
|
const EXPIRES_AT_INTEGER_RE = /^\d+$/;
|
|
25
|
+
/** The largest `expires_at` the Rust spine's `u64` parse accepts. */
|
|
26
|
+
const EXPIRES_AT_MAX = 18446744073709551615n;
|
|
25
27
|
/**
|
|
26
28
|
* Default cookie options for session cookies.
|
|
27
29
|
*
|
|
@@ -69,9 +71,10 @@ export const parse_session = async (signed_value, keyring, options, now_seconds)
|
|
|
69
71
|
// theoretical, but stricter parsing closes the gap as defense-in-depth.
|
|
70
72
|
if (!EXPIRES_AT_INTEGER_RE.test(expires_at_str))
|
|
71
73
|
return null;
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
+
// refuse what the Rust spine's `u64` parse refuses, leading zeros allowed
|
|
75
|
+
if (BigInt(expires_at_str) > EXPIRES_AT_MAX)
|
|
74
76
|
return null;
|
|
77
|
+
const expires_at = parseInt(expires_at_str, 10);
|
|
75
78
|
// Check expiration
|
|
76
79
|
const now = now_seconds ?? Math.floor(Date.now() / 1000);
|
|
77
80
|
if (expires_at <= now)
|
package/dist/db/CLAUDE.md
CHANGED
|
@@ -187,32 +187,34 @@ DO NOTHING`), `_put_fact_refs`, `_get_fact` / `_get_fact_meta` / `_has_fact`
|
|
|
187
187
|
`query_fact_holder_unheld` (answered from holder rows alone).
|
|
188
188
|
- **`fact_store.ts`** — `PgFactStore`, implementing `HeldFactStore` (reads per
|
|
189
189
|
the `@fuzdev/fuz_util/fact_store.ts` `FactStore` contract; puts take
|
|
190
|
-
`HeldFactPutOptions`, whose required `holder` —
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
190
|
+
`HeldFactPutOptions`, whose required `holder` — an actor id, or `null` for a
|
|
191
|
+
system put — is recorded in `fact_holder` on every put, a dedup hit included,
|
|
192
|
+
in one transaction with the fact row and its refs): size-routed writes
|
|
193
|
+
(embedded ≤ `embedded_threshold` / disk CAS above it), refs exactly as each
|
|
194
|
+
put declares them (the bytes are never scanned), idempotent put,
|
|
195
|
+
verify-on-read for disk-backed content. With `disk_root` + `fs` (the
|
|
196
196
|
`runtime/*Deps`) configured, oversize `put` and the streaming `put_stream`
|
|
197
197
|
write to the `<shard>/<rest>` disk CAS and `get` reads from it; without them
|
|
198
198
|
an oversize write throws (`put_stream` needs `fs` for a body of any size).
|
|
199
199
|
The disk CAS is the only place `get` reads external bytes from; the store
|
|
200
200
|
makes no network request. A row whose `external_url` is not a
|
|
201
201
|
`file:<shard>/<rest>` URL (the store never writes one), and any external row
|
|
202
|
-
on a store with no disk CAS, reads as `null` with a warning;
|
|
203
|
-
|
|
202
|
+
on a store with no disk CAS, reads as `null` with a warning; one naming another
|
|
203
|
+
fact's file reads as `null` with an error. The serve route 404s both.
|
|
204
204
|
- **`file_fact_url.ts`** — the canonical `file:<shard>/<rest>` URL shape
|
|
205
205
|
(`FileFactUrl` brand, `mint_file_fact_url` / `parse_file_fact_url` /
|
|
206
206
|
`FILE_FACT_URL_PATTERN`) plus `fact_disk_path(hash) → {shard, rest}`, the
|
|
207
|
-
single source of truth for the on-disk layout
|
|
207
|
+
single source of truth for the on-disk layout, and `file_fact_url_addresses`,
|
|
208
|
+
the check that a URL names its own hash's file (twins the Rust `fuz_fact`).
|
|
208
209
|
- **`fact_disk_storage.ts`** — the filesystem CAS over `runtime/{FsStream,FsWrite,FsRemove,FsRead}Deps`
|
|
209
|
-
(not raw `node:fs`): `stream_fact_to_disk` (bounded-memory blake3
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
(not raw `node:fs`): `stream_fact_to_disk` (bounded-memory blake3 as it
|
|
211
|
+
streams, buffer→spill, fsync-then-atomic-rename — over a file already at the
|
|
212
|
+
CAS path, so a repeat put heals a corrupt one), `write_fact_bytes_to_disk`
|
|
213
|
+
(buffering twin), `read_fact_bytes_from_disk`, and `sweep_orphan_temps`
|
|
214
|
+
(reaps stale `.tmp` spills by mtime). The temp is `fsync`ed before the
|
|
215
|
+
rename publishes it (twins the Rust `fuz_fact` §fsync posture: data-sync
|
|
216
|
+
before rename, parent-dir fsync waived) — the serve path streams the file
|
|
217
|
+
without re-hashing, so write-time durability is the guard.
|
|
216
218
|
- **`fact_store_errors.ts`** — `FactPayloadTooLargeError` / `FactStorageFullError` (+
|
|
217
219
|
`is_enospc_error`) thrown by `put_stream`, for a consumer route's 413 / 507.
|
|
218
220
|
- The HTTP serving plumbing lives under `server/` (`serve_fact_route.ts`,
|
|
@@ -421,8 +421,9 @@ export interface CellListParams {
|
|
|
421
421
|
* uppercase-hex digest, or a `blake3:` string of any other length is not a
|
|
422
422
|
* ref. Refs are what fact serving admits a read through and what cell ref
|
|
423
423
|
* admission gates on a write, so the grammar is exact: a string either is an
|
|
424
|
-
* address or isn't one. Object keys are not walked — only values. (
|
|
425
|
-
* `fact_ref` edges
|
|
424
|
+
* address or isn't one. Object keys are not walked — only values. (A fact's
|
|
425
|
+
* own `fact_ref` edges are never derived from its bytes — they are the refs its
|
|
426
|
+
* put declares.)
|
|
426
427
|
*
|
|
427
428
|
* Returns `null` (rather than `[]`) when no refs are present — the column
|
|
428
429
|
* is nullable and the `idx_cell_refs` partial index is `WHERE refs IS NOT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/cell_queries.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cell_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/cell_queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAa/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,OAAO;IACvB,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,cAAc,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,2KAegD,CAAC;AAK1E;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,MAAM,KAAG,MAC2F,CAAC;AAEhJ;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,2DAKmC,CAAC;AAElE,iFAAiF;AACjF,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAE5E;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,SAAS,EACf,OAAO,oBAAoB,KACzB,OAAO,CAAC,OAAO,CAoBjB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GAC1B,MAAM,SAAS,EACf,IAAI,IAAI,EACR,UAAU;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,KACrC,OAAO,CAAC,OAAO,GAAG,IAAI,CAUxB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,SAAS,EACf,MAAM,MAAM,KACV,OAAO,CAAC,OAAO,GAAG,IAAI,CAQxB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,SAAS,EACf,KAAK,aAAa,CAAC,IAAI,CAAC,KACtB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAQxB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,GACrC,MAAM,SAAS,EACf,KAAK,aAAa,CAAC,IAAI,CAAC,KACtB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAQ5B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,SAAS,EACf,IAAI,IAAI,EACR,OAAO,eAAe,KACpB,OAAO,CAAC,OAAO,GAAG,IAAI,CA4BxB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,SAAS,EACf,IAAI,IAAI,EACR,UAAU;IAAE,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CAAE,KACpC,OAAO,CAAC,OAAO,CAWjB,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,yBAAyB,GACrC,MAAM,SAAS,EACf,IAAI,IAAI,EACR,YAAY,MAAM,EAClB,SAAS;IAAE,qBAAqB,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;CAAE,KACnE,OAAO,CAAC,OAAO,GAAG,IAAI,CAYxB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,GACnC,MAAM,SAAS,EACf,MAAM,MAAM,EACZ,UAAU,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,QAAQ,CAAC,KACjD,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CASvB,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B,GACtC,MAAM,SAAS,EACf,UAAU,IAAI,EACd,UAAU,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,QAAQ,CAAC,KACjD,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAQvB,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,eAAO,MAAM,eAAe,GAC3B,MAAM,SAAS,EACf,QAAQ,cAAc,KACpB,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CA4DxB,CAAC;AAiFF,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC9B,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,4EAA4E;IAC5E,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,0EAA0E;IAC1E,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iGAAiG;IACjG,OAAO,CAAC,EAAE,IAAI,CAAC;IACf;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAClB;;;;OAIG;IACH,eAAe,EAAE,IAAI,GAAG,IAAI,CAAC;IAC7B;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B;;;;;;;OAOG;IACH,uBAAuB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAChD;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACzD;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,yCAAyC;IACzC,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,CAAC;IACvC,sCAAsC;IACtC,eAAe,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACjC,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,IAAI,KAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,IAI/D,CAAC"}
|
package/dist/db/cell_queries.js
CHANGED
|
@@ -494,8 +494,9 @@ const build_shared_with_sql = (order_column, order_direction) => `${CALLER_ROLE_
|
|
|
494
494
|
* uppercase-hex digest, or a `blake3:` string of any other length is not a
|
|
495
495
|
* ref. Refs are what fact serving admits a read through and what cell ref
|
|
496
496
|
* admission gates on a write, so the grammar is exact: a string either is an
|
|
497
|
-
* address or isn't one. Object keys are not walked — only values. (
|
|
498
|
-
* `fact_ref` edges
|
|
497
|
+
* address or isn't one. Object keys are not walked — only values. (A fact's
|
|
498
|
+
* own `fact_ref` edges are never derived from its bytes — they are the refs its
|
|
499
|
+
* put declares.)
|
|
499
500
|
*
|
|
500
501
|
* Returns `null` (rather than `[]`) when no refs are present — the column
|
|
501
502
|
* is nullable and the `idx_cell_refs` partial index is `WHERE refs IS NOT
|
|
@@ -20,10 +20,12 @@
|
|
|
20
20
|
* re-hashing it (`server/serve_fact_route.ts`). This twins the Rust `fuz_fact`
|
|
21
21
|
* §fsync posture: data-sync before the rename; the parent-dir fsync stays
|
|
22
22
|
* deliberately waived (a lost dirent is regenerable under content addressing).
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* The temp is renamed over the final path even when a file is already there:
|
|
24
|
+
* the temp's bytes are the ones just hashed, so the rename is a no-op for a
|
|
25
|
+
* sound file and replaces a corrupt one (a torn write, bit rot) with bytes that
|
|
26
|
+
* match their name — a re-upload heals the CAS. `.tmp/` is a sibling of
|
|
27
|
+
* `<shard>/` under the same `facts_dir` so `rename` is always same-filesystem
|
|
28
|
+
* (no EXDEV).
|
|
27
29
|
*
|
|
28
30
|
* @module
|
|
29
31
|
*/
|
|
@@ -56,22 +58,20 @@ export type StreamPlacement = {
|
|
|
56
58
|
};
|
|
57
59
|
/**
|
|
58
60
|
* Outcome of streaming an upload to storage: the `blake3:`-prefixed fact hash,
|
|
59
|
-
* the
|
|
61
|
+
* the byte count, and where the bytes landed.
|
|
60
62
|
* `PgFactStore.put_stream` turns this into the `fact` row insert.
|
|
61
63
|
*/
|
|
62
64
|
export interface StreamFactToDiskResult {
|
|
63
65
|
hash: FactHash;
|
|
64
|
-
sha256: string;
|
|
65
66
|
size: number;
|
|
66
67
|
placement: StreamPlacement;
|
|
67
68
|
}
|
|
68
69
|
/**
|
|
69
|
-
* Stream `source` to storage with bounded memory: hash BLAKE3
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* never buffers in RAM.
|
|
70
|
+
* Stream `source` to storage with bounded memory: hash BLAKE3 incrementally,
|
|
71
|
+
* buffer in memory until the bytes cross `embedded_threshold`, then spill the
|
|
72
|
+
* buffer + remaining chunks through a temp file and atomically land it in the
|
|
73
|
+
* disk CAS. Peak heap is `O(chunk + embedded_threshold)`, never `O(artifact)`, so a
|
|
74
|
+
* multi-GB upload never buffers in RAM.
|
|
75
75
|
*
|
|
76
76
|
* - **Embedded vs disk.** A body `<= embedded_threshold` stays in memory and is
|
|
77
77
|
* returned as `{kind: 'embedded'}` for the PG `bytes` column. Above it (with a
|
|
@@ -87,17 +87,17 @@ export interface StreamFactToDiskResult {
|
|
|
87
87
|
*
|
|
88
88
|
* @mutates `facts_dir` filesystem
|
|
89
89
|
*/
|
|
90
|
-
export declare const stream_fact_to_disk: (deps: Pick<FactDiskStorageDeps, "mkdir" | "rename" | "remove" | "write_file_stream" | "fsync"
|
|
90
|
+
export declare const stream_fact_to_disk: (deps: Pick<FactDiskStorageDeps, "mkdir" | "rename" | "remove" | "write_file_stream" | "fsync">, facts_dir: string | undefined, source: ReadableStream<Uint8Array>, max_bytes: number, embedded_threshold: number) => Promise<StreamFactToDiskResult>;
|
|
91
91
|
/**
|
|
92
92
|
* Write fully-buffered `bytes` for `hash` to the canonical
|
|
93
93
|
* `<facts_dir>/<shard>/<rest>` path, then publish via `commit_temp_to_cas`
|
|
94
|
-
* (fsync'd temp + atomic rename
|
|
94
|
+
* (fsync'd temp + atomic rename). The buffering twin of
|
|
95
95
|
* `stream_fact_to_disk`, used by `PgFactStore.put` for oversize sync bytes.
|
|
96
96
|
* Returns the `file:` `external_url` for the `fact` row.
|
|
97
97
|
*
|
|
98
98
|
* @mutates `facts_dir` filesystem
|
|
99
99
|
*/
|
|
100
|
-
export declare const write_fact_bytes_to_disk: (deps: Pick<FactDiskStorageDeps, "mkdir" | "rename" | "remove" | "write_file" | "fsync"
|
|
100
|
+
export declare const write_fact_bytes_to_disk: (deps: Pick<FactDiskStorageDeps, "mkdir" | "rename" | "remove" | "write_file" | "fsync">, facts_dir: string, hash: FactHash, bytes: Uint8Array) => Promise<FileFactUrl>;
|
|
101
101
|
/**
|
|
102
102
|
* Read a disk-backed fact's bytes from the `<facts_dir>/<shard>/<rest>` layout
|
|
103
103
|
* the writers above produce, addressed by the row's `file:<shard>/<rest>`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fact_disk_storage.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/fact_disk_storage.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fact_disk_storage.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/fact_disk_storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAQH,OAAO,EAAoB,KAAK,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACnF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9F,OAAO,EAIN,KAAK,WAAW,EAChB,MAAM,oBAAoB,CAAC;AAO5B,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,SAAS,CAAC;AAEvC,8EAA8E;AAC9E,eAAO,MAAM,0BAA0B,QAAiB,CAAC;AAEzD;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC,GACnF,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC,GAC9D,IAAI,CAAC,YAAY,EAAE,mBAAmB,CAAC,GACvC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAC1B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,WAAW,CAAA;CAAE,CAAC;AAEvF;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,eAAe,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,mBAAmB,GAAG,OAAO,CAAC,EAC9F,WAAW,MAAM,GAAG,SAAS,EAC7B,QAAQ,cAAc,CAAC,UAAU,CAAC,EAClC,WAAW,MAAM,EACjB,oBAAoB,MAAM,KACxB,OAAO,CAAC,sBAAsB,CA0GhC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,GACpC,MAAM,IAAI,CAAC,mBAAmB,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC,EACvF,WAAW,MAAM,EACjB,MAAM,QAAQ,EACd,OAAO,UAAU,KACf,OAAO,CAAC,WAAW,CAgBrB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,GACrC,MAAM,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,EAC5C,WAAW,MAAM,EACjB,KAAK,MAAM,KACT,OAAO,CAAC,UAAU,CAIpB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAC9B,MAAM,IAAI,CAAC,mBAAmB,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC,EAC9D,WAAW,MAAM,EACjB,UAAU;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KAC3D,OAAO,CAAC,MAAM,CA0BhB,CAAC"}
|