@harperfast/harper 5.3.0-beta.3 → 5.3.0-beta.4
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/bin/cliOperations.ts +25 -3
- package/bin/run.ts +18 -0
- package/components/Application.ts +52 -78
- package/components/DESIGN.md +76 -3
- package/components/Scope.ts +10 -4
- package/components/anthropic/index.ts +10 -1
- package/components/bedrock/index.ts +10 -1
- package/components/componentLoader.ts +23 -14
- package/components/mcp/tools/operations.ts +3 -1
- package/components/ollama/index.ts +10 -1
- package/components/openai/index.ts +265 -18
- package/components/operations.js +40 -1
- package/config/configUtils.ts +3 -19
- package/dataLayer/DESIGN.md +29 -5
- package/dataLayer/harperBridge/ResourceBridge.ts +39 -3
- package/dataLayer/restoreMarker.ts +250 -14
- package/dataLayer/schema.ts +2 -7
- package/dataLayer/schemaDescribe.ts +10 -0
- package/dist/bin/cliOperations.js +28 -3
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/run.js +19 -0
- package/dist/bin/run.js.map +1 -1
- package/dist/components/Application.d.ts +8 -2
- package/dist/components/Application.js +43 -69
- package/dist/components/Application.js.map +1 -1
- package/dist/components/Scope.d.ts +1 -1
- package/dist/components/Scope.js +9 -4
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/anthropic/index.d.ts +0 -10
- package/dist/components/anthropic/index.js +9 -1
- package/dist/components/anthropic/index.js.map +1 -1
- package/dist/components/bedrock/index.d.ts +0 -12
- package/dist/components/bedrock/index.js +9 -1
- package/dist/components/bedrock/index.js.map +1 -1
- package/dist/components/componentLoader.js +23 -14
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/mcp/tools/operations.js +1 -1
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/ollama/index.d.ts +0 -13
- package/dist/components/ollama/index.js +9 -1
- package/dist/components/ollama/index.js.map +1 -1
- package/dist/components/openai/index.d.ts +11 -15
- package/dist/components/openai/index.js +224 -12
- package/dist/components/openai/index.js.map +1 -1
- package/dist/components/operations.d.ts +9 -0
- package/dist/components/operations.js +32 -2
- package/dist/components/operations.js.map +1 -1
- package/dist/config/configUtils.d.ts +1 -2
- package/dist/config/configUtils.js +7 -22
- package/dist/config/configUtils.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +29 -2
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/restoreMarker.d.ts +25 -3
- package/dist/dataLayer/restoreMarker.js +213 -13
- package/dist/dataLayer/restoreMarker.js.map +1 -1
- package/dist/dataLayer/schema.js +1 -4
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +10 -0
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +28 -0
- package/dist/resources/DatabaseTransaction.d.ts +21 -1
- package/dist/resources/DatabaseTransaction.js +147 -8
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.js +1 -1
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/Table.d.ts +31 -3
- package/dist/resources/Table.js +397 -79
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/auditStore.js +16 -10
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +1 -0
- package/dist/resources/blob.js +14 -5
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/branchDatabase.js +3 -3
- package/dist/resources/branchDatabase.js.map +1 -1
- package/dist/resources/databaseDropPreparation.d.ts +20 -0
- package/dist/resources/databaseDropPreparation.js +106 -0
- package/dist/resources/databaseDropPreparation.js.map +1 -0
- package/dist/resources/databases.d.ts +26 -21
- package/dist/resources/databases.js +1040 -204
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +23 -0
- package/dist/resources/derivedIndexRegistry.js +92 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -1
- package/dist/resources/derivedIndexRuntime.d.ts +10 -0
- package/dist/resources/derivedIndexRuntime.js +136 -25
- package/dist/resources/derivedIndexRuntime.js.map +1 -1
- package/dist/resources/derivedIndexes.d.ts +39 -0
- package/dist/resources/derivedIndexes.js +733 -0
- package/dist/resources/derivedIndexes.js.map +1 -0
- package/dist/resources/fullTextSchema.d.ts +8 -0
- package/dist/resources/fullTextSchema.js +42 -0
- package/dist/resources/fullTextSchema.js.map +1 -1
- package/dist/resources/fullTextSchemaLifecycle.d.ts +0 -5
- package/dist/resources/fullTextSchemaLifecycle.js +0 -9
- package/dist/resources/fullTextSchemaLifecycle.js.map +1 -1
- package/dist/resources/graphql.js +101 -9
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +0 -10
- package/dist/resources/indexes/hnswDerivedIndex.js +0 -230
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -1
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.d.ts +3 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js +57 -8
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js.map +1 -1
- package/dist/resources/models/Models.d.ts +26 -3
- package/dist/resources/models/Models.js +256 -13
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/TestBackend.d.ts +3 -1
- package/dist/resources/models/TestBackend.js +35 -1
- package/dist/resources/models/TestBackend.js.map +1 -1
- package/dist/resources/models/analyticsTable.d.ts +2 -2
- package/dist/resources/models/analyticsTable.js +4 -2
- package/dist/resources/models/analyticsTable.js.map +1 -1
- package/dist/resources/models/backendHelpers.d.ts +24 -0
- package/dist/resources/models/backendHelpers.js +18 -1
- package/dist/resources/models/backendHelpers.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +10 -21
- package/dist/resources/models/backendRegistry.js +74 -18
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +7 -0
- package/dist/resources/models/bootstrap.js +36 -4
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/models/decideHook.d.ts +33 -0
- package/dist/resources/models/decideHook.js +105 -0
- package/dist/resources/models/decideHook.js.map +1 -0
- package/dist/resources/models/decision.d.ts +64 -0
- package/dist/resources/models/decision.js +507 -0
- package/dist/resources/models/decision.js.map +1 -0
- package/dist/resources/models/decisionStore.d.ts +134 -0
- package/dist/resources/models/decisionStore.js +350 -0
- package/dist/resources/models/decisionStore.js.map +1 -0
- package/dist/resources/models/embedHook.d.ts +66 -8
- package/dist/resources/models/embedHook.js +228 -61
- package/dist/resources/models/embedHook.js.map +1 -1
- package/dist/resources/models/generativeDecision.d.ts +58 -0
- package/dist/resources/models/generativeDecision.js +315 -0
- package/dist/resources/models/generativeDecision.js.map +1 -0
- package/dist/resources/models/types.d.ts +232 -4
- package/dist/security/authn/oidc/tokenExchange.js +3 -33
- package/dist/security/authn/oidc/tokenExchange.js.map +1 -1
- package/dist/security/authn/oidc/tokenUseTable.d.ts +9 -0
- package/dist/security/authn/oidc/tokenUseTable.js +28 -0
- package/dist/security/authn/oidc/tokenUseTable.js.map +1 -0
- package/dist/security/certificateVerification/certificateVerificationSource.d.ts +0 -1
- package/dist/security/certificateVerification/certificateVerificationSource.js +3 -3
- package/dist/security/certificateVerification/certificateVerificationSource.js.map +1 -1
- package/dist/security/certificateVerification/crlVerification.js +77 -165
- package/dist/security/certificateVerification/crlVerification.js.map +1 -1
- package/dist/security/certificateVerification/types.d.ts +0 -3
- package/dist/security/certificateVerification/verificationTables.d.ts +19 -0
- package/dist/security/certificateVerification/verificationTables.js +125 -0
- package/dist/security/certificateVerification/verificationTables.js.map +1 -0
- package/dist/security/certificateVerification/verificationUtils.d.ts +1 -1
- package/dist/security/certificateVerification/verificationUtils.js +6 -31
- package/dist/security/certificateVerification/verificationUtils.js.map +1 -1
- package/dist/security/jsLoader.d.ts +5 -0
- package/dist/security/jsLoader.js +8 -0
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/server/Server.d.ts +1 -0
- package/dist/server/Server.js.map +1 -1
- package/dist/server/http.js +2 -2
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +21 -2
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobOwnership.d.ts +25 -0
- package/dist/server/jobs/jobOwnership.js +127 -0
- package/dist/server/jobs/jobOwnership.js.map +1 -0
- package/dist/server/jobs/jobProcess.js +9 -2
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobs.js +18 -5
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/loadRootComponents.js +10 -0
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.js +11 -1
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/serverHandlers.js +12 -2
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/threads/itc.d.ts +4 -1
- package/dist/server/threads/itc.js +29 -6
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +12 -4
- package/dist/server/threads/manageThreads.js +241 -119
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/threadServer.d.ts +1 -0
- package/dist/server/threads/threadServer.js +15 -1
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/server/threads/windowsProcessTree.d.ts +91 -0
- package/dist/server/threads/windowsProcessTree.js +361 -0
- package/dist/server/threads/windowsProcessTree.js.map +1 -0
- package/dist/server/throttle.d.ts +1 -1
- package/dist/server/throttle.js +8 -1
- package/dist/server/throttle.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.js +53 -46
- package/dist/upgrade/directives/5-3-0.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +10 -1
- package/dist/utility/errors/hdbError.js +55 -11
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/fsync.d.ts +2 -0
- package/dist/utility/fsync.js +20 -0
- package/dist/utility/fsync.js.map +1 -0
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +3 -0
- package/dist/utility/hdbTerms.js +3 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/signalling.d.ts +7 -1
- package/dist/utility/signalling.js +27 -3
- package/dist/utility/signalling.js.map +1 -1
- package/dist/utility/when.d.ts +1 -0
- package/dist/utility/when.js +21 -0
- package/dist/utility/when.js.map +1 -1
- package/dist/validation/configValidator.js +30 -3
- package/dist/validation/configValidator.js.map +1 -1
- package/index.ts +13 -0
- package/json/systemSchema.json +28 -0
- package/npm-shrinkwrap.json +151 -55
- package/package.json +14 -13
- package/resources/DESIGN.md +80 -100
- package/resources/DatabaseTransaction.ts +157 -10
- package/resources/PrimaryRocksDatabase.ts +2 -2
- package/resources/Table.ts +494 -101
- package/resources/auditStore.ts +18 -10
- package/resources/blob.ts +13 -6
- package/resources/branchDatabase.ts +3 -3
- package/resources/databaseDropPreparation.ts +120 -0
- package/resources/databases.ts +1155 -205
- package/resources/derivedIndexRegistry.ts +122 -0
- package/resources/derivedIndexRuntime.ts +157 -30
- package/resources/derivedIndexes.ts +856 -0
- package/resources/fullTextSchema.ts +55 -0
- package/resources/fullTextSchemaLifecycle.ts +0 -15
- package/resources/graphql.ts +107 -12
- package/resources/indexes/DESIGN.md +7 -0
- package/resources/indexes/hnswDerivedIndex.ts +0 -260
- package/resources/indexes/nativeFullTextDerivedIndexLifecycle.ts +72 -9
- package/resources/models/DESIGN.md +39 -0
- package/resources/models/Models.ts +361 -18
- package/resources/models/TestBackend.ts +56 -1
- package/resources/models/analyticsTable.ts +6 -4
- package/resources/models/backendHelpers.ts +17 -0
- package/resources/models/backendRegistry.ts +76 -21
- package/resources/models/bootstrap.ts +57 -7
- package/resources/models/decideHook.ts +135 -0
- package/resources/models/decision.ts +505 -0
- package/resources/models/decisionStore.ts +419 -0
- package/resources/models/embedHook.ts +272 -55
- package/resources/models/generativeDecision.ts +459 -0
- package/resources/models/types.ts +231 -4
- package/security/DESIGN.md +22 -2
- package/security/authn/oidc/tokenExchange.ts +6 -34
- package/security/authn/oidc/tokenUseTable.ts +27 -0
- package/security/certificateVerification/certificateVerificationSource.ts +2 -3
- package/security/certificateVerification/crlVerification.ts +96 -174
- package/security/certificateVerification/types.ts +0 -3
- package/security/certificateVerification/verificationTables.ts +124 -0
- package/security/certificateVerification/verificationUtils.ts +8 -32
- package/security/jsLoader.ts +9 -1
- package/server/DESIGN.md +27 -1
- package/server/Server.ts +2 -1
- package/server/http.ts +4 -2
- package/server/itc/serverHandlers.js +29 -1
- package/server/jobs/jobOwnership.ts +89 -0
- package/server/jobs/jobProcess.ts +8 -2
- package/server/jobs/jobs.ts +15 -4
- package/server/loadRootComponents.js +11 -0
- package/server/serverHelpers/contentTypes.ts +13 -1
- package/server/serverHelpers/serverHandlers.js +11 -2
- package/server/threads/itc.js +32 -6
- package/server/threads/manageThreads.js +268 -122
- package/server/threads/threadServer.js +13 -1
- package/server/threads/windowsProcessTree.ts +409 -0
- package/server/throttle.ts +11 -1
- package/studio/web/assets/{Chat-CveGbxe6.js → Chat-Bq60AO-g.js} +1 -1
- package/studio/web/assets/{FloatingChat-IpCFgYWL.js → FloatingChat-D4560T0p.js} +3 -3
- package/studio/web/assets/{apiToken-CS8fFTgL.js → apiToken-BEvbFPMc.js} +1 -1
- package/studio/web/assets/{applications-D7F4Jopl.js → applications-CSUVTH4E.js} +1 -1
- package/studio/web/assets/{cssMode-Daw_oLPq.js → cssMode-DJyc9mHj.js} +1 -1
- package/studio/web/assets/{editor-B3Bs1zWX.js → editor-DDIsQfj6.js} +1 -1
- package/studio/web/assets/{html-CDaQwWiE.js → html-g1BJHxLy.js} +1 -1
- package/studio/web/assets/{htmlMode-Cb6emO4U.js → htmlMode-Vh5IglCQ.js} +1 -1
- package/studio/web/assets/{index-B4g2Fu_2.js → index-DGRAzvO4.js} +5 -5
- package/studio/web/assets/{index.lazy-NwhvF1q1.js → index.lazy-vgSic7et.js} +1 -1
- package/studio/web/assets/{javascript-2_86gB9Q.js → javascript-5VIolqf7.js} +1 -1
- package/studio/web/assets/{jsonMode-DX-i86uQ.js → jsonMode-DG4zQraI.js} +1 -1
- package/studio/web/assets/{languageServices-B85WN-Ej.js → languageServices-t5FBpX-i.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-JCWHIsKg.js → lspLanguageFeatures-DgVnNPh-.js} +1 -1
- package/studio/web/assets/{notifications-D9ejzt52.js → notifications-BeWcX04m.js} +1 -1
- package/studio/web/assets/{notifications-B7hjKhai.js → notifications-DUGWrWoO.js} +1 -1
- package/studio/web/assets/{profile-D8B6No3F.js → profile-BvUEDBzW.js} +1 -1
- package/studio/web/assets/{regions-DFazIfTK.js → regions-CB-_2m7M.js} +1 -1
- package/studio/web/assets/{register-CwFLviLF.js → register-1w1Zr3b2.js} +2 -2
- package/studio/web/assets/{setComponentFile-VnJ80SSJ.js → setComponentFile-z4-qJCbA.js} +1 -1
- package/studio/web/assets/{setup-BYQxFy-C.js → setup-CS50uJ4x.js} +2 -2
- package/studio/web/assets/{status-Cn5XjmsL.js → status-CI0wOdOE.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-g9xIh6TX.js → toggleHighContrast-BsAE4jPe.js} +1 -1
- package/studio/web/assets/{tsMode-EC-n0Wqc.js → tsMode-D83Gg3cq.js} +1 -1
- package/studio/web/assets/{typescript-DHmM9JCO.js → typescript-Dfp-GrNq.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-BUdnVSVv.js → useEntityRestURL-BKetlINf.js} +1 -1
- package/studio/web/assets/{workers-BVl9bBB-.js → workers-CCvmDLH3.js} +1 -1
- package/studio/web/assets/{xml-C4_sqOkX.js → xml-06pZp00U.js} +1 -1
- package/studio/web/assets/{yaml-CVkbDqtW.js → yaml-iSnWMVlV.js} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/directives/5-3-0.ts +61 -54
- package/utility/DESIGN.md +5 -1
- package/utility/errors/hdbError.ts +56 -8
- package/utility/fsync.ts +16 -0
- package/utility/hdbTerms.ts +3 -0
- package/utility/signalling.ts +33 -4
- package/utility/when.ts +22 -0
- package/validation/configValidator.ts +36 -7
|
@@ -11,8 +11,19 @@ export interface Models {
|
|
|
11
11
|
embed(input: string | string[], opts?: EmbedOpts): Promise<Float32Array[]>;
|
|
12
12
|
generate(input: GenerateInput, opts?: GenerateOpts): Promise<GenerateResult>;
|
|
13
13
|
generateStream(input: GenerateInput, opts?: GenerateOpts): AsyncIterable<GenerateChunk>;
|
|
14
|
+
/** Choose from a closed, schema-defined set and return the distribution over it. See #2779. */
|
|
15
|
+
decide<T = unknown>(
|
|
16
|
+
state: DecideInput,
|
|
17
|
+
schema: DecisionSchema,
|
|
18
|
+
opts: RecordedDecideOpts
|
|
19
|
+
): Promise<RecordedDecision<T>>;
|
|
20
|
+
decide<T = unknown>(state: DecideInput, schema: DecisionSchema, opts?: DecideOpts): Promise<Decision<T>>;
|
|
21
|
+
/** The durable record of a decision made with `persist: true`, with its recorded outcome, or undefined. See #2840. */
|
|
22
|
+
getDecision<T = unknown>(id: string): Promise<DecisionRecord<T> | undefined>;
|
|
23
|
+
/** Record what actually happened for a decision: its truth, the action taken, or both. See #2840. */
|
|
24
|
+
recordOutcome<T = unknown>(id: string, outcome: OutcomeReport): Promise<DecisionRecord<T>>;
|
|
14
25
|
/** Register a custom backend under a logical id, selectable via `opts.model`. See #1325. */
|
|
15
|
-
registerBackend(kind:
|
|
26
|
+
registerBackend(kind: ModelKind, id: string, backend: ModelBackend): void;
|
|
16
27
|
/** Build a `ModelBackend` from a spec; pair with `registerBackend`. See #1325. */
|
|
17
28
|
defineBackend(spec: DefineBackendSpec): ModelBackend;
|
|
18
29
|
/** Replace the model selection policy with a custom router. See #1326. */
|
|
@@ -25,22 +36,62 @@ export interface ModelBackend {
|
|
|
25
36
|
embed?(input: string | string[], opts: BackendOpts<EmbedOpts>): Promise<ModelCallResult<Float32Array[]>>;
|
|
26
37
|
generate?(input: GenerateInput, opts: BackendOpts<GenerateOpts>): Promise<ModelCallResult<GenerateResult>>;
|
|
27
38
|
generateStream?(input: GenerateInput, opts: BackendOpts<GenerateOpts>): AsyncIterable<GenerateChunk>;
|
|
39
|
+
decide?(
|
|
40
|
+
state: DecideInput,
|
|
41
|
+
schema: DecisionSchema,
|
|
42
|
+
opts: BackendOpts<DecideOpts>
|
|
43
|
+
): Promise<ModelCallResult<DecisionOutput<unknown>>>;
|
|
44
|
+
/**
|
|
45
|
+
* Score every entry of `choices` as the answer to `input` from the model's own likelihoods
|
|
46
|
+
* (#2838): one finite, unnormalized log-likelihood per choice, in order. A call the backend
|
|
47
|
+
* cannot score (too many choices for its alternatives list, a model that rejects
|
|
48
|
+
* log-probabilities, a response with no scored label) throws `ChoiceScoringUnsupportedError`
|
|
49
|
+
* so the caller can fall back; any other error is a failure.
|
|
50
|
+
*/
|
|
51
|
+
scoreChoices?(
|
|
52
|
+
input: GenerateInput,
|
|
53
|
+
choices: readonly string[],
|
|
54
|
+
opts: BackendOpts<ScoreChoicesOpts>
|
|
55
|
+
): Promise<ModelCallResult<ChoiceScores>>;
|
|
28
56
|
}
|
|
29
57
|
|
|
58
|
+
/** Registry kinds a backend is mapped under; a `decision` backend implements `decide` (#2779). */
|
|
59
|
+
export type ModelKind = 'embedding' | 'generative' | 'decision';
|
|
60
|
+
|
|
30
61
|
export interface ModelCapabilities {
|
|
31
62
|
embed: boolean;
|
|
32
63
|
generate: boolean;
|
|
33
64
|
stream: boolean;
|
|
34
65
|
tools: boolean;
|
|
35
66
|
adapters: boolean;
|
|
67
|
+
/** Implements `decide`. Optional so pre-#2779 backends stay source-compatible; absent reads as false. */
|
|
68
|
+
decide?: boolean;
|
|
69
|
+
/** `decide` probabilities are calibrated as returned. Absent reads as false. */
|
|
70
|
+
calibrated?: boolean;
|
|
71
|
+
/** Implements `scoreChoices`. Absent reads as false. */
|
|
72
|
+
scoreChoices?: boolean;
|
|
73
|
+
/** `decide` returns a no-match score for leaves that opt in with `noMatch: true` (#2846). Absent reads as false. */
|
|
74
|
+
noMatch?: boolean;
|
|
75
|
+
/** That no-match score is calibrated as returned. Absent reads as false. */
|
|
76
|
+
calibratedNoMatch?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* `generate` sends `responseFormat: { schema }` to the provider as a decoding constraint rather
|
|
79
|
+
* than a hint. Says what Harper sends, not what a remote endpoint honors. Absent reads as false.
|
|
80
|
+
*/
|
|
81
|
+
structuredOutput?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* The most choices one `scoreChoices` call accepts. Absent means no stated limit. A limit, not a
|
|
84
|
+
* capability: it cannot be required, and a call above it is declined without a request.
|
|
85
|
+
*/
|
|
86
|
+
maxScoredChoices?: number;
|
|
36
87
|
}
|
|
37
88
|
|
|
38
|
-
/** A capability a call can require of its backend (a key of `ModelCapabilities`). */
|
|
39
|
-
export type Capability = keyof ModelCapabilities
|
|
89
|
+
/** A capability a call can require of its backend (a boolean key of `ModelCapabilities`). */
|
|
90
|
+
export type Capability = Exclude<keyof ModelCapabilities, 'maxScoredChoices'>;
|
|
40
91
|
|
|
41
92
|
/** What the router is asked to resolve for a single call. See #1326. */
|
|
42
93
|
export interface RouteRequest {
|
|
43
|
-
kind:
|
|
94
|
+
kind: ModelKind;
|
|
44
95
|
/** Logical name from `opts.model` (a role or a concrete backend id); defaults to `'default'`. */
|
|
45
96
|
logicalName: string;
|
|
46
97
|
/** Capabilities the chosen backend must satisfy — explicit `opts.requires` plus any auto-derived (e.g. tools present in the input). */
|
|
@@ -74,10 +125,22 @@ export interface DefineBackendSpec {
|
|
|
74
125
|
embed?: ModelBackend['embed'];
|
|
75
126
|
generate?: ModelBackend['generate'];
|
|
76
127
|
generateStream?: ModelBackend['generateStream'];
|
|
128
|
+
decide?: ModelBackend['decide'];
|
|
129
|
+
scoreChoices?: ModelBackend['scoreChoices'];
|
|
77
130
|
/** Backend supports tool calls in `generate` / `generateStream`. Default `false`. */
|
|
78
131
|
tools?: boolean;
|
|
79
132
|
/** Backend supports per-call LoRA / adapter selection. Default `false`. */
|
|
80
133
|
adapters?: boolean;
|
|
134
|
+
/** `decide` probabilities are calibrated as returned. Default `false`. */
|
|
135
|
+
calibrated?: boolean;
|
|
136
|
+
/** `decide` returns a no-match score for opted-in leaves. Default `false`. */
|
|
137
|
+
noMatch?: boolean;
|
|
138
|
+
/** That no-match score is calibrated as returned. Default `false`. */
|
|
139
|
+
calibratedNoMatch?: boolean;
|
|
140
|
+
/** `generate` sends `responseFormat: { schema }` as a decoding constraint. Default `false`. */
|
|
141
|
+
structuredOutput?: boolean;
|
|
142
|
+
/** The most choices one `scoreChoices` call accepts, a positive integer. Default: no limit. */
|
|
143
|
+
maxScoredChoices?: number;
|
|
81
144
|
}
|
|
82
145
|
|
|
83
146
|
export type EmbedOpts = {
|
|
@@ -89,6 +152,170 @@ export type EmbedOpts = {
|
|
|
89
152
|
signal?: AbortSignal;
|
|
90
153
|
};
|
|
91
154
|
|
|
155
|
+
/** Text, or JSON-serializable program state, for `decide`. */
|
|
156
|
+
export type DecideInput = string | object;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* One leaf of a decision schema: a closed set every backend family can score. `enum` holds
|
|
160
|
+
* 2..255 distinct values of one type; an integer range spans at most 255 values; booleans order
|
|
161
|
+
* as `[false, true]` for tie-breaking.
|
|
162
|
+
*/
|
|
163
|
+
export type DecisionLeaf = { description?: string; noMatch?: boolean } & (
|
|
164
|
+
| { enum: readonly string[] | readonly number[] | readonly boolean[] }
|
|
165
|
+
| { type: 'boolean' }
|
|
166
|
+
| { type: 'integer'; minimum: number; maximum: number }
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
/** A decision schema: one leaf, or one level of named leaves. Deeper nesting is deliberately unsupported. */
|
|
170
|
+
export type DecisionSchema =
|
|
171
|
+
DecisionLeaf | { type: 'object'; description?: string; properties: Record<string, DecisionLeaf> };
|
|
172
|
+
|
|
173
|
+
export type DecideOpts = {
|
|
174
|
+
model?: string;
|
|
175
|
+
/** Capabilities the chosen backend must satisfy, e.g. `['calibrated']`; the router filters candidates (#1326). */
|
|
176
|
+
requires?: Capability[];
|
|
177
|
+
/** Task framing beyond the schema's own descriptions. */
|
|
178
|
+
instructions?: string;
|
|
179
|
+
signal?: AbortSignal;
|
|
180
|
+
/**
|
|
181
|
+
* `true` commits a durable record of the decision to `hdb_model_decisions` before returning, so its
|
|
182
|
+
* outcome can be recorded later; the result then carries its `id`. Default `false`: nothing is stored
|
|
183
|
+
* beyond the per-call analytics row, as with `embed` and `generate`.
|
|
184
|
+
*/
|
|
185
|
+
persist?: boolean;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/** Options that record the decision, so the result is a `RecordedDecision` with an `id`. */
|
|
189
|
+
export type RecordedDecideOpts = DecideOpts & { persist: true };
|
|
190
|
+
|
|
191
|
+
export interface DecisionOutcome {
|
|
192
|
+
value: unknown;
|
|
193
|
+
probability: number;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* What a `decision` backend returns for one call. For a leaf schema `distribution` is required
|
|
198
|
+
* and complete (one entry per allowed value, summing to one); for an object schema `fields`
|
|
199
|
+
* carries one such entry per property. The facade derives `value` and `probability`, so a
|
|
200
|
+
* backend may omit them; a `value` it does supply must be a most-probable outcome, and on a
|
|
201
|
+
* tie it leads the distribution.
|
|
202
|
+
*/
|
|
203
|
+
export interface DecisionOutput<T = unknown> {
|
|
204
|
+
value?: T;
|
|
205
|
+
probability?: number;
|
|
206
|
+
distribution?: DecisionOutcome[];
|
|
207
|
+
fields?: Record<string, DecisionOutput<unknown>>;
|
|
208
|
+
/** For a leaf that opted in: the score in [0, 1] that the input matches none of the allowed values. */
|
|
209
|
+
noMatch?: number;
|
|
210
|
+
calibrated?: boolean;
|
|
211
|
+
/**
|
|
212
|
+
* Opaque identity of the configuration that produced the scores (sampling, scoring method,
|
|
213
|
+
* prompt revision), stored with the decision so calibration is keyed per configuration (#2841).
|
|
214
|
+
*/
|
|
215
|
+
signature?: string;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Result of `models.decide`. For a leaf schema `value` is the first entry of `distribution`,
|
|
220
|
+
* which is sorted descending with ties in schema order unless the backend chose one of the tied
|
|
221
|
+
* values; `probability` is its entry. For an object schema
|
|
222
|
+
* `value` is assembled from each field's marginal argmax — a combination no single sample may
|
|
223
|
+
* have produced — and the marginals live in `fields`.
|
|
224
|
+
*/
|
|
225
|
+
export interface Decision<T = unknown> {
|
|
226
|
+
/** Present only when the call passed `persist: true`: the cluster-unique id of the decision's record in `hdb_model_decisions`, committed before the decision is returned; pass it to `recordOutcome` (#2840). */
|
|
227
|
+
id?: string;
|
|
228
|
+
value: T;
|
|
229
|
+
probability?: number;
|
|
230
|
+
distribution?: DecisionOutcome[];
|
|
231
|
+
fields?: Record<string, FieldDecision>;
|
|
232
|
+
/** Leaf schemas that opted in: the score that the input matches none of the allowed values (#2846). */
|
|
233
|
+
noMatch?: number;
|
|
234
|
+
/** Whether the probabilities come from a calibrated source, as the backend reports it. */
|
|
235
|
+
calibrated: boolean;
|
|
236
|
+
usage?: TokenUsage;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** A decision made with `persist: true`: its `id` is always present. */
|
|
240
|
+
export type RecordedDecision<T = unknown> = Decision<T> & { id: string };
|
|
241
|
+
|
|
242
|
+
/** One field's marginal in an object-schema `Decision`. */
|
|
243
|
+
export interface FieldDecision {
|
|
244
|
+
value: unknown;
|
|
245
|
+
probability: number;
|
|
246
|
+
distribution: DecisionOutcome[];
|
|
247
|
+
/** Fields that opted in: the no-match score. */
|
|
248
|
+
noMatch?: number;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export type ScoreChoicesOpts = {
|
|
252
|
+
model?: string;
|
|
253
|
+
/** Capabilities the chosen backend must satisfy, beyond `scoreChoices` itself; the router filters candidates (#1326). */
|
|
254
|
+
requires?: Capability[];
|
|
255
|
+
signal?: AbortSignal;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/** Unnormalized; the caller normalizes. */
|
|
259
|
+
export interface ChoiceScores {
|
|
260
|
+
logLikelihoods: number[];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** What turned out to be true for a decision: an allowed value, none of them, or not known. Tagged, so no label is a sentinel. */
|
|
264
|
+
export type OutcomeTruth = { kind: 'value'; value: unknown } | { kind: 'noMatch' } | { kind: 'unknown' };
|
|
265
|
+
|
|
266
|
+
/** What the application did with a decision: acted on a value, routed it as no-match, abstained by policy, or not known. */
|
|
267
|
+
export type OutcomeAction =
|
|
268
|
+
{ kind: 'value'; value: unknown } | { kind: 'noMatch' } | { kind: 'abstained' } | { kind: 'unknown' };
|
|
269
|
+
|
|
270
|
+
/** The facts reported for one leaf: either, or both. Each is stored on its own, so reports never overwrite each other. */
|
|
271
|
+
export interface LeafOutcomeReport {
|
|
272
|
+
truth?: OutcomeTruth;
|
|
273
|
+
action?: OutcomeAction;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** A `recordOutcome` report: leaf facts for a leaf schema, or per-field facts for an object schema. */
|
|
277
|
+
export type OutcomeReport = LeafOutcomeReport | { fields: Record<string, LeafOutcomeReport> };
|
|
278
|
+
|
|
279
|
+
export interface RecordedLeafOutcome extends LeafOutcomeReport {
|
|
280
|
+
truthAt?: number;
|
|
281
|
+
actionAt?: number;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export type RecordedOutcome = RecordedLeafOutcome | { fields: Record<string, RecordedLeafOutcome> };
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* The durable record of one decision (#2840): what was asked, what was answered, who answered,
|
|
288
|
+
* and what was recorded afterwards. Written once by `decide`; only `outcome` grows.
|
|
289
|
+
*/
|
|
290
|
+
export interface DecisionRecord<T = unknown> {
|
|
291
|
+
id: string;
|
|
292
|
+
/** The `hdb_model_calls` row of the call that produced it; correlation only. */
|
|
293
|
+
callId: number;
|
|
294
|
+
at: number;
|
|
295
|
+
/** When the record and its facts expire; a fact never extends it. */
|
|
296
|
+
expiresAt: number;
|
|
297
|
+
tenant?: string;
|
|
298
|
+
app?: string;
|
|
299
|
+
backend: string;
|
|
300
|
+
model: string;
|
|
301
|
+
signature?: string;
|
|
302
|
+
/** Identity of the `models` config block in force when the decision was made. */
|
|
303
|
+
configHash?: string;
|
|
304
|
+
/** sha256 of the per-call `instructions`, when any were given. */
|
|
305
|
+
instructionsHash?: string;
|
|
306
|
+
/** The schema's allowed values, without descriptions. */
|
|
307
|
+
schema: DecisionSchema;
|
|
308
|
+
/** Identity of the full schema, descriptions included. */
|
|
309
|
+
schemaHash: string;
|
|
310
|
+
value: T;
|
|
311
|
+
probability?: number;
|
|
312
|
+
distribution?: DecisionOutcome[];
|
|
313
|
+
fields?: Record<string, FieldDecision>;
|
|
314
|
+
noMatch?: number;
|
|
315
|
+
calibrated: boolean;
|
|
316
|
+
outcome: RecordedOutcome;
|
|
317
|
+
}
|
|
318
|
+
|
|
92
319
|
export type GenerateOpts = {
|
|
93
320
|
model?: string;
|
|
94
321
|
/** Capabilities the chosen backend must satisfy (e.g. `['tools']`); the router selects/filters candidates accordingly. Tools present in the input are auto-required. (#1326) */
|
package/security/DESIGN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Authentication tokens, OIDC exchange and TLS material.
|
|
4
4
|
|
|
5
|
-
**Read this when:** touching `tokenAuthentication.ts`, `impersonation.ts`, `authn/oidc
|
|
5
|
+
**Read this when:** touching `tokenAuthentication.ts`, `impersonation.ts`, `authn/oidc/`, `keys.ts` or `certificateVerification/`.
|
|
6
6
|
|
|
7
7
|
Index of every design note: [DESIGN.md](../DESIGN.md).
|
|
8
8
|
|
|
@@ -33,7 +33,7 @@ Four constraints that look like choices but are not:
|
|
|
33
33
|
|
|
34
34
|
Naming `sql` in a scope grants the SQL interface, not unrestricted DML through it: a write statement additionally requires its matching data operation (`insert`/`update`/`delete`) in scope. That is what keeps `read_only` — which expands to include `sql` — from admitting a DELETE, given that `verifyPermsAST` returns early for a super_user before any table check runs.
|
|
35
35
|
|
|
36
|
-
`hdb_oidc_token_use` (
|
|
36
|
+
`hdb_oidc_token_use` (declared on every node at every start by `tokenUseTable.ts`, so a node that never exchanges still removes the rows replicated to it — see dataLayer/DESIGN.md, "System table bootstrap") records spent tokens keyed on a SHA-256 of the token itself, each expiring (record metadata, replicated with the row) past the token's own expiry. Hashed rather than stored, so the table never holds a credential; keyed on the token's **signed input** (`header.payload`) rather than `jti` because not every issuer emits one (Azure uses `uti`). Not on the whole token string: the signature segment is covered by nothing, and base64url decoding ignores the surplus low bits of its final character, so 16 distinct spellings of an RS256 signature decode to the same bytes, all verify, and all hash differently — one leaked token would buy 16 exchanges. ES\* malleability (`s → n−s`) is a second such vector. The signed input is exactly what the issuer asserted, so every variant collapses to one fingerprint. The get-then-put is not atomic and does not claim to be: a concurrent replay is not a privilege escalation, since whoever holds the token could obtain one operation token anyway.
|
|
37
37
|
|
|
38
38
|
## Scoped tokens and synthetic-role identity (`security/tokenAuthentication.ts`, `security/impersonation.ts`)
|
|
39
39
|
|
|
@@ -150,6 +150,26 @@ the latch back on a synchronous throw or a rejected callback promise (equality-g
|
|
|
150
150
|
rejection cannot unlatch a newer reload) — the latch means "last successfully applied", so the
|
|
151
151
|
periodic poll can heal a lost `hdb_certificate` write instead of deduplicating it forever.
|
|
152
152
|
|
|
153
|
+
## Client-certificate revocation checking keeps three tables (`security/certificateVerification/`)
|
|
154
|
+
|
|
155
|
+
`verificationTables.ts` declares them, and every writable start and the verification path apply the same
|
|
156
|
+
declarations (dataLayer/DESIGN.md, "System table bootstrap"). A row's expiry is record metadata; a table's
|
|
157
|
+
`expiration` is only the fallback for a row written without one.
|
|
158
|
+
|
|
159
|
+
- A verdict (`hdb_certificate_cache`) expires `cacheTtl` after its check because `CertificateVerificationSource`
|
|
160
|
+
sets `context.expiresAt`: a caching table decides staleness by the stored expiry, and a source fill stores
|
|
161
|
+
`sourceContext.expiresAt`, never a field the source returns. `createCacheKey` hashes a key version, so a
|
|
162
|
+
verdict cached before verdicts carried an expiry, which has none and would read as fresh forever, is never
|
|
163
|
+
read again.
|
|
164
|
+
- A revocation (`hdb_revoked_certificates`) lives until `crl_next_update + gracePeriod`, the window
|
|
165
|
+
`performCRLCheck` honors while it decides by `crl_next_update`. Expiring it at `nextUpdate` made that branch
|
|
166
|
+
unreachable and reported a revoked certificate on an overdue CRL as good.
|
|
167
|
+
- A CRL's revocations replace the previous set all or nothing, in a transaction of their own rather than the
|
|
168
|
+
verdict fill's `performCRLCheck` runs in, so other checks see a complete set once it commits. The check that
|
|
169
|
+
downloaded the CRL decides from the CRL itself: by the time it could read the table, another worker may have
|
|
170
|
+
replaced the set with a different generation of that CRL. A check answered by a cached CRL reads the table
|
|
171
|
+
outside the verdict fill's transaction, whose LMDB snapshot misses rows committed after it.
|
|
172
|
+
|
|
153
173
|
## A component-facing export needs BOTH `index.ts` and `getHarperExports` (`security/jsLoader.ts`, `index.ts`)
|
|
154
174
|
|
|
155
175
|
Adding `export { x } from './…'` to `index.ts` publishes `x` on the `harper` **package** but does not
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
import jwt from 'jsonwebtoken';
|
|
11
11
|
import Joi from 'joi';
|
|
12
12
|
import { createHash } from 'node:crypto';
|
|
13
|
-
import { table, type Table } from '../../../resources/databases.ts';
|
|
14
13
|
import { ClientError } from '../../../utility/errors/hdbError.ts';
|
|
15
14
|
import { validateBySchema } from '../../../validation/validationWrapper.ts';
|
|
16
15
|
import { loggerWithTag } from '../../../utility/logging/logger.ts';
|
|
@@ -24,6 +23,7 @@ import { matchTrustPolicyClaims } from './claims.ts';
|
|
|
24
23
|
import { normalizeIssuer } from './jwks.ts';
|
|
25
24
|
import { profileForIssuer, type IdentityProviderProfile } from './providers/index.ts';
|
|
26
25
|
import { loadEnabledPolicies } from './trustPolicyOperations.ts';
|
|
26
|
+
import { declareTokenUseTable } from './tokenUseTable.ts';
|
|
27
27
|
import type { OidcTrustPolicy, TokenClaims } from './types.ts';
|
|
28
28
|
|
|
29
29
|
const logger = loggerWithTag('oidc-trust');
|
|
@@ -41,8 +41,6 @@ const REPLAY_RECORD_PADDING_MS = 120_000;
|
|
|
41
41
|
/** Real identity tokens are ~1-2 KB; this bounds what we are willing to even parse. */
|
|
42
42
|
const MAX_TOKEN_LENGTH = 8192;
|
|
43
43
|
|
|
44
|
-
const TOKEN_USE_TABLE = 'hdb_oidc_token_use';
|
|
45
|
-
|
|
46
44
|
/**
|
|
47
45
|
* Spent identity tokens, keyed by the fingerprint below and expiring with the token, so the table
|
|
48
46
|
* stays proportional to in-flight tokens rather than to deploy history and never holds a credential.
|
|
@@ -52,8 +50,6 @@ const TOKEN_USE_TABLE = 'hdb_oidc_token_use';
|
|
|
52
50
|
* not a privilege escalation: whoever holds the token could obtain one operation token regardless.
|
|
53
51
|
* What it stops is the realistic case, a token that leaks after a legitimate run and is reused
|
|
54
52
|
* inside its window.
|
|
55
|
-
*
|
|
56
|
-
* table() also registers into `databases.system`, so the lookup finds it after the first call.
|
|
57
53
|
*/
|
|
58
54
|
let tokenUseTable: any;
|
|
59
55
|
|
|
@@ -63,29 +59,7 @@ export function clearTokenUseTableCache(): void {
|
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
function getTokenUseTable(): any {
|
|
66
|
-
|
|
67
|
-
// The systemSchema stub and the 5.3.0 directive declare only the primary key — the `expiresAt`
|
|
68
|
-
// TTL is not expressible through CreateTableObject — so this call is what actually installs the
|
|
69
|
-
// TTL, layered on top of the bootstrap. Short-circuiting on existence would mean a table that
|
|
70
|
-
// arrived any other way (bootstrap, replication, restore, a manual create_table) never gets it,
|
|
71
|
-
// and replay records would then accumulate in a system table forever. hdb_certificate_cache
|
|
72
|
-
// does the same two-step for the same reason.
|
|
73
|
-
tokenUseTable ??= table<Table>({
|
|
74
|
-
table: TOKEN_USE_TABLE,
|
|
75
|
-
database: 'system',
|
|
76
|
-
// `audit: true` explicitly, NOT the default (which follows logging.auditLog). Auditing is the
|
|
77
|
-
// replication change feed (databases.ts: "auditing must be enabled for replication"), and
|
|
78
|
-
// replay records MUST replicate so a token spent on one node cannot be re-spent on another
|
|
79
|
-
// inside its window. Without this, an operator with logging.auditLog:false would silently lose
|
|
80
|
-
// cross-node replay protection. Its sibling hdb_oidc_trust is audited for the same reason.
|
|
81
|
-
audit: true,
|
|
82
|
-
attributes: [
|
|
83
|
-
{ name: 'id', isPrimaryKey: true },
|
|
84
|
-
{ name: 'policy_id' },
|
|
85
|
-
{ name: 'used_at' },
|
|
86
|
-
{ name: 'expiresAt', expiresAt: true, indexed: true },
|
|
87
|
-
],
|
|
88
|
-
});
|
|
62
|
+
tokenUseTable ??= declareTokenUseTable();
|
|
89
63
|
return tokenUseTable;
|
|
90
64
|
}
|
|
91
65
|
|
|
@@ -216,12 +190,10 @@ async function recordTokenUse(fingerprint: string, claims: TokenClaims, policyId
|
|
|
216
190
|
const useTable = getTokenUseTable();
|
|
217
191
|
if (await useTable.get(fingerprint)) rejectToken(`token ${fingerprint.slice(0, 12)} has already been exchanged`);
|
|
218
192
|
|
|
219
|
-
await useTable.put(
|
|
220
|
-
id: fingerprint,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
expiresAt: (claims.exp as number) * 1000 + REPLAY_RECORD_PADDING_MS,
|
|
224
|
-
});
|
|
193
|
+
await useTable.put(
|
|
194
|
+
{ id: fingerprint, policy_id: policyId, used_at: Date.now() },
|
|
195
|
+
{ expiresAt: (claims.exp as number) * 1000 + REPLAY_RECORD_PADDING_MS }
|
|
196
|
+
);
|
|
225
197
|
}
|
|
226
198
|
|
|
227
199
|
/**
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every node must declare system.hdb_oidc_token_use in this shape whether or not it ever performs an
|
|
3
|
+
* exchange: passive cluster members receive every replicated replay row, and only an `expiration` stored
|
|
4
|
+
* in the node's own catalog arms the cleanup scan that removes them. See dataLayer/DESIGN.md, "System
|
|
5
|
+
* table bootstrap".
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { table, type Table } from '../../../resources/databases.ts';
|
|
9
|
+
import { SYSTEM_SCHEMA_NAME, SYSTEM_TABLE_NAMES } from '../../../utility/hdbTerms.ts';
|
|
10
|
+
|
|
11
|
+
export const TOKEN_USE_TABLE = SYSTEM_TABLE_NAMES.OIDC_TOKEN_USE_TABLE_NAME;
|
|
12
|
+
|
|
13
|
+
/** Bounds only a row written without an expiry of its own; each replay record carries its token's. */
|
|
14
|
+
const FALLBACK_EXPIRATION_SECONDS = 86_400;
|
|
15
|
+
|
|
16
|
+
export function declareTokenUseTable(): Table {
|
|
17
|
+
return table<Table>({
|
|
18
|
+
table: TOKEN_USE_TABLE,
|
|
19
|
+
database: SYSTEM_SCHEMA_NAME,
|
|
20
|
+
// Explicit rather than the logging.auditLog default: auditing is the replication change feed, and a
|
|
21
|
+
// token spent on one node must be refused on the others.
|
|
22
|
+
audit: true,
|
|
23
|
+
schemaDefined: true,
|
|
24
|
+
expiration: FALLBACK_EXPIRATION_SECONDS,
|
|
25
|
+
attributes: [{ name: 'id', isPrimaryKey: true }, { name: 'policy_id' }, { name: 'used_at' }],
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -69,15 +69,14 @@ export class CertificateVerificationSource extends Resource {
|
|
|
69
69
|
throw new Error(`Unsupported verification method: ${method} for ID: ${id}`);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
//
|
|
73
|
-
|
|
72
|
+
// without a cacheTtl, the table's expiration applies rather than none
|
|
73
|
+
if (Number.isFinite(methodConfig.cacheTtl)) context.expiresAt = Date.now() + methodConfig.cacheTtl;
|
|
74
74
|
|
|
75
75
|
return {
|
|
76
76
|
certificate_id: id,
|
|
77
77
|
status: result.status,
|
|
78
78
|
reason: result.reason,
|
|
79
79
|
checked_at: Date.now(),
|
|
80
|
-
expiresAt,
|
|
81
80
|
method,
|
|
82
81
|
};
|
|
83
82
|
}
|