life-as-api 0.2.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/LICENSE +21 -0
- package/README.md +377 -0
- package/dist/agent/finance-agent.d.ts +44 -0
- package/dist/agent/finance-agent.js +75 -0
- package/dist/agent/finance-agent.js.map +1 -0
- package/dist/agent/legal-agent.d.ts +44 -0
- package/dist/agent/legal-agent.js +76 -0
- package/dist/agent/legal-agent.js.map +1 -0
- package/dist/agent/medical-agent.d.ts +44 -0
- package/dist/agent/medical-agent.js +75 -0
- package/dist/agent/medical-agent.js.map +1 -0
- package/dist/agent/trusted-agent-registry.d.ts +53 -0
- package/dist/agent/trusted-agent-registry.js +57 -0
- package/dist/agent/trusted-agent-registry.js.map +1 -0
- package/dist/audit/audit-chain-verifier.d.ts +10 -0
- package/dist/audit/audit-chain-verifier.js +67 -0
- package/dist/audit/audit-chain-verifier.js.map +1 -0
- package/dist/audit/audit-log.d.ts +48 -0
- package/dist/audit/audit-log.js +74 -0
- package/dist/audit/audit-log.js.map +1 -0
- package/dist/audit/sqlite-audit-log.d.ts +29 -0
- package/dist/audit/sqlite-audit-log.js +142 -0
- package/dist/audit/sqlite-audit-log.js.map +1 -0
- package/dist/auth/access-context-issuer.d.ts +18 -0
- package/dist/auth/access-context-issuer.js +88 -0
- package/dist/auth/access-context-issuer.js.map +1 -0
- package/dist/auth/assert-authorized-for-subject.d.ts +2 -0
- package/dist/auth/assert-authorized-for-subject.js +20 -0
- package/dist/auth/assert-authorized-for-subject.js.map +1 -0
- package/dist/auth/backend-context-minting-boundary.d.ts +23 -0
- package/dist/auth/backend-context-minting-boundary.js +281 -0
- package/dist/auth/backend-context-minting-boundary.js.map +1 -0
- package/dist/auth/default-authorization-policy.d.ts +7 -0
- package/dist/auth/default-authorization-policy.js +64 -0
- package/dist/auth/default-authorization-policy.js.map +1 -0
- package/dist/auth/fake-auth-adapter.d.ts +7 -0
- package/dist/auth/fake-auth-adapter.js +27 -0
- package/dist/auth/fake-auth-adapter.js.map +1 -0
- package/dist/auth/http-client.d.ts +12 -0
- package/dist/auth/http-client.js +7 -0
- package/dist/auth/http-client.js.map +1 -0
- package/dist/auth/in-memory-grant-resolver.d.ts +21 -0
- package/dist/auth/in-memory-grant-resolver.js +73 -0
- package/dist/auth/in-memory-grant-resolver.js.map +1 -0
- package/dist/auth/in-memory-tenant-boundary.d.ts +16 -0
- package/dist/auth/in-memory-tenant-boundary.js +37 -0
- package/dist/auth/in-memory-tenant-boundary.js.map +1 -0
- package/dist/auth/jwks-key-ring-auth-adapter.d.ts +38 -0
- package/dist/auth/jwks-key-ring-auth-adapter.js +123 -0
- package/dist/auth/jwks-key-ring-auth-adapter.js.map +1 -0
- package/dist/auth/jwks-key-ring.d.ts +25 -0
- package/dist/auth/jwks-key-ring.js +111 -0
- package/dist/auth/jwks-key-ring.js.map +1 -0
- package/dist/auth/jwt-auth-adapter.d.ts +15 -0
- package/dist/auth/jwt-auth-adapter.js +59 -0
- package/dist/auth/jwt-auth-adapter.js.map +1 -0
- package/dist/auth/jwt-core.d.ts +32 -0
- package/dist/auth/jwt-core.js +226 -0
- package/dist/auth/jwt-core.js.map +1 -0
- package/dist/auth/jwt-key-ring-auth-adapter.d.ts +16 -0
- package/dist/auth/jwt-key-ring-auth-adapter.js +58 -0
- package/dist/auth/jwt-key-ring-auth-adapter.js.map +1 -0
- package/dist/auth/oidc-discovery.d.ts +15 -0
- package/dist/auth/oidc-discovery.js +46 -0
- package/dist/auth/oidc-discovery.js.map +1 -0
- package/dist/auth/production-scoped-life-api.d.ts +58 -0
- package/dist/auth/production-scoped-life-api.js +802 -0
- package/dist/auth/production-scoped-life-api.js.map +1 -0
- package/dist/auth/proposal-scope-inspector.d.ts +3 -0
- package/dist/auth/proposal-scope-inspector.js +42 -0
- package/dist/auth/proposal-scope-inspector.js.map +1 -0
- package/dist/auth/proposal-scoped-life-api.d.ts +21 -0
- package/dist/auth/proposal-scoped-life-api.js +168 -0
- package/dist/auth/proposal-scoped-life-api.js.map +1 -0
- package/dist/auth/rate-limited-context-minting-boundary.d.ts +27 -0
- package/dist/auth/rate-limited-context-minting-boundary.js +77 -0
- package/dist/auth/rate-limited-context-minting-boundary.js.map +1 -0
- package/dist/auth/revocation-aware-auth-adapter.d.ts +21 -0
- package/dist/auth/revocation-aware-auth-adapter.js +88 -0
- package/dist/auth/revocation-aware-auth-adapter.js.map +1 -0
- package/dist/auth/sqlite-grant-resolver.d.ts +8 -0
- package/dist/auth/sqlite-grant-resolver.js +78 -0
- package/dist/auth/sqlite-grant-resolver.js.map +1 -0
- package/dist/auth/sqlite-tenant-boundary.d.ts +7 -0
- package/dist/auth/sqlite-tenant-boundary.js +41 -0
- package/dist/auth/sqlite-tenant-boundary.js.map +1 -0
- package/dist/auth/static-jwt-key-ring.d.ts +13 -0
- package/dist/auth/static-jwt-key-ring.js +73 -0
- package/dist/auth/static-jwt-key-ring.js.map +1 -0
- package/dist/auth/subject-scoped-life-api.d.ts +14 -0
- package/dist/auth/subject-scoped-life-api.js +51 -0
- package/dist/auth/subject-scoped-life-api.js.map +1 -0
- package/dist/auth/test-context-minting-boundary.d.ts +13 -0
- package/dist/auth/test-context-minting-boundary.js +74 -0
- package/dist/auth/test-context-minting-boundary.js.map +1 -0
- package/dist/auth/types.d.ts +77 -0
- package/dist/auth/types.js +16 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/compliance/subject-data-report.d.ts +43 -0
- package/dist/compliance/subject-data-report.js +155 -0
- package/dist/compliance/subject-data-report.js.map +1 -0
- package/dist/consent/consent-guard.d.ts +4 -0
- package/dist/consent/consent-guard.js +37 -0
- package/dist/consent/consent-guard.js.map +1 -0
- package/dist/consent/grant-registry.d.ts +7 -0
- package/dist/consent/grant-registry.js +13 -0
- package/dist/consent/grant-registry.js.map +1 -0
- package/dist/consent/intersect-selector.d.ts +3 -0
- package/dist/consent/intersect-selector.js +66 -0
- package/dist/consent/intersect-selector.js.map +1 -0
- package/dist/contract/diagnostics.d.ts +32 -0
- package/dist/contract/diagnostics.js +112 -0
- package/dist/contract/diagnostics.js.map +1 -0
- package/dist/contract/project-contracts.d.ts +5 -0
- package/dist/contract/project-contracts.js +159 -0
- package/dist/contract/project-contracts.js.map +1 -0
- package/dist/contract/types.d.ts +32 -0
- package/dist/contract/types.js +5 -0
- package/dist/contract/types.js.map +1 -0
- package/dist/crypto/aes-gcm.d.ts +11 -0
- package/dist/crypto/aes-gcm.js +78 -0
- package/dist/crypto/aes-gcm.js.map +1 -0
- package/dist/crypto/claim-serializer.d.ts +26 -0
- package/dist/crypto/claim-serializer.js +59 -0
- package/dist/crypto/claim-serializer.js.map +1 -0
- package/dist/crypto/sha256.d.ts +12 -0
- package/dist/crypto/sha256.js +40 -0
- package/dist/crypto/sha256.js.map +1 -0
- package/dist/crypto/static-key.d.ts +11 -0
- package/dist/crypto/static-key.js +60 -0
- package/dist/crypto/static-key.js.map +1 -0
- package/dist/crypto/types.d.ts +20 -0
- package/dist/crypto/types.js +8 -0
- package/dist/crypto/types.js.map +1 -0
- package/dist/datasource/trusted-data-source-registry.d.ts +51 -0
- package/dist/datasource/trusted-data-source-registry.js +57 -0
- package/dist/datasource/trusted-data-source-registry.js.map +1 -0
- package/dist/erasure/tombstone.d.ts +13 -0
- package/dist/erasure/tombstone.js +20 -0
- package/dist/erasure/tombstone.js.map +1 -0
- package/dist/evidence/evidence-backed-claim-creator.d.ts +48 -0
- package/dist/evidence/evidence-backed-claim-creator.js +107 -0
- package/dist/evidence/evidence-backed-claim-creator.js.map +1 -0
- package/dist/evidence/in-memory-raw-document-store.d.ts +26 -0
- package/dist/evidence/in-memory-raw-document-store.js +84 -0
- package/dist/evidence/in-memory-raw-document-store.js.map +1 -0
- package/dist/evidence/raw-document-store.d.ts +12 -0
- package/dist/evidence/raw-document-store.js +8 -0
- package/dist/evidence/raw-document-store.js.map +1 -0
- package/dist/evidence/source-evidence-validator.d.ts +4 -0
- package/dist/evidence/source-evidence-validator.js +14 -0
- package/dist/evidence/source-evidence-validator.js.map +1 -0
- package/dist/evidence/sqlite-raw-document-store.d.ts +19 -0
- package/dist/evidence/sqlite-raw-document-store.js +122 -0
- package/dist/evidence/sqlite-raw-document-store.js.map +1 -0
- package/dist/guardian/guardian-registry.d.ts +96 -0
- package/dist/guardian/guardian-registry.js +95 -0
- package/dist/guardian/guardian-registry.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/observability/health.d.ts +12 -0
- package/dist/observability/health.js +16 -0
- package/dist/observability/health.js.map +1 -0
- package/dist/observability/logger.d.ts +21 -0
- package/dist/observability/logger.js +40 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +15 -0
- package/dist/observability/metrics.js +52 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/persistence/backup.d.ts +24 -0
- package/dist/persistence/backup.js +251 -0
- package/dist/persistence/backup.js.map +1 -0
- package/dist/persistence/decryptability-scan.d.ts +10 -0
- package/dist/persistence/decryptability-scan.js +144 -0
- package/dist/persistence/decryptability-scan.js.map +1 -0
- package/dist/persistence/in-memory-unit-of-work.d.ts +11 -0
- package/dist/persistence/in-memory-unit-of-work.js +32 -0
- package/dist/persistence/in-memory-unit-of-work.js.map +1 -0
- package/dist/persistence/key-availability.d.ts +9 -0
- package/dist/persistence/key-availability.js +125 -0
- package/dist/persistence/key-availability.js.map +1 -0
- package/dist/persistence/sqlite/migrations.d.ts +9 -0
- package/dist/persistence/sqlite/migrations.js +535 -0
- package/dist/persistence/sqlite/migrations.js.map +1 -0
- package/dist/persistence/sqlite/schema.d.ts +10 -0
- package/dist/persistence/sqlite/schema.js +101 -0
- package/dist/persistence/sqlite/schema.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-fact-store.d.ts +24 -0
- package/dist/persistence/sqlite/sqlite-fact-store.js +207 -0
- package/dist/persistence/sqlite/sqlite-fact-store.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-source-registry.d.ts +17 -0
- package/dist/persistence/sqlite/sqlite-source-registry.js +132 -0
- package/dist/persistence/sqlite/sqlite-source-registry.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.d.ts +8 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.js +41 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.js.map +1 -0
- package/dist/persistence/sqlite/types.d.ts +24 -0
- package/dist/persistence/sqlite/types.js +28 -0
- package/dist/persistence/sqlite/types.js.map +1 -0
- package/dist/persistence/unit-of-work.d.ts +6 -0
- package/dist/persistence/unit-of-work.js +15 -0
- package/dist/persistence/unit-of-work.js.map +1 -0
- package/dist/proposal/accepted-claim-appender.d.ts +7 -0
- package/dist/proposal/accepted-claim-appender.js +16 -0
- package/dist/proposal/accepted-claim-appender.js.map +1 -0
- package/dist/proposal/in-memory-proposal-queue.d.ts +21 -0
- package/dist/proposal/in-memory-proposal-queue.js +218 -0
- package/dist/proposal/in-memory-proposal-queue.js.map +1 -0
- package/dist/proposal/policy-aware-proposal-queue.d.ts +23 -0
- package/dist/proposal/policy-aware-proposal-queue.js +162 -0
- package/dist/proposal/policy-aware-proposal-queue.js.map +1 -0
- package/dist/proposal/proposal-policy.d.ts +37 -0
- package/dist/proposal/proposal-policy.js +72 -0
- package/dist/proposal/proposal-policy.js.map +1 -0
- package/dist/proposal/proposal-queue.d.ts +13 -0
- package/dist/proposal/proposal-queue.js +15 -0
- package/dist/proposal/proposal-queue.js.map +1 -0
- package/dist/proposal/source-aware-claim-appender.d.ts +13 -0
- package/dist/proposal/source-aware-claim-appender.js +47 -0
- package/dist/proposal/source-aware-claim-appender.js.map +1 -0
- package/dist/proposal/sqlite-proposal-queue.d.ts +26 -0
- package/dist/proposal/sqlite-proposal-queue.js +282 -0
- package/dist/proposal/sqlite-proposal-queue.js.map +1 -0
- package/dist/resolution/resolve-claims.d.ts +4 -0
- package/dist/resolution/resolve-claims.js +101 -0
- package/dist/resolution/resolve-claims.js.map +1 -0
- package/dist/resolution/trust-profile.d.ts +12 -0
- package/dist/resolution/trust-profile.js +23 -0
- package/dist/resolution/trust-profile.js.map +1 -0
- package/dist/resolution/types.d.ts +15 -0
- package/dist/resolution/types.js +8 -0
- package/dist/resolution/types.js.map +1 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.d.ts +23 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.js +240 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.js.map +1 -0
- package/dist/sdk/create-life-api.d.ts +55 -0
- package/dist/sdk/create-life-api.js +251 -0
- package/dist/sdk/create-life-api.js.map +1 -0
- package/dist/sdk/create-sqlite-life-api.d.ts +33 -0
- package/dist/sdk/create-sqlite-life-api.js +654 -0
- package/dist/sdk/create-sqlite-life-api.js.map +1 -0
- package/dist/sdk/life-api.d.ts +27 -0
- package/dist/sdk/life-api.js +17 -0
- package/dist/sdk/life-api.js.map +1 -0
- package/dist/sdk/validation.d.ts +8 -0
- package/dist/sdk/validation.js +216 -0
- package/dist/sdk/validation.js.map +1 -0
- package/dist/source/in-memory-source-registry.d.ts +15 -0
- package/dist/source/in-memory-source-registry.js +104 -0
- package/dist/source/in-memory-source-registry.js.map +1 -0
- package/dist/source/source-aware-fact-store.d.ts +19 -0
- package/dist/source/source-aware-fact-store.js +40 -0
- package/dist/source/source-aware-fact-store.js.map +1 -0
- package/dist/source/source-kind-predicate-policy.d.ts +4 -0
- package/dist/source/source-kind-predicate-policy.js +62 -0
- package/dist/source/source-kind-predicate-policy.js.map +1 -0
- package/dist/source/source-registry.d.ts +11 -0
- package/dist/source/source-registry.js +12 -0
- package/dist/source/source-registry.js.map +1 -0
- package/dist/store/in-memory-fact-store.d.ts +25 -0
- package/dist/store/in-memory-fact-store.js +192 -0
- package/dist/store/in-memory-fact-store.js.map +1 -0
- package/dist/surface/context-query.d.ts +21 -0
- package/dist/surface/context-query.js +113 -0
- package/dist/surface/context-query.js.map +1 -0
- package/dist/surface/evidence-backed-context-query.d.ts +62 -0
- package/dist/surface/evidence-backed-context-query.js +240 -0
- package/dist/surface/evidence-backed-context-query.js.map +1 -0
- package/dist/types/access-context.d.ts +25 -0
- package/dist/types/access-context.js +6 -0
- package/dist/types/access-context.js.map +1 -0
- package/dist/types/claim.d.ts +48 -0
- package/dist/types/claim.js +5 -0
- package/dist/types/claim.js.map +1 -0
- package/dist/types/consent.d.ts +41 -0
- package/dist/types/consent.js +3 -0
- package/dist/types/consent.js.map +1 -0
- package/dist/types/crypto-boundary.d.ts +12 -0
- package/dist/types/crypto-boundary.js +15 -0
- package/dist/types/crypto-boundary.js.map +1 -0
- package/dist/types/evidence.d.ts +31 -0
- package/dist/types/evidence.js +8 -0
- package/dist/types/evidence.js.map +1 -0
- package/dist/types/fact-store.d.ts +24 -0
- package/dist/types/fact-store.js +12 -0
- package/dist/types/fact-store.js.map +1 -0
- package/dist/types/ids.d.ts +36 -0
- package/dist/types/ids.js +11 -0
- package/dist/types/ids.js.map +1 -0
- package/dist/types/proposal.d.ts +38 -0
- package/dist/types/proposal.js +7 -0
- package/dist/types/proposal.js.map +1 -0
- package/dist/types/source.d.ts +33 -0
- package/dist/types/source.js +6 -0
- package/dist/types/source.js.map +1 -0
- package/dist/types/trust.d.ts +24 -0
- package/dist/types/trust.js +5 -0
- package/dist/types/trust.js.map +1 -0
- package/dist/utilities/deep-freeze.d.ts +1 -0
- package/dist/utilities/deep-freeze.js +17 -0
- package/dist/utilities/deep-freeze.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alper
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# life-as-api
|
|
2
|
+
|
|
3
|
+
A personal context layer: a typed, encrypted, consent-gated claim log that lets authorised
|
|
4
|
+
agents query structured facts about a person's life without exposing raw documents, crypto
|
|
5
|
+
primitives, or the underlying storage engine.
|
|
6
|
+
|
|
7
|
+
> **v0.2.0** · 3908 tests · typecheck clean
|
|
8
|
+
|
|
9
|
+
The production auth boundary is complete for the documented MVP boundary: a scoped 8-method
|
|
10
|
+
facade (`ProductionScopedLifeApi`) enforces subject and proposal scope on every call, backed by
|
|
11
|
+
a SQLite persistence layer with an AES-256-GCM encryption boundary. Security-relevant decisions
|
|
12
|
+
are recorded through an internal audit abstraction with a local hash chain over `audit_events`
|
|
13
|
+
(tamper-evident locally — not court-grade, not external notarization). Operator tooling covers
|
|
14
|
+
backup/restore, key-availability validation, and full decryptability scanning (D2–D4). On top of
|
|
15
|
+
that closure, the platform layer (Platform-01 through 05) adds trusted-agent/data-source
|
|
16
|
+
registries, guardianship, purpose enforcement, a GDPR Art. 15/20 subject data report, and three
|
|
17
|
+
certified first-party agents — all optional, additive, and fail-closed. See
|
|
18
|
+
[docs/specs/post-auth-product-boundary-spec.md](docs/specs/post-auth-product-boundary-spec.md)
|
|
19
|
+
and [CHANGELOG.md](CHANGELOG.md) for exact claims and non-claims release by release.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Concept
|
|
24
|
+
|
|
25
|
+
> "Jarvis, what are my active subscriptions?"
|
|
26
|
+
|
|
27
|
+
The system stores *claims* (immutable, encrypted, provenance-linked facts) and lets agents
|
|
28
|
+
*query* them through a consent gate — seeing only what they've been explicitly granted.
|
|
29
|
+
Nothing is ever mutated in-place. Everything is append-only and audited.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Production factory (MVP-stable)
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { createSQLiteLifeApiForProduction } from "life-as-api";
|
|
37
|
+
import type {
|
|
38
|
+
ProductionApiBundle,
|
|
39
|
+
ProductionScopedLifeApi,
|
|
40
|
+
ProductionFactoryConfig,
|
|
41
|
+
MintedContext,
|
|
42
|
+
} from "life-as-api";
|
|
43
|
+
|
|
44
|
+
// 1. Configure and build the production bundle
|
|
45
|
+
const bundle: ProductionApiBundle = await createSQLiteLifeApiForProduction({
|
|
46
|
+
db: yourMigratedSqliteDatabase,
|
|
47
|
+
|
|
48
|
+
// Encryption source — exactly one of encryptionKey or keyProvider must be provided.
|
|
49
|
+
// Option A: raw key bytes (dev/staging) — factory creates StaticKeyProvider internally.
|
|
50
|
+
encryptionKey: { keyId: "key-v1", rawBytes: yourEncryptionKeyBytes },
|
|
51
|
+
// Option B: external KeyProvider (production) — plug in a KMS-backed adapter.
|
|
52
|
+
// keyProvider: yourKmsKeyProvider, // implements KeyProvider; encryptionKey must be absent
|
|
53
|
+
|
|
54
|
+
authAdapter: yourAuthAdapter, // implements AuthAdapter
|
|
55
|
+
rawDocumentStore: yourDurableDocStore, // implements FactoryCompatibleRawDocumentStore
|
|
56
|
+
auditLog: yourDurableAuditLog, // implements FactoryCompatibleAuditLog
|
|
57
|
+
// ... see ProductionFactoryConfig for full field list
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// 2. Mint a trusted context from bearer credentials
|
|
61
|
+
const minted: MintedContext = await bundle.auth.mint(bearerCredential, targetPersonId, "owner");
|
|
62
|
+
|
|
63
|
+
// 3. Get a subject-scoped production API
|
|
64
|
+
const api: ProductionScopedLifeApi = bundle.createScopedApi(minted);
|
|
65
|
+
|
|
66
|
+
// 4. Use the 8 scope-enforced facade methods
|
|
67
|
+
await api.queryContracts(personId, queryInput);
|
|
68
|
+
await api.requestErasure(personId);
|
|
69
|
+
await api.getErasureStatus(personId);
|
|
70
|
+
await api.acceptProposal(proposalId, acceptOptions);
|
|
71
|
+
await api.rejectProposal(proposalId, { reason: "Not accurate" });
|
|
72
|
+
await api.createProposal(proposalInput);
|
|
73
|
+
await api.getProposal(proposalId); // returns undefined if not found or cross-subject
|
|
74
|
+
await api.listProposals({ status: "pending" }); // scoped to bound person only
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
All 8 methods enforce subject/proposal scope before delegation. Agents are bound to the
|
|
78
|
+
`personId` from their grant (`authorizedPersonId`). Broad grants (no `personId`) are denied
|
|
79
|
+
at context-minting time, not at query time.
|
|
80
|
+
|
|
81
|
+
**Proposal read semantics:** `getProposal` returns `undefined` for missing, cross-subject,
|
|
82
|
+
unknown-subject (empty `candidateClaims`), and multi-subject proposals — all four cases are
|
|
83
|
+
indistinguishable. `listProposals` returns only proposals whose unique candidate subject
|
|
84
|
+
matches the bound person; cross/unknown/multi-subject proposals are silently omitted.
|
|
85
|
+
`listProposals` does not expose arbitrary `subject` or `underGrant` filters.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// 5. Optional: run the D2b local health diagnostic (no user/agent context required)
|
|
89
|
+
const health = await bundle.healthCheck();
|
|
90
|
+
// health.status: "ok" | "degraded" | "failed"
|
|
91
|
+
// health.checks: readonly HealthCheckItem[] — seven named checks
|
|
92
|
+
// health.checkedAt: ISO timestamp
|
|
93
|
+
// { status: "ok" } means all seven local checks passed.
|
|
94
|
+
// It does NOT mean operational production readiness.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**This does not claim full OIDC/OAuth authorization flow, session revocation, rate limiting,
|
|
98
|
+
external tamper-evident audit, GDPR/legal compliance, multi-process consistency, or operational
|
|
99
|
+
production readiness.** RS256/JWKS adapter (`JwksKeyRingAuthAdapter`) is implemented — not exported
|
|
100
|
+
from package root; host-supplied. ES256, full OIDC server, OAuth flow, session revocation remain
|
|
101
|
+
unclaimed. See §3 below.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Platform layer (0.2.0)
|
|
106
|
+
|
|
107
|
+
Five optional, additive slices sit on top of the production auth closure. Every one of them is
|
|
108
|
+
fail-closed and backward-compatible: if you don't configure it, behavior is byte-identical to
|
|
109
|
+
0.1.0.
|
|
110
|
+
|
|
111
|
+
### Platform-01 — Trusted Agent Registry + Purpose Binding
|
|
112
|
+
|
|
113
|
+
When a `TrustedAgentRegistry` is configured, no `AgentConsentContext` is minted without
|
|
114
|
+
`isAgentTrusted(agentId, purpose)` returning `true` — the check fires before `issuer.mintAgent`,
|
|
115
|
+
before any context that could read data exists. Registry exceptions, unknown agents, or expired
|
|
116
|
+
certifications deny the mint; the registry never fails open. Leaving `trustedAgentRegistry`
|
|
117
|
+
unset leaves the agent-mint path unchanged.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const bundle = await createSQLiteLifeApiForProduction({
|
|
121
|
+
// ...required fields
|
|
122
|
+
trustedAgentRegistry: new InMemoryTrustedAgentRegistry([medicalAgentRegistryEntry(validUntilMs)]),
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`GrantDescriptor.purpose` remains declarative — the library does not enforce it on the plain
|
|
127
|
+
access-context path; enforcement there is agent/host responsibility (see Platform-04 for the
|
|
128
|
+
minting-time enforcement path).
|
|
129
|
+
|
|
130
|
+
### Platform-02 — Trusted Data Source Registry + Proposal Policy
|
|
131
|
+
|
|
132
|
+
`TrustedDataSourceRegistry` and `ProposalPolicy` (`DefaultProposalPolicy`,
|
|
133
|
+
`RegistryBackedProposalPolicy`) decide whether an incoming proposal is auto-accepted,
|
|
134
|
+
auto-rejected, or left for manual review. Unknown source, expired certification, unrecognised
|
|
135
|
+
scope, or any exception during evaluation resolves to `"manual"` — the fail-safe default,
|
|
136
|
+
identical to pre-Platform-02 behavior. An explicit `config.proposalPolicy` always wins over the
|
|
137
|
+
`trustedDataSourceRegistry` convenience wiring when both are supplied.
|
|
138
|
+
|
|
139
|
+
### Platform-03 — Guardianship / Bevollmächtigung
|
|
140
|
+
|
|
141
|
+
`GuardianRegistry` plus `mintGuardianContext()` let an authorised guardian mint a scoped
|
|
142
|
+
`MintedContext` for a ward. The registry check (`getRelationship` + `isAuthorized`) fires before
|
|
143
|
+
`issuer.mintOwner` — no context exists if the check fails. The registry check is fail-closed on
|
|
144
|
+
an unknown guardian/ward pair, an expired relationship, or a scope that isn't an exact match.
|
|
145
|
+
`requestErasure` and `getErasureStatus` are always denied for guardian contexts, regardless of
|
|
146
|
+
granted scopes — erasure is personal and not delegable. Without a configured `guardianRegistry`,
|
|
147
|
+
`mintGuardianContext` throws `GUARDIAN_REGISTRY_NOT_CONFIGURED_001`; all other behavior is
|
|
148
|
+
unaffected.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const minted = await bundle.auth.mintGuardianContext(bearerCredential, wardPersonId, "manage_finances");
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Platform-04 — Purpose-Enforcement + Subject Data Report (GDPR Art. 15/20)
|
|
155
|
+
|
|
156
|
+
When a caller passes `MintOptions.declaredPurpose` **and** the resolved grant declares its own
|
|
157
|
+
`purpose` **and** the two differ, the mint is denied with the same opaque error used for
|
|
158
|
+
"grant not found" — the two denial reasons are indistinguishable to the caller. If either side
|
|
159
|
+
omits a purpose, there is no enforcement and behavior matches pre-Platform-04. On a successful
|
|
160
|
+
mint with a declared purpose, `MintedContext.declaredPurpose` carries the value.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
const minted = await bundle.auth.mint(bearerCredential, personId, "agent", {
|
|
164
|
+
declaredPurpose: "diagnosis",
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`generateSubjectDataReport(personId)` produces a complete structured account of everything held
|
|
169
|
+
about a person — grants across all statuses, proposals (metadata only, never the encrypted
|
|
170
|
+
payload), and audit events (via grant join plus guardian ward events) — together with a SHA-256
|
|
171
|
+
`dataIntegrityHash` over canonical JSON, making the report tamper-evident. The function does not
|
|
172
|
+
itself enforce caller identity; restricting it to the subject (owner context or an authorised
|
|
173
|
+
guardian) is host responsibility.
|
|
174
|
+
|
|
175
|
+
### Platform-05 — Certified First-Party Agents
|
|
176
|
+
|
|
177
|
+
`MedicalAgent`, `FinanceAgent`, and `LegalAgent` are read-only, purpose-bound reference agents,
|
|
178
|
+
each with a matching `*AgentRegistryEntry()` factory that builds a `TrustedAgentRegistryEntry`
|
|
179
|
+
certified by `"life-as-api-foundation"` for direct registration with a `TrustedAgentRegistry`.
|
|
180
|
+
Each agent's constructor accepts only a query function — there is no propose/write capability
|
|
181
|
+
anywhere on these classes. `run()` fail-closed throws a `*_SCOPE_DENIED_001` coded error for any
|
|
182
|
+
`declaredPurpose` outside the agent's own allowed set, including an absent purpose. An optional
|
|
183
|
+
`onAudit` hook fires on every `run()` call; persisting that audit trail durably remains a host
|
|
184
|
+
responsibility.
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
const medical = new MedicalAgent({ query: bundle.createScopedApi(minted).queryContracts, clock });
|
|
188
|
+
await medical.run(minted, queryInput); // only proceeds if minted.declaredPurpose is
|
|
189
|
+
// "diagnosis" | "treatment" | "emergency"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`PurposeTag` gained 11 additive values for these agents (`diagnosis`, `treatment`, `emergency`,
|
|
193
|
+
`tax`, `credit_check`, `insurance_claim`, `account_overview`, `notary`, `contract_review`,
|
|
194
|
+
`evidence_preservation`, `court_filing`) — union-widening only, fully backward-compatible.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Test/dev quick start
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import {
|
|
202
|
+
createInMemoryLifeApiForTest,
|
|
203
|
+
asPersonId, asSourceId, asContractId, asGrantId, asISOTime,
|
|
204
|
+
} from "life-as-api";
|
|
205
|
+
import type { OwnerContext, AgentConsentContext } from "life-as-api";
|
|
206
|
+
|
|
207
|
+
const { api } = await createInMemoryLifeApiForTest();
|
|
208
|
+
const owner: OwnerContext = { kind: "owner", personId: asPersonId("me") };
|
|
209
|
+
|
|
210
|
+
// Store a claim with full provenance
|
|
211
|
+
await api.createClaimWithNewEvidence(owner, {
|
|
212
|
+
document: { bytes: new TextEncoder().encode("...statement..."), mimeType: "application/pdf" },
|
|
213
|
+
source: { id: asSourceId("src-001"), kind: "user_manual", label: "Bank statement" },
|
|
214
|
+
claim: {
|
|
215
|
+
subject: asPersonId("me"),
|
|
216
|
+
predicate: "contract.amount",
|
|
217
|
+
payload: { type: "money", currency: "EUR", minorUnits: 4999 },
|
|
218
|
+
validFrom: asISOTime("2025-01-15T00:00:00.000Z"),
|
|
219
|
+
contractId: asContractId("cntr-001"),
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`createInMemoryLifeApiForTest` is for development and testing only. It does not enforce
|
|
225
|
+
production auth boundaries.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## MVP-stable public API surface
|
|
230
|
+
|
|
231
|
+
| Import | Kind | Notes |
|
|
232
|
+
|--------|------|-------|
|
|
233
|
+
| `createSQLiteLifeApiForProduction` | factory | Returns `Promise<ProductionApiBundle>` |
|
|
234
|
+
| `ProductionApiBundle` | type | `{ auth: ContextMintingBoundary; createScopedApi; healthCheck }` |
|
|
235
|
+
| `ProductionScopedLifeApi` | type | 8-method scoped facade |
|
|
236
|
+
| `ListProposalsInput` | type | `{ status?: ProposalStatus }` — narrow filter for `listProposals` |
|
|
237
|
+
| `ContextMintingBoundary` | type | Interface for the auth minting boundary |
|
|
238
|
+
| `MintedContext` | type | Trusted context with scope metadata |
|
|
239
|
+
| `ProductionFactoryConfig` | type | Factory configuration interface — `encryptionKey?` (raw bytes → `StaticKeyProvider`) **or** `keyProvider?: KeyProvider` (external KMS-backed adapter); exactly one required; both present → fail-closed; also optional `logger?: Logger`, `metrics?: MetricsRecorder` |
|
|
240
|
+
| `Logger`, `LogEvent`, `LogLevel` | types | D2a best-effort operator diagnostics interface |
|
|
241
|
+
| `noopLogger` | runtime | Safe frozen no-op logger — the library default |
|
|
242
|
+
| `MetricsRecorder` | type | D2c optional push-style metrics adapter interface (`increment?`, `observe?`) |
|
|
243
|
+
| `MetricName` | type | Closed union of the five D2c metric names |
|
|
244
|
+
| `MetricLabels` | type | Closed interface of the six allowed low-cardinality label keys |
|
|
245
|
+
| `noopMetricsRecorder` | runtime | Safe frozen no-op metrics recorder — the library default |
|
|
246
|
+
| `HealthStatus` | type | `"ok" \| "degraded" \| "failed"` — aggregate and per-check status |
|
|
247
|
+
| `HealthCheckItem` | type | `{ name, status, code, errorName? }` — one entry per check, no sensitive fields |
|
|
248
|
+
| `HealthCheckResult` | type | `{ status, checkedAt, checks }` — full D2b result shape |
|
|
249
|
+
| `RejectOptions` | type | `{ reason: string }` for `rejectProposal` |
|
|
250
|
+
| `ProposalInput`, `AcceptOptions` | types | Proposal method parameter types |
|
|
251
|
+
| `PersonId`, `ProposalId`, … | opaque ID types | Tagged string IDs |
|
|
252
|
+
| `AuthAdapter`, `TenantBoundary`, `GrantResolver` | interfaces | Host adapter contracts |
|
|
253
|
+
| `SubjectScopedLifeApi`, `ProposalScopedLifeApi` | lower-level | Host-adapter composition utilities |
|
|
254
|
+
| `assertAuthorizedForSubject`, `inspectProposalScope` | helpers | Host-adapter scope utilities |
|
|
255
|
+
| `createInMemoryLifeApiForTest` | dev/test factory | Not a production pattern |
|
|
256
|
+
| `KeyProvider`, `KeyDescriptor` | types | Interface-only — external KMS adapter contract; no implementation exported |
|
|
257
|
+
| `TrustedAgentRegistry`, `TrustedAgentRegistryEntry` | types (Platform-01) | Interface + entry shape for agent-mint gating |
|
|
258
|
+
| `InMemoryTrustedAgentRegistry` | runtime (Platform-01) | Reference/dev implementation — production hosts supply their own |
|
|
259
|
+
| `TrustedDataSourceRegistry`, `TrustedDataSourceEntry` | types (Platform-02) | Interface + entry shape for source trust/expiry |
|
|
260
|
+
| `InMemoryTrustedDataSourceRegistry` | runtime (Platform-02) | Reference/dev implementation |
|
|
261
|
+
| `ProposalPolicy`, `ProposalPolicyInput`, `ProposalDisposition` | types (Platform-02) | Auto-accept/auto-reject/manual policy contract |
|
|
262
|
+
| `DefaultProposalPolicy`, `RegistryBackedProposalPolicy` | runtime (Platform-02) | Manual-default and registry-backed policy implementations |
|
|
263
|
+
| `GuardianRegistry`, `GuardianRelationship` | types (Platform-03) | Guardian/ward relationship contract |
|
|
264
|
+
| `InMemoryGuardianRegistry` | runtime (Platform-03) | Reference/dev implementation |
|
|
265
|
+
| `GuardianContextMintingBoundary` | type (Platform-03) | `ContextMintingBoundary` extended with `mintGuardianContext()` |
|
|
266
|
+
| `SubjectDataReport`, `GrantSummary`, `ProposalSummary`, `AuditEventSummary`, `SubjectDataReportOptions` | types (Platform-04) | Shape of the GDPR Art. 15/20 subject data report |
|
|
267
|
+
| `generateSubjectDataReport` | runtime (Platform-04) | Builds the subject data report; caller-identity enforcement is host responsibility |
|
|
268
|
+
| `MedicalAgent`, `medicalAgentRegistryEntry`, `MEDICAL_AGENT_ID`, `MEDICAL_AGENT_VERSION`, `ALLOWED_MEDICAL_PURPOSES`, `MedicalPurpose` | Platform-05 | Certified first-party medical agent (read-only, purpose-bound) |
|
|
269
|
+
| `FinanceAgent`, `financeAgentRegistryEntry`, `FINANCE_AGENT_ID`, `FINANCE_AGENT_VERSION`, `ALLOWED_FINANCE_PURPOSES`, `FinancePurpose` | Platform-05 | Certified first-party finance agent (read-only, purpose-bound) |
|
|
270
|
+
| `LegalAgent`, `legalAgentRegistryEntry`, `LEGAL_AGENT_ID`, `LEGAL_AGENT_VERSION`, `ALLOWED_LEGAL_PURPOSES`, `LegalPurpose` | Platform-05 | Certified first-party legal agent (read-only, purpose-bound) |
|
|
271
|
+
|
|
272
|
+
### Not exported from package root (intentional)
|
|
273
|
+
|
|
274
|
+
| Symbol | Reason |
|
|
275
|
+
|--------|--------|
|
|
276
|
+
| `LifeApiImpl` | Raw factory-internal API — bypasses scope enforcement |
|
|
277
|
+
| `BackendContextMintingBoundary` | Factory-internal production dependency |
|
|
278
|
+
| `AccessContextIssuer` (runtime) | Trust authority — instance-scoped only |
|
|
279
|
+
| `ProductionScopedLifeApiImpl` | Implementation class — use the interface |
|
|
280
|
+
| `JwtAuthAdapter`, `JwtKeyRingAuthAdapter`, `StaticJwtKeyRing` | Not package-root exported |
|
|
281
|
+
| `SQLiteTenantBoundary`, `SQLiteGrantResolver` | Not package-root exported |
|
|
282
|
+
| `SQLiteProposalQueue`, `SQLiteAuditLog`, `SQLiteRawDocumentStore` | Not package-root exported |
|
|
283
|
+
| `JwksKeyRingAuthAdapter` | RS256/JWKS auth adapter — not package-root exported |
|
|
284
|
+
| `TokenRevocationStore`, `RevocationAwareAuthAdapter` | Session revocation wrapper — not package-root exported |
|
|
285
|
+
| `RateLimiter`, `RateLimitedContextMintingBoundary` | Rate-limiting wrapper — not package-root exported |
|
|
286
|
+
|
|
287
|
+
The package exports map (`package.json exports`) is root-only. Unsupported subpath imports
|
|
288
|
+
(e.g. `"life-as-api/src/…"`, `"life-as-api/dist/…"`) are not part of the public API and
|
|
289
|
+
are blocked by Node.js for consumers respecting the exports map.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## What this is
|
|
294
|
+
|
|
295
|
+
- A typed, immutable claim log with AES-256-GCM encrypted payloads
|
|
296
|
+
- A consent-gated query surface (agents see only granted predicates)
|
|
297
|
+
- A proposal queue (agents propose, humans/systems accept or reject)
|
|
298
|
+
- A provenance chain: `RawDocument → EvidenceRef → Source → Claim`
|
|
299
|
+
- A production auth boundary: factory returns a scoped production API bundle; trusted context minting is enforced; grant person scope propagates to agent contexts; erasure/query/proposal create/accept/reject/read enforce documented subject/proposal scope
|
|
300
|
+
|
|
301
|
+
## What this is NOT
|
|
302
|
+
|
|
303
|
+
- **No KMS / external key custody** — JWT secrets in process memory; at-rest keys via `StaticKeyProvider`
|
|
304
|
+
- **No full OIDC/OAuth** — RS256/JWKS auth adapter (`JwksKeyRingAuthAdapter`) implemented (D5, `cbe40ed`); not exported from package root; host-supplied. ES256, full OIDC authorization server, OAuth flow not claimed
|
|
305
|
+
- **No session revocation built in** — `TokenRevocationStore` interface and
|
|
306
|
+
`RevocationAwareAuthAdapter` wrapper are implemented (host-injectable denylist, fail-closed on
|
|
307
|
+
store error); not exported from package root; without wiring one in, compromised credentials
|
|
308
|
+
require out-of-band grant revocation
|
|
309
|
+
- **No rate limiting built in** — `RateLimiter` interface and `RateLimitedContextMintingBoundary`
|
|
310
|
+
wrapper are implemented (host-injectable, principal-scoped, configurable fail-open/fail-closed
|
|
311
|
+
on store error); not exported from package root; no bundled limiter implementation or store, no
|
|
312
|
+
API-level throttle unless a host wires one in
|
|
313
|
+
- **No external tamper-evident audit** — audit events in SQLite only; no hash-chaining or external sink
|
|
314
|
+
- **No GDPR / legal erasure compliance** — tombstone model is not a legally valid erasure mechanism
|
|
315
|
+
- **No multi-process ProposalQueue consistency** — single-process only
|
|
316
|
+
- **No operational production readiness** — D2a adds best-effort operator diagnostics (logger); D2b adds seven local health checks (`healthCheck()` on the bundle — DB, schema, key provider, auth/tenant/grant adapters); `{ status: "ok" }` is not operational production readiness; D2c adds an optional internal `MetricsRecorder` boundary — push-style adapter for counters only; no external sink, no OpenTelemetry, no HTTP/Prometheus endpoint, no SLA/SLO claim; D3a adds internal SQLite backup/validation utilities (`backupSQLiteDatabase`, `validateBackup`) — recoverability tooling only, not an SLA or operational-readiness claim; D4b adds `validateBackupKeyAvailability(sourcePath, keyProvider)` — internal offline key availability check (are all referenced keyIds resolvable?); key availability does not prove correct key material or decryptability; D4c adds `scanBackupDecryptability(sourcePath, cryptoBoundary)` — internal offline AES-GCM decryptability scan across all three encrypted tables; `{ status: "ok" }` proves tag verification passed on all rows, not semantic correctness or DR readiness
|
|
317
|
+
- **No UI, MCP server, OCR, LLM extraction, Open Banking connectors**
|
|
318
|
+
- **No admin methods** — `createSourceAdmin`, `createGrantAdmin`, etc. are deferred
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Running tests
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
npm run build # compile src/ → dist/ (required before dist/-dependent checks)
|
|
326
|
+
npx vitest run # full suite (3908 passing)
|
|
327
|
+
npx tsc --noEmit # typecheck
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Installing / Releasing
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
npm install life-as-api # once published
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Releases are cut manually: `npm publish` runs `prepublishOnly` (`typecheck` → `test` → `build`)
|
|
339
|
+
before anything is packed, so a broken typecheck or a failing test blocks publish. The publish
|
|
340
|
+
step itself is deliberately manual — there is no CI-triggered auto-publish.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Documentation
|
|
345
|
+
|
|
346
|
+
| Doc | Contents |
|
|
347
|
+
|-----|----------|
|
|
348
|
+
| [docs/specs/post-auth-product-boundary-spec.md](docs/specs/post-auth-product-boundary-spec.md) | Post-auth product boundary freeze — capabilities, non-claims, post-MVP tracks |
|
|
349
|
+
| [docs/specs/post-mvp-proposal-read-facade-spec.md](docs/specs/post-mvp-proposal-read-facade-spec.md) | Proposal Read Facade spec — scoped `getProposal`/`listProposals` (implemented `7bc55b4`) |
|
|
350
|
+
| [docs/specs/post-mvp-audit-hardening-spec.md](docs/specs/post-mvp-audit-hardening-spec.md) | Audit Hardening spec — internal audit coverage C1 (implemented `ac44391`); read allow-path audit C3 (implemented `b85df38`); local hash chain C4: `sequence`/`prev_hash`/`event_hash` on `audit_events`, internal `verifyAuditChain` detects row deletion/reorder/naive modification (implemented `ebf52c2`; local-only — not court-grade, not WORM, not external notarization) |
|
|
351
|
+
| [docs/specs/post-auth-mvp-packaging-exports-spec.md](docs/specs/post-auth-mvp-packaging-exports-spec.md) | Packaging/exports review — Phase 1 (type gaps, complete) and Phase 2 (exports map, complete) |
|
|
352
|
+
| [docs/specs/post-auth-mvp-packaging-phase2-spec.md](docs/specs/post-auth-mvp-packaging-phase2-spec.md) | Package Exports Phase 2 spec — build strategy, exports map, deep import policy (implemented `0518c1a`) |
|
|
353
|
+
| [docs/specs/production-auth-closure-recheck-spec.md](docs/specs/production-auth-closure-recheck-spec.md) | C1–C10 Final Audit — Option A accepted |
|
|
354
|
+
| [docs/specs/production-auth-closure-spec.md](docs/specs/production-auth-closure-spec.md) | Auth closure criteria (C1–C10), MUST gaps, DEFER/NEVER inventory |
|
|
355
|
+
| [docs/roadmap/production-auth-track-freeze.md](docs/roadmap/production-auth-track-freeze.md) | Canonical auth track record — all slices, invariants, claims allowed/forbidden |
|
|
356
|
+
| [docs/INVARIANTS.md](docs/INVARIANTS.md) | Machine-checkable property table (all invariant codes) |
|
|
357
|
+
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | System components, data flow, intentional exclusions |
|
|
358
|
+
| [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md) | Assets, actors, trust boundaries, threats, mitigations |
|
|
359
|
+
| [docs/SDK_USAGE.md](docs/SDK_USAGE.md) | How to use every public API method |
|
|
360
|
+
| [docs/KNOWN_LIMITATIONS.md](docs/KNOWN_LIMITATIONS.md) | MVP gaps and production blockers |
|
|
361
|
+
| [docs/releases/v0.1.0-architecture-ready.md](docs/releases/v0.1.0-architecture-ready.md) | Release notes — v0.1.0-architecture-ready (historical baseline) |
|
|
362
|
+
| [docs/BACKUP_RESTORE.md](docs/BACKUP_RESTORE.md) | Backup and Restore operator procedure — `backupSQLiteDatabase`, `validateBackup`, restore steps, key boundary, non-claims (D3a) |
|
|
363
|
+
| [docs/KEY_MANAGEMENT.md](docs/KEY_MANAGEMENT.md) | Key Management operator procedure — key inventory query, rotation steps, pre-restore key check, KMS adapter contract, non-claims (D4a) |
|
|
364
|
+
| [docs/specs/post-mvp-observability-d2c-metrics-spec.md](docs/specs/post-mvp-observability-d2c-metrics-spec.md) | D2c Metrics Boundary Spec — `MetricsRecorder` interface, five metric names, six label keys, label policy, failure policy, non-claims; runtime accepted at `9820589` |
|
|
365
|
+
| [docs/OPERATIONAL_RUNBOOK.md](docs/OPERATIONAL_RUNBOOK.md) | Operational Runbook — startup/backup/key-availability/restore-drill/promotion checklists, nine incident triage trees, four-layer observability guide, security-sensitive data rules, non-claims (D2/D3/D4 integration) |
|
|
366
|
+
| [docs/specs/post-mvp-kms-adapter-spec.md](docs/specs/post-mvp-kms-adapter-spec.md) | KMS Adapter Spec — `KeyProvider` adapter contract, factory config extension (`keyProvider?`), envelope-encryption pattern, no provider binding, D4e non-exportable deferral; accepted, runtime at `f500719` |
|
|
367
|
+
| [docs/specs/post-mvp-external-idp-oidc-spec.md](docs/specs/post-mvp-external-idp-oidc-spec.md) | External IdP / OIDC / JWKS Spec — `JwksKeyRingAuthAdapter` (RS256 + live JWKS), injectable `HttpClient`, host-injected `ClaimMapper`, OIDC discovery utility, algorithm binding, fetch-amplification bound; ✅ Accepted, runtime at `cbe40ed` |
|
|
368
|
+
| [docs/specs/post-mvp-session-revocation-spec.md](docs/specs/post-mvp-session-revocation-spec.md) | Session Revocation Spec — `TokenRevocationStore` (host-injectable denylist), `RevocationAwareAuthAdapter` wrapper, JTI extraction from unverified payload, fail-closed store error policy, 8 invariants; ✅ Accepted, runtime at `28624ac` |
|
|
369
|
+
| [docs/specs/post-mvp-rate-limiting-spec.md](docs/specs/post-mvp-rate-limiting-spec.md) | Rate Limiting Spec — `RateLimiter` (host-injectable interface), `RateLimitedContextMintingBoundary` wrapper, post-verification key derivation (`principalId + tenantId`), configurable fail-open/closed on store error, 7 invariants; ✅ Accepted, runtime at `88e88c9` |
|
|
370
|
+
| [docs/specs/post-mvp-d4c-decryptability-scan-spec.md](docs/specs/post-mvp-d4c-decryptability-scan-spec.md) | D4c Full Decryptability Scan Spec — `scanBackupDecryptability(sourcePath, cryptoBoundary)`, covers all 3 encrypted tables, aggregate counts only, `"ok"\|"partial"\|"failed"` status, no entity IDs or plaintext in result; ✅ Accepted, runtime at `9995ac5` |
|
|
371
|
+
| [docs/specs/post-mvp-kms-key-recovery-escrow-procedure-spec.md](docs/specs/post-mvp-kms-key-recovery-escrow-procedure-spec.md) | KMS Key Recovery / Escrow Procedure Spec — operator procedure for key inventory, recovery roles, retirement pre-checks (D3a/D4b/D4c chain), restore drill checklist, break-glass controls, evidence artifacts; docs-only, no runtime, no KMS integration, no key escrow implemented by library; 📋 Pending GPT-5.5 acceptance |
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Compliance disclaimer
|
|
376
|
+
|
|
377
|
+
This repository describes software architecture decisions. It is not legal advice. Nothing here constitutes a GDPR compliance mechanism, a legally valid erasure mechanism, a security audit, or an operational readiness guarantee. Real production deployments require legal review, external security assessment, and compliance validation appropriate to the jurisdiction and data category.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Clock, MintedContext } from "../auth/types.js";
|
|
2
|
+
import type { QueryContractsInput, ContextQueryResult } from "../surface/evidence-backed-context-query.js";
|
|
3
|
+
import type { TrustedAgentRegistryEntry } from "./trusted-agent-registry.js";
|
|
4
|
+
export declare const FINANCE_AGENT_ID = "life-as-api/finance-agent-v1";
|
|
5
|
+
export declare const FINANCE_AGENT_VERSION = "1.0.0";
|
|
6
|
+
export declare const ALLOWED_FINANCE_PURPOSES: readonly ["tax", "credit_check", "insurance_claim", "account_overview"];
|
|
7
|
+
export type FinancePurpose = typeof ALLOWED_FINANCE_PURPOSES[number];
|
|
8
|
+
/**
|
|
9
|
+
* Builds the TrustedAgentRegistryEntry for the certified Finance Agent.
|
|
10
|
+
* FINANCE_AGENT_REGISTRY_ENTRY_001: certifiedBy is always "life-as-api-foundation".
|
|
11
|
+
* Permissions include every allowed purpose (the minting boundary passes
|
|
12
|
+
* decision.purpose as the scope argument to isAgentTrusted) plus declarative
|
|
13
|
+
* read:* scopes for operator documentation.
|
|
14
|
+
*/
|
|
15
|
+
export declare function financeAgentRegistryEntry(validUntilMs: number): TrustedAgentRegistryEntry;
|
|
16
|
+
export interface FinanceAgentAuditEvent {
|
|
17
|
+
readonly at: string;
|
|
18
|
+
readonly agentId: string;
|
|
19
|
+
readonly reasonCode: "FINANCE_AGENT_RUN_001";
|
|
20
|
+
readonly decision: "allowed" | "denied";
|
|
21
|
+
readonly declaredPurpose?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface FinanceAgentOptions {
|
|
24
|
+
readonly query: (ctx: MintedContext, input: QueryContractsInput) => Promise<ContextQueryResult>;
|
|
25
|
+
readonly clock: Clock;
|
|
26
|
+
readonly onAudit?: (event: FinanceAgentAuditEvent) => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Certified first-party Finance Agent.
|
|
30
|
+
* FINANCE_AGENT_READ_ONLY_001: query-capability only, no propose/write capability.
|
|
31
|
+
*/
|
|
32
|
+
export declare class FinanceAgent {
|
|
33
|
+
private readonly opts;
|
|
34
|
+
constructor(opts: FinanceAgentOptions);
|
|
35
|
+
/**
|
|
36
|
+
* FINANCE_AGENT_SCOPE_ENFORCED_001 / FINANCE_AGENT_PURPOSE_BOUND_001: run() only
|
|
37
|
+
* delegates to the configured query function when ctx.declaredPurpose is one of
|
|
38
|
+
* ALLOWED_FINANCE_PURPOSES. Any other value, or an absent declaredPurpose, denies
|
|
39
|
+
* fail-closed before the query function is ever invoked.
|
|
40
|
+
* FINANCE_AGENT_AUDIT_TRAIL_001: the onAudit hook (if configured) always fires,
|
|
41
|
+
* for both the allowed and denied outcome.
|
|
42
|
+
*/
|
|
43
|
+
run(ctx: MintedContext, query: QueryContractsInput): Promise<ContextQueryResult>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Platform-05 — Certified First-Party Agents: Finance Agent.
|
|
2
|
+
//
|
|
3
|
+
// FINANCE_AGENT_PURPOSE_BOUND_001: this agent acts ONLY when the caller's MintedContext
|
|
4
|
+
// carries declaredPurpose "tax" | "credit_check" | "insurance_claim" | "account_overview".
|
|
5
|
+
// Any other declared purpose (or none) is denied before the query function is invoked.
|
|
6
|
+
// FINANCE_AGENT_REGISTRY_ENTRY_001: financeAgentRegistryEntry() returns a
|
|
7
|
+
// TrustedAgentRegistryEntry certifiedBy "life-as-api-foundation" so hosts can register
|
|
8
|
+
// this agent with a TrustedAgentRegistry (Platform-01) without hand-rolling the entry.
|
|
9
|
+
// FINANCE_AGENT_SCOPE_ENFORCED_001: run() throws FINANCE_AGENT_SCOPE_DENIED_001 when
|
|
10
|
+
// declaredPurpose is absent or not in ALLOWED_FINANCE_PURPOSES — fail-closed.
|
|
11
|
+
// FINANCE_AGENT_READ_ONLY_001: the agent has query-capability only. The constructor
|
|
12
|
+
// accepts exclusively a `query` function; there is no propose/write capability anywhere
|
|
13
|
+
// on this class.
|
|
14
|
+
// FINANCE_AGENT_AUDIT_TRAIL_001: every run() call invokes the optional onAudit hook with
|
|
15
|
+
// reasonCode "FINANCE_AGENT_RUN_001" (allowed or denied). Actual audit persistence is a
|
|
16
|
+
// host responsibility — this hook is a notification point only.
|
|
17
|
+
export const FINANCE_AGENT_ID = "life-as-api/finance-agent-v1";
|
|
18
|
+
export const FINANCE_AGENT_VERSION = "1.0.0";
|
|
19
|
+
export const ALLOWED_FINANCE_PURPOSES = ["tax", "credit_check", "insurance_claim", "account_overview"];
|
|
20
|
+
// TRUSTED_AGENT_REGISTRY_PUBKEY_ENFORCEMENT_DEFERRED_001: placeholder public key —
|
|
21
|
+
// cryptographic signature verification at mint time is not yet implemented.
|
|
22
|
+
const FINANCE_AGENT_PUBLIC_KEY_PEM_PLACEHOLDER = "-----BEGIN PUBLIC KEY-----\nPLACEHOLDER-FINANCE-AGENT-KEY-NOT-YET-ENFORCED\n-----END PUBLIC KEY-----";
|
|
23
|
+
/**
|
|
24
|
+
* Builds the TrustedAgentRegistryEntry for the certified Finance Agent.
|
|
25
|
+
* FINANCE_AGENT_REGISTRY_ENTRY_001: certifiedBy is always "life-as-api-foundation".
|
|
26
|
+
* Permissions include every allowed purpose (the minting boundary passes
|
|
27
|
+
* decision.purpose as the scope argument to isAgentTrusted) plus declarative
|
|
28
|
+
* read:* scopes for operator documentation.
|
|
29
|
+
*/
|
|
30
|
+
export function financeAgentRegistryEntry(validUntilMs) {
|
|
31
|
+
return {
|
|
32
|
+
agentId: FINANCE_AGENT_ID,
|
|
33
|
+
name: "Certified Finance Agent (first-party)",
|
|
34
|
+
permissions: [...ALLOWED_FINANCE_PURPOSES, "read:finance", "read:tax", "read:insurance"],
|
|
35
|
+
certifiedBy: "life-as-api-foundation",
|
|
36
|
+
validUntil: new Date(validUntilMs).toISOString(),
|
|
37
|
+
publicKeyPem: FINANCE_AGENT_PUBLIC_KEY_PEM_PLACEHOLDER,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Certified first-party Finance Agent.
|
|
42
|
+
* FINANCE_AGENT_READ_ONLY_001: query-capability only, no propose/write capability.
|
|
43
|
+
*/
|
|
44
|
+
export class FinanceAgent {
|
|
45
|
+
opts;
|
|
46
|
+
constructor(opts) {
|
|
47
|
+
this.opts = opts;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* FINANCE_AGENT_SCOPE_ENFORCED_001 / FINANCE_AGENT_PURPOSE_BOUND_001: run() only
|
|
51
|
+
* delegates to the configured query function when ctx.declaredPurpose is one of
|
|
52
|
+
* ALLOWED_FINANCE_PURPOSES. Any other value, or an absent declaredPurpose, denies
|
|
53
|
+
* fail-closed before the query function is ever invoked.
|
|
54
|
+
* FINANCE_AGENT_AUDIT_TRAIL_001: the onAudit hook (if configured) always fires,
|
|
55
|
+
* for both the allowed and denied outcome.
|
|
56
|
+
*/
|
|
57
|
+
async run(ctx, query) {
|
|
58
|
+
const purpose = ctx.declaredPurpose;
|
|
59
|
+
const allowed = purpose !== undefined &&
|
|
60
|
+
ALLOWED_FINANCE_PURPOSES.includes(purpose);
|
|
61
|
+
this.opts.onAudit?.({
|
|
62
|
+
at: this.opts.clock.now(),
|
|
63
|
+
agentId: FINANCE_AGENT_ID,
|
|
64
|
+
reasonCode: "FINANCE_AGENT_RUN_001",
|
|
65
|
+
decision: allowed ? "allowed" : "denied",
|
|
66
|
+
...(purpose !== undefined ? { declaredPurpose: purpose } : {}),
|
|
67
|
+
});
|
|
68
|
+
if (!allowed) {
|
|
69
|
+
throw Object.assign(new Error("FINANCE_AGENT_SCOPE_DENIED_001: FinanceAgent may only run with declaredPurpose " +
|
|
70
|
+
`"tax" | "credit_check" | "insurance_claim" | "account_overview" (got: ${purpose ?? "undefined"})`), { code: "FINANCE_AGENT_SCOPE_DENIED_001" });
|
|
71
|
+
}
|
|
72
|
+
return this.opts.query(ctx, query);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=finance-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finance-agent.js","sourceRoot":"","sources":["../../src/agent/finance-agent.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,wFAAwF;AACxF,6FAA6F;AAC7F,yFAAyF;AACzF,0EAA0E;AAC1E,yFAAyF;AACzF,yFAAyF;AACzF,qFAAqF;AACrF,gFAAgF;AAChF,oFAAoF;AACpF,0FAA0F;AAC1F,mBAAmB;AACnB,yFAAyF;AACzF,0FAA0F;AAC1F,kEAAkE;AAMlE,MAAM,CAAC,MAAM,gBAAgB,GAAG,8BAA8B,CAAC;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG,OAAO,CAAC;AAE7C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,CAAU,CAAC;AAGhH,mFAAmF;AACnF,4EAA4E;AAC5E,MAAM,wCAAwC,GAC5C,sGAAsG,CAAC;AAEzG;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,YAAoB;IAC5D,OAAO;QACL,OAAO,EAAE,gBAAgB;QACzB,IAAI,EAAE,uCAAuC;QAC7C,WAAW,EAAE,CAAC,GAAG,wBAAwB,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,CAAC;QACxF,WAAW,EAAE,wBAAwB;QACrC,UAAU,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;QAChD,YAAY,EAAE,wCAAwC;KACvD,CAAC;AACJ,CAAC;AAgBD;;;GAGG;AACH,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,IAAyB;QAAzB,SAAI,GAAJ,IAAI,CAAqB;IAAG,CAAC;IAE1D;;;;;;;OAOG;IACH,KAAK,CAAC,GAAG,CAAC,GAAkB,EAAE,KAA0B;QACtD,MAAM,OAAO,GAAG,GAAG,CAAC,eAAe,CAAC;QACpC,MAAM,OAAO,GACX,OAAO,KAAK,SAAS;YACpB,wBAAkD,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAExE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;YACzB,OAAO,EAAE,gBAAgB;YACzB,UAAU,EAAE,uBAAuB;YACnC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;YACxC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/D,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,MAAM,CAAC,MAAM,CACjB,IAAI,KAAK,CACP,iFAAiF;gBACjF,yEAAyE,OAAO,IAAI,WAAW,GAAG,CACnG,EACD,EAAE,IAAI,EAAE,gCAAgC,EAAE,CAC3C,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;CACF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Clock, MintedContext } from "../auth/types.js";
|
|
2
|
+
import type { QueryContractsInput, ContextQueryResult } from "../surface/evidence-backed-context-query.js";
|
|
3
|
+
import type { TrustedAgentRegistryEntry } from "./trusted-agent-registry.js";
|
|
4
|
+
export declare const LEGAL_AGENT_ID = "life-as-api/legal-agent-v1";
|
|
5
|
+
export declare const LEGAL_AGENT_VERSION = "1.0.0";
|
|
6
|
+
export declare const ALLOWED_LEGAL_PURPOSES: readonly ["notary", "contract_review", "evidence_preservation", "court_filing"];
|
|
7
|
+
export type LegalPurpose = typeof ALLOWED_LEGAL_PURPOSES[number];
|
|
8
|
+
/**
|
|
9
|
+
* Builds the TrustedAgentRegistryEntry for the certified Legal Agent.
|
|
10
|
+
* LEGAL_AGENT_REGISTRY_ENTRY_001: certifiedBy is always "life-as-api-foundation".
|
|
11
|
+
* Permissions include every allowed purpose (the minting boundary passes
|
|
12
|
+
* decision.purpose as the scope argument to isAgentTrusted) plus declarative
|
|
13
|
+
* read:* scopes for operator documentation.
|
|
14
|
+
*/
|
|
15
|
+
export declare function legalAgentRegistryEntry(validUntilMs: number): TrustedAgentRegistryEntry;
|
|
16
|
+
export interface LegalAgentAuditEvent {
|
|
17
|
+
readonly at: string;
|
|
18
|
+
readonly agentId: string;
|
|
19
|
+
readonly reasonCode: "LEGAL_AGENT_RUN_001";
|
|
20
|
+
readonly decision: "allowed" | "denied";
|
|
21
|
+
readonly declaredPurpose?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface LegalAgentOptions {
|
|
24
|
+
readonly query: (ctx: MintedContext, input: QueryContractsInput) => Promise<ContextQueryResult>;
|
|
25
|
+
readonly clock: Clock;
|
|
26
|
+
readonly onAudit?: (event: LegalAgentAuditEvent) => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Certified first-party Legal Agent.
|
|
30
|
+
* LEGAL_AGENT_READ_ONLY_001: query-capability only, no propose/write capability.
|
|
31
|
+
*/
|
|
32
|
+
export declare class LegalAgent {
|
|
33
|
+
private readonly opts;
|
|
34
|
+
constructor(opts: LegalAgentOptions);
|
|
35
|
+
/**
|
|
36
|
+
* LEGAL_AGENT_SCOPE_ENFORCED_001 / LEGAL_AGENT_PURPOSE_BOUND_001: run() only
|
|
37
|
+
* delegates to the configured query function when ctx.declaredPurpose is one of
|
|
38
|
+
* ALLOWED_LEGAL_PURPOSES. Any other value, or an absent declaredPurpose, denies
|
|
39
|
+
* fail-closed before the query function is ever invoked.
|
|
40
|
+
* LEGAL_AGENT_AUDIT_TRAIL_001: the onAudit hook (if configured) always fires,
|
|
41
|
+
* for both the allowed and denied outcome.
|
|
42
|
+
*/
|
|
43
|
+
run(ctx: MintedContext, query: QueryContractsInput): Promise<ContextQueryResult>;
|
|
44
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Platform-05 — Certified First-Party Agents: Legal Agent.
|
|
2
|
+
//
|
|
3
|
+
// LEGAL_AGENT_PURPOSE_BOUND_001: this agent acts ONLY when the caller's MintedContext
|
|
4
|
+
// carries declaredPurpose "notary" | "contract_review" | "evidence_preservation" |
|
|
5
|
+
// "court_filing". Any other declared purpose (or none) is denied before the query
|
|
6
|
+
// function is invoked.
|
|
7
|
+
// LEGAL_AGENT_REGISTRY_ENTRY_001: legalAgentRegistryEntry() returns a
|
|
8
|
+
// TrustedAgentRegistryEntry certifiedBy "life-as-api-foundation" so hosts can register
|
|
9
|
+
// this agent with a TrustedAgentRegistry (Platform-01) without hand-rolling the entry.
|
|
10
|
+
// LEGAL_AGENT_SCOPE_ENFORCED_001: run() throws LEGAL_AGENT_SCOPE_DENIED_001 when
|
|
11
|
+
// declaredPurpose is absent or not in ALLOWED_LEGAL_PURPOSES — fail-closed.
|
|
12
|
+
// LEGAL_AGENT_READ_ONLY_001: the agent has query-capability only. The constructor
|
|
13
|
+
// accepts exclusively a `query` function; there is no propose/write capability anywhere
|
|
14
|
+
// on this class.
|
|
15
|
+
// LEGAL_AGENT_AUDIT_TRAIL_001: every run() call invokes the optional onAudit hook with
|
|
16
|
+
// reasonCode "LEGAL_AGENT_RUN_001" (allowed or denied). Actual audit persistence is a
|
|
17
|
+
// host responsibility — this hook is a notification point only.
|
|
18
|
+
export const LEGAL_AGENT_ID = "life-as-api/legal-agent-v1";
|
|
19
|
+
export const LEGAL_AGENT_VERSION = "1.0.0";
|
|
20
|
+
export const ALLOWED_LEGAL_PURPOSES = ["notary", "contract_review", "evidence_preservation", "court_filing"];
|
|
21
|
+
// TRUSTED_AGENT_REGISTRY_PUBKEY_ENFORCEMENT_DEFERRED_001: placeholder public key —
|
|
22
|
+
// cryptographic signature verification at mint time is not yet implemented.
|
|
23
|
+
const LEGAL_AGENT_PUBLIC_KEY_PEM_PLACEHOLDER = "-----BEGIN PUBLIC KEY-----\nPLACEHOLDER-LEGAL-AGENT-KEY-NOT-YET-ENFORCED\n-----END PUBLIC KEY-----";
|
|
24
|
+
/**
|
|
25
|
+
* Builds the TrustedAgentRegistryEntry for the certified Legal Agent.
|
|
26
|
+
* LEGAL_AGENT_REGISTRY_ENTRY_001: certifiedBy is always "life-as-api-foundation".
|
|
27
|
+
* Permissions include every allowed purpose (the minting boundary passes
|
|
28
|
+
* decision.purpose as the scope argument to isAgentTrusted) plus declarative
|
|
29
|
+
* read:* scopes for operator documentation.
|
|
30
|
+
*/
|
|
31
|
+
export function legalAgentRegistryEntry(validUntilMs) {
|
|
32
|
+
return {
|
|
33
|
+
agentId: LEGAL_AGENT_ID,
|
|
34
|
+
name: "Certified Legal Agent (first-party)",
|
|
35
|
+
permissions: [...ALLOWED_LEGAL_PURPOSES, "read:legal", "read:contracts", "read:identity"],
|
|
36
|
+
certifiedBy: "life-as-api-foundation",
|
|
37
|
+
validUntil: new Date(validUntilMs).toISOString(),
|
|
38
|
+
publicKeyPem: LEGAL_AGENT_PUBLIC_KEY_PEM_PLACEHOLDER,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Certified first-party Legal Agent.
|
|
43
|
+
* LEGAL_AGENT_READ_ONLY_001: query-capability only, no propose/write capability.
|
|
44
|
+
*/
|
|
45
|
+
export class LegalAgent {
|
|
46
|
+
opts;
|
|
47
|
+
constructor(opts) {
|
|
48
|
+
this.opts = opts;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* LEGAL_AGENT_SCOPE_ENFORCED_001 / LEGAL_AGENT_PURPOSE_BOUND_001: run() only
|
|
52
|
+
* delegates to the configured query function when ctx.declaredPurpose is one of
|
|
53
|
+
* ALLOWED_LEGAL_PURPOSES. Any other value, or an absent declaredPurpose, denies
|
|
54
|
+
* fail-closed before the query function is ever invoked.
|
|
55
|
+
* LEGAL_AGENT_AUDIT_TRAIL_001: the onAudit hook (if configured) always fires,
|
|
56
|
+
* for both the allowed and denied outcome.
|
|
57
|
+
*/
|
|
58
|
+
async run(ctx, query) {
|
|
59
|
+
const purpose = ctx.declaredPurpose;
|
|
60
|
+
const allowed = purpose !== undefined &&
|
|
61
|
+
ALLOWED_LEGAL_PURPOSES.includes(purpose);
|
|
62
|
+
this.opts.onAudit?.({
|
|
63
|
+
at: this.opts.clock.now(),
|
|
64
|
+
agentId: LEGAL_AGENT_ID,
|
|
65
|
+
reasonCode: "LEGAL_AGENT_RUN_001",
|
|
66
|
+
decision: allowed ? "allowed" : "denied",
|
|
67
|
+
...(purpose !== undefined ? { declaredPurpose: purpose } : {}),
|
|
68
|
+
});
|
|
69
|
+
if (!allowed) {
|
|
70
|
+
throw Object.assign(new Error("LEGAL_AGENT_SCOPE_DENIED_001: LegalAgent may only run with declaredPurpose " +
|
|
71
|
+
`"notary" | "contract_review" | "evidence_preservation" | "court_filing" (got: ${purpose ?? "undefined"})`), { code: "LEGAL_AGENT_SCOPE_DENIED_001" });
|
|
72
|
+
}
|
|
73
|
+
return this.opts.query(ctx, query);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=legal-agent.js.map
|