@intx/db 0.2.2 → 0.4.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/README.md +13 -2
- package/dist/approval-store.d.ts +59 -0
- package/dist/approval-store.js +92 -0
- package/dist/asset-resolution.d.ts +2 -2
- package/dist/backfill-principal-keys.d.ts +9 -0
- package/dist/backfill-principal-keys.js +51 -0
- package/dist/client.d.ts +37 -2
- package/dist/client.js +6 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -0
- package/dist/connection.js +12 -8
- package/dist/credential-resolution.d.ts +181 -20
- package/dist/credential-resolution.js +251 -3
- package/dist/grant-store.js +35 -13
- package/dist/index.d.ts +20 -5
- package/dist/index.js +19 -5
- package/dist/model-source-resolution.d.ts +54 -7
- package/dist/model-source-resolution.js +177 -22
- package/dist/parse-row.d.ts +245 -34
- package/dist/parse-row.js +117 -18
- package/dist/principal-key-store.d.ts +51 -0
- package/dist/principal-key-store.js +82 -0
- package/dist/principal-store.d.ts +44 -0
- package/dist/principal-store.js +67 -0
- package/dist/rekey-credential-secrets.d.ts +13 -0
- package/dist/rekey-credential-secrets.js +61 -0
- package/dist/schema/approvals.d.ts +245 -0
- package/dist/schema/approvals.js +57 -0
- package/dist/schema/catalog.d.ts +17 -0
- package/dist/schema/catalog.js +7 -1
- package/dist/schema/credentials.d.ts +1 -1
- package/dist/schema/git-tokens.js +1 -1
- package/dist/schema/grants.js +8 -2
- package/dist/schema/index.d.ts +10 -4
- package/dist/schema/index.js +10 -4
- package/dist/schema/messages.d.ts +5 -5
- package/dist/schema/messages.js +20 -9
- package/dist/schema/offerings.js +8 -2
- package/dist/schema/{workflow-deployments.d.ts → principal-keys.d.ts} +29 -32
- package/dist/schema/principal-keys.js +28 -0
- package/dist/schema/principals.d.ts +2 -2
- package/dist/schema/principals.js +7 -5
- package/dist/schema/providers.d.ts +17 -0
- package/dist/schema/providers.js +5 -0
- package/dist/schema/roles.js +6 -2
- package/dist/schema/session-assets.d.ts +1 -38
- package/dist/schema/session-assets.js +36 -19
- package/dist/schema/sessions.js +7 -2
- package/dist/schema/sidecar-allocation.d.ts +385 -0
- package/dist/schema/sidecar-allocation.js +53 -0
- package/dist/schema/sidecar.d.ts +2 -2
- package/dist/schema/sidecar.js +3 -1
- package/dist/schema/signal-correlations.d.ts +177 -0
- package/dist/schema/signal-correlations.js +31 -0
- package/dist/schema/tenants.js +13 -3
- package/dist/schema/wallets.d.ts +3 -3
- package/dist/schema/wallets.js +4 -2
- package/dist/schema/{agents.d.ts → workflow-definitions.d.ts} +79 -113
- package/dist/schema/workflow-definitions.js +97 -0
- package/dist/schema/workflow-probe.d.ts +358 -0
- package/dist/schema/workflow-probe.js +51 -0
- package/dist/schema/workflow-run-dispatch.d.ts +345 -0
- package/dist/schema/workflow-run-dispatch.js +63 -0
- package/dist/schema/{agent-assets.d.ts → workflow-run-execution.d.ts} +44 -27
- package/dist/schema/workflow-run-execution.js +48 -0
- package/dist/schema/workflow-run-launch-spec.d.ts +200 -0
- package/dist/schema/workflow-run-launch-spec.js +26 -0
- package/dist/schema/{instances.d.ts → workflow-run.d.ts} +61 -66
- package/dist/schema/workflow-run.js +110 -0
- package/dist/sender-key-resolver.d.ts +91 -0
- package/dist/sender-key-resolver.js +184 -0
- package/dist/sidecar-allocation-store.d.ts +206 -0
- package/dist/sidecar-allocation-store.js +714 -0
- package/dist/signal-correlation-store.d.ts +36 -0
- package/dist/signal-correlation-store.js +63 -0
- package/dist/signer-identity.d.ts +12 -0
- package/dist/signer-identity.js +15 -0
- package/dist/tenant-hierarchy.d.ts +4 -1
- package/dist/tenant-hierarchy.js +37 -5
- package/dist/workflow-definition-store.d.ts +55 -0
- package/dist/workflow-definition-store.js +93 -0
- package/dist/workflow-probe-store.d.ts +47 -0
- package/dist/workflow-probe-store.js +124 -0
- package/dist/workflow-run-dispatch-store.d.ts +83 -0
- package/dist/workflow-run-dispatch-store.js +308 -0
- package/dist/workflow-run-launch-spec-store.d.ts +13 -0
- package/dist/workflow-run-launch-spec-store.js +30 -0
- package/dist/workflow-run-store.d.ts +54 -0
- package/dist/workflow-run-store.js +85 -0
- package/migrations/0037_credential_use_backfill.sql +39 -0
- package/migrations/0038_chilly_blacklash.sql +37 -0
- package/migrations/0039_quick_carnage.sql +2 -0
- package/migrations/0040_reshape_approval_origin.sql +24 -0
- package/migrations/0041_make_approval_timeout_at_nullable.sql +1 -0
- package/migrations/0042_youthful_mantis.sql +2 -0
- package/migrations/0043_signal_correlation_deployment_fk.sql +1 -0
- package/migrations/0044_model_offering_quirks.sql +1 -0
- package/migrations/0045_create_workflow_run.sql +13 -0
- package/migrations/0046_approval_signal_correlation_run_fk.sql +2 -0
- package/migrations/0047_create_workflow_definition.sql +30 -0
- package/migrations/0048_workflow_definition_origin_agent_id.sql +2 -0
- package/migrations/0049_curly_omega_flight.sql +2 -0
- package/migrations/0050_late_crystal.sql +10 -0
- package/migrations/0051_funny_madelyne_pryor.sql +1 -0
- package/migrations/0052_drop_inference_turn_instance_fk.sql +1 -0
- package/migrations/0053_session_mail_session_id_index.sql +1 -0
- package/migrations/0054_rekey_instance_grants_to_workflow_run.sql +10 -0
- package/migrations/0055_backfill_anchor_workflow_runs.sql +69 -0
- package/migrations/0056_repoint_deployment_fks_to_anchor_run.sql +32 -0
- package/migrations/0057_drop_workflow_deployment_projection.sql +22 -0
- package/migrations/0058_repoint_offering_fk_to_definition.sql +41 -0
- package/migrations/0059_repoint_transaction_fk_to_run.sql +10 -0
- package/migrations/0060_drop_session_mail_instance_fk.sql +6 -0
- package/migrations/0061_drop_session_asset_instance_fk.sql +7 -0
- package/migrations/0062_drop_agent_asset_table.sql +11 -0
- package/migrations/0063_repoint_agent_role_fk_to_definition.sql +39 -0
- package/migrations/0064_repoint_agent_session_fk_to_definition.sql +47 -0
- package/migrations/0065_add_workflow_definition_model_requirements.sql +37 -0
- package/migrations/0066_rekey_agent_definition_principals_to_workflow.sql +27 -0
- package/migrations/0067_add_workflow_definition_kind.sql +10 -0
- package/migrations/0068_drop_agent_tables_and_origin_agent_id.sql +31 -0
- package/migrations/0069_drop_workflow_definition_kind.sql +10 -0
- package/migrations/0070_flashy_proteus.sql +13 -0
- package/migrations/0072_add_workflow_definition_credential_bindings.sql +1 -0
- package/migrations/0073_grant_target_exactly_one_check.sql +13 -0
- package/migrations/0074_add_provider_api_base_url.sql +1 -0
- package/migrations/0075_workflow_run_launch_spec.sql +17 -0
- package/migrations/0076_sidecar_allocation.sql +40 -0
- package/migrations/0077_workflow_run_dispatch.sql +29 -0
- package/migrations/0078_workflow_run_dispatch_kind.sql +2 -0
- package/migrations/0079_rename_workflow_run_deployment_id_to_anchor_run_id.sql +4 -0
- package/migrations/0080_rename_correlation_approval_deployment_id_to_anchor_run_id.sql +9 -0
- package/migrations/0081_workflow_definition_content_hash_and_approved_wire_hash.sql +4 -0
- package/migrations/0082_blue_black_queen.sql +1 -0
- package/migrations/0083_replace_launch_spec_snapshot_with_frozen_bundle.sql +3 -0
- package/migrations/0084_delete_orphaned_credential_grants.sql +22 -0
- package/migrations/0085_add_approval_run_idx.sql +1 -0
- package/migrations/0086_cool_human_cannonball.sql +1 -0
- package/migrations/0087_drop_sidecar_placement.sql +3 -0
- package/migrations/0088_thick_sprite.sql +32 -0
- package/migrations/0089_tense_selene.sql +13 -0
- package/migrations/0090_tenant_domain_lower_unique.sql +2 -0
- package/migrations/0091_workflow_run_dispatch_sender_address.sql +21 -0
- package/migrations/0092_sidecar_destroy_failed.sql +4 -0
- package/migrations/0093_sidecar_initialization.sql +2 -0
- package/migrations/meta/0037_snapshot.json +3237 -0
- package/migrations/meta/0038_snapshot.json +3470 -0
- package/migrations/meta/0039_snapshot.json +3470 -0
- package/migrations/meta/0040_snapshot.json +3489 -0
- package/migrations/meta/0041_snapshot.json +3489 -0
- package/migrations/meta/0042_snapshot.json +3489 -0
- package/migrations/meta/0043_snapshot.json +3498 -0
- package/migrations/meta/0044_snapshot.json +3504 -0
- package/migrations/meta/0045_snapshot.json +3589 -0
- package/migrations/meta/0046_snapshot.json +3607 -0
- package/migrations/meta/0047_snapshot.json +3832 -0
- package/migrations/meta/0048_snapshot.json +3853 -0
- package/migrations/meta/0049_snapshot.json +3854 -0
- package/migrations/meta/0050_snapshot.json +3924 -0
- package/migrations/meta/0051_snapshot.json +3940 -0
- package/migrations/meta/0052_snapshot.json +3931 -0
- package/migrations/meta/0053_snapshot.json +3952 -0
- package/migrations/meta/0054_snapshot.json +3952 -0
- package/migrations/meta/0055_snapshot.json +3952 -0
- package/migrations/meta/0056_snapshot.json +3952 -0
- package/migrations/meta/0057_snapshot.json +3839 -0
- package/migrations/meta/0058_snapshot.json +3839 -0
- package/migrations/meta/0059_snapshot.json +3839 -0
- package/migrations/meta/0060_snapshot.json +3830 -0
- package/migrations/meta/0061_snapshot.json +3821 -0
- package/migrations/meta/0062_snapshot.json +3723 -0
- package/migrations/meta/0063_snapshot.json +3723 -0
- package/migrations/meta/0064_snapshot.json +3723 -0
- package/migrations/meta/0065_snapshot.json +3729 -0
- package/migrations/meta/0066_snapshot.json +3729 -0
- package/migrations/meta/0067_snapshot.json +3736 -0
- package/migrations/meta/0068_snapshot.json +3347 -0
- package/migrations/meta/0069_snapshot.json +3340 -0
- package/migrations/meta/0070_snapshot.json +3444 -0
- package/migrations/meta/0072_snapshot.json +3450 -0
- package/migrations/meta/0073_snapshot.json +3455 -0
- package/migrations/meta/0074_snapshot.json +3461 -0
- package/migrations/meta/0075_snapshot.json +3567 -0
- package/migrations/meta/0076_snapshot.json +3851 -0
- package/migrations/meta/0077_snapshot.json +4067 -0
- package/migrations/meta/0078_snapshot.json +4078 -0
- package/migrations/meta/0079_snapshot.json +4078 -0
- package/migrations/meta/0080_snapshot.json +4078 -0
- package/migrations/meta/0081_snapshot.json +4096 -0
- package/migrations/meta/0082_snapshot.json +4102 -0
- package/migrations/meta/0083_snapshot.json +4096 -0
- package/migrations/meta/0084_snapshot.json +4096 -0
- package/migrations/meta/0085_snapshot.json +4111 -0
- package/migrations/meta/0086_snapshot.json +4117 -0
- package/migrations/meta/0087_snapshot.json +4100 -0
- package/migrations/meta/0088_snapshot.json +4286 -0
- package/migrations/meta/0089_snapshot.json +4376 -0
- package/migrations/meta/0090_snapshot.json +4387 -0
- package/migrations/meta/0091_snapshot.json +4397 -0
- package/migrations/meta/0092_snapshot.json +4397 -0
- package/migrations/meta/0093_snapshot.json +4407 -0
- package/migrations/meta/_journal.json +392 -0
- package/package.json +7 -3
- package/dist/schema/agent-assets.js +0 -15
- package/dist/schema/agents.js +0 -57
- package/dist/schema/instances.js +0 -39
- package/dist/schema/workflow-deployments.js +0 -37
package/README.md
CHANGED
|
@@ -31,12 +31,23 @@ const row = await db.query.agent.findFirst({
|
|
|
31
31
|
});
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
The `parseRow` functions (`
|
|
35
|
-
on) validate each table's `jsonb` columns once and return fully
|
|
34
|
+
The `parseRow` functions (`parseWorkflowDefinitionRow`, `parseGrantRow`,
|
|
35
|
+
and so on) validate each table's `jsonb` columns once and return fully
|
|
36
36
|
typed values; downstream code uses those values without
|
|
37
37
|
re-casting. See `CONVENTIONS.md` for the project-wide rule against
|
|
38
38
|
cast-at-callsite in DB consumers.
|
|
39
39
|
|
|
40
|
+
Connections created by `createDB` set PostgreSQL's `statement_timeout` to
|
|
41
|
+
60,000 milliseconds. Override it with `statementTimeoutMs` in `DBConfig`
|
|
42
|
+
(a positive integer up to 2,147,483,647 milliseconds). The Hub and the
|
|
43
|
+
`bin/` database scripts read this override from `DB_STATEMENT_TIMEOUT_MS`.
|
|
44
|
+
|
|
45
|
+
PostgreSQL cancels statements that exceed the deadline, including time
|
|
46
|
+
waiting for locks. An uncaught timeout rolls back the enclosing transaction.
|
|
47
|
+
This bounds individual statements once they reach PostgreSQL; pool waits,
|
|
48
|
+
network stalls, and time between statements in an open transaction remain
|
|
49
|
+
outside that deadline. Migration clients use their own connection settings.
|
|
50
|
+
|
|
40
51
|
## Model catalog
|
|
41
52
|
|
|
42
53
|
The `model`, `model_provider`, `model_offering`, and `model_pricing`
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { DB, DBExecutor } from "./client.js";
|
|
2
|
+
import { approval } from "./schema/approvals.js";
|
|
3
|
+
import { parseApprovalRow } from "./parse-row.js";
|
|
4
|
+
type DBHandle = DB["db"];
|
|
5
|
+
type ApprovalRow = typeof approval.$inferSelect;
|
|
6
|
+
type ApprovalInsert = typeof approval.$inferInsert;
|
|
7
|
+
type ParsedApproval = ReturnType<typeof parseApprovalRow>;
|
|
8
|
+
type ApprovalResolution = Exclude<ApprovalRow["status"], "pending">;
|
|
9
|
+
type ApprovalScope = NonNullable<ApprovalRow["scope"]>;
|
|
10
|
+
export type ResolveApprovalArgs = {
|
|
11
|
+
status: ApprovalResolution;
|
|
12
|
+
scope?: ApprovalScope;
|
|
13
|
+
resolvedAt: Date;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Store for the `approval` table backing the approval round-trip. Each method
|
|
17
|
+
* accepts an optional transaction handle so the resolver can flip the approval
|
|
18
|
+
* and its signal correlation in a single `db.transaction`; when omitted the
|
|
19
|
+
* method runs against the store's own connection.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createApprovalStore(db: DBHandle): {
|
|
22
|
+
create(row: ApprovalInsert, tx?: DBExecutor): Promise<ParsedApproval>;
|
|
23
|
+
/**
|
|
24
|
+
* Idempotent variant of `create`. On a `correlationId` unique conflict the
|
|
25
|
+
* insert is a no-op and this returns `null` rather than throwing, so a
|
|
26
|
+
* redelivered register frame (sidecar reconnect, workflow-log replay,
|
|
27
|
+
* supervisor restart re-emitting) does not fail the co-write. Conflicts
|
|
28
|
+
* on `correlationId` -- not the `id` primary key -- because the register
|
|
29
|
+
* co-write mints a fresh `id` per frame while the correlation is the stable
|
|
30
|
+
* dedup key. Returns the parsed row only when this call performed the
|
|
31
|
+
* insert.
|
|
32
|
+
*/
|
|
33
|
+
createIfAbsent(row: ApprovalInsert, tx?: DBExecutor): Promise<ParsedApproval | null>;
|
|
34
|
+
findByCorrelationId(correlationId: string, tx?: DBExecutor): Promise<ParsedApproval | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Look up an approval by its primary key. The resolve/reject routes key on
|
|
37
|
+
* the `approvalId` path parameter, which is the row's `id`, so they need a
|
|
38
|
+
* by-id read distinct from the by-correlation read the register co-write
|
|
39
|
+
* uses. Returns null when no row carries the id.
|
|
40
|
+
*/
|
|
41
|
+
findById(id: string, tx?: DBExecutor): Promise<ParsedApproval | null>;
|
|
42
|
+
/**
|
|
43
|
+
* List a run's approvals, newest first, scoped by `tenantId` so one
|
|
44
|
+
* tenant's approvals never leak into another's view. Serves the run
|
|
45
|
+
* approvals list route; callers apply whatever status/scope predicate they
|
|
46
|
+
* need over the result.
|
|
47
|
+
*/
|
|
48
|
+
listByRunId(tenantId: string, runId: string, tx?: DBExecutor): Promise<ParsedApproval[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Conditionally resolve a pending approval. The `WHERE status = 'pending'`
|
|
51
|
+
* guard makes resolution terminal at the database: the first caller to
|
|
52
|
+
* resolve a given correlation gets the updated row back; any later caller
|
|
53
|
+
* (a duplicate delivery, a timeout racing an approval) matches no row and
|
|
54
|
+
* receives null.
|
|
55
|
+
*/
|
|
56
|
+
resolve(correlationId: string, args: ResolveApprovalArgs, tx?: DBExecutor): Promise<ParsedApproval | null>;
|
|
57
|
+
};
|
|
58
|
+
export type ApprovalStore = ReturnType<typeof createApprovalStore>;
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { and, eq } from "drizzle-orm";
|
|
2
|
+
import { approval } from "./schema/approvals.js";
|
|
3
|
+
import { parseApprovalRow } from "./parse-row.js";
|
|
4
|
+
/**
|
|
5
|
+
* Store for the `approval` table backing the approval round-trip. Each method
|
|
6
|
+
* accepts an optional transaction handle so the resolver can flip the approval
|
|
7
|
+
* and its signal correlation in a single `db.transaction`; when omitted the
|
|
8
|
+
* method runs against the store's own connection.
|
|
9
|
+
*/
|
|
10
|
+
export function createApprovalStore(db) {
|
|
11
|
+
return {
|
|
12
|
+
async create(row, tx) {
|
|
13
|
+
const [inserted] = await (tx ?? db)
|
|
14
|
+
.insert(approval)
|
|
15
|
+
.values(row)
|
|
16
|
+
.returning();
|
|
17
|
+
if (inserted === undefined) {
|
|
18
|
+
throw new Error(`approvalStore.create: insert returned no row for ${row.id}`);
|
|
19
|
+
}
|
|
20
|
+
return parseApprovalRow(inserted);
|
|
21
|
+
},
|
|
22
|
+
/**
|
|
23
|
+
* Idempotent variant of `create`. On a `correlationId` unique conflict the
|
|
24
|
+
* insert is a no-op and this returns `null` rather than throwing, so a
|
|
25
|
+
* redelivered register frame (sidecar reconnect, workflow-log replay,
|
|
26
|
+
* supervisor restart re-emitting) does not fail the co-write. Conflicts
|
|
27
|
+
* on `correlationId` -- not the `id` primary key -- because the register
|
|
28
|
+
* co-write mints a fresh `id` per frame while the correlation is the stable
|
|
29
|
+
* dedup key. Returns the parsed row only when this call performed the
|
|
30
|
+
* insert.
|
|
31
|
+
*/
|
|
32
|
+
async createIfAbsent(row, tx) {
|
|
33
|
+
const [inserted] = await (tx ?? db)
|
|
34
|
+
.insert(approval)
|
|
35
|
+
.values(row)
|
|
36
|
+
.onConflictDoNothing({ target: approval.correlationId })
|
|
37
|
+
.returning();
|
|
38
|
+
return inserted === undefined ? null : parseApprovalRow(inserted);
|
|
39
|
+
},
|
|
40
|
+
async findByCorrelationId(correlationId, tx) {
|
|
41
|
+
const row = await (tx ?? db).query.approval.findFirst({
|
|
42
|
+
where: eq(approval.correlationId, correlationId),
|
|
43
|
+
});
|
|
44
|
+
return row === undefined ? null : parseApprovalRow(row);
|
|
45
|
+
},
|
|
46
|
+
/**
|
|
47
|
+
* Look up an approval by its primary key. The resolve/reject routes key on
|
|
48
|
+
* the `approvalId` path parameter, which is the row's `id`, so they need a
|
|
49
|
+
* by-id read distinct from the by-correlation read the register co-write
|
|
50
|
+
* uses. Returns null when no row carries the id.
|
|
51
|
+
*/
|
|
52
|
+
async findById(id, tx) {
|
|
53
|
+
const row = await (tx ?? db).query.approval.findFirst({
|
|
54
|
+
where: eq(approval.id, id),
|
|
55
|
+
});
|
|
56
|
+
return row === undefined ? null : parseApprovalRow(row);
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* List a run's approvals, newest first, scoped by `tenantId` so one
|
|
60
|
+
* tenant's approvals never leak into another's view. Serves the run
|
|
61
|
+
* approvals list route; callers apply whatever status/scope predicate they
|
|
62
|
+
* need over the result.
|
|
63
|
+
*/
|
|
64
|
+
async listByRunId(tenantId, runId, tx) {
|
|
65
|
+
const rows = await (tx ?? db).query.approval.findMany({
|
|
66
|
+
where: and(eq(approval.tenantId, tenantId), eq(approval.runId, runId)),
|
|
67
|
+
orderBy: (a, { desc }) => desc(a.createdAt),
|
|
68
|
+
});
|
|
69
|
+
return rows.map(parseApprovalRow);
|
|
70
|
+
},
|
|
71
|
+
/**
|
|
72
|
+
* Conditionally resolve a pending approval. The `WHERE status = 'pending'`
|
|
73
|
+
* guard makes resolution terminal at the database: the first caller to
|
|
74
|
+
* resolve a given correlation gets the updated row back; any later caller
|
|
75
|
+
* (a duplicate delivery, a timeout racing an approval) matches no row and
|
|
76
|
+
* receives null.
|
|
77
|
+
*/
|
|
78
|
+
async resolve(correlationId, args, tx) {
|
|
79
|
+
const [updated] = await (tx ?? db)
|
|
80
|
+
.update(approval)
|
|
81
|
+
.set({
|
|
82
|
+
status: args.status,
|
|
83
|
+
scope: args.scope ?? null,
|
|
84
|
+
resolvedAt: args.resolvedAt,
|
|
85
|
+
updatedAt: new Date(),
|
|
86
|
+
})
|
|
87
|
+
.where(and(eq(approval.correlationId, correlationId), eq(approval.status, "pending")))
|
|
88
|
+
.returning();
|
|
89
|
+
return updated === undefined ? null : parseApprovalRow(updated);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -23,8 +23,8 @@ export declare function resolveAssetByName(db: DB["db"], tenantId: string, kind:
|
|
|
23
23
|
createdAt: Date;
|
|
24
24
|
updatedAt: Date;
|
|
25
25
|
tenantId: string;
|
|
26
|
-
creatorPrincipalId: string | null;
|
|
27
26
|
displayName: string | null;
|
|
27
|
+
creatorPrincipalId: string | null;
|
|
28
28
|
} | null>;
|
|
29
29
|
/**
|
|
30
30
|
* Resolves an asset by ID, validating that it belongs to the given
|
|
@@ -38,8 +38,8 @@ export declare function resolveAssetById(db: DB["db"], tenantId: string, assetId
|
|
|
38
38
|
createdAt: Date;
|
|
39
39
|
updatedAt: Date;
|
|
40
40
|
tenantId: string;
|
|
41
|
-
creatorPrincipalId: string | null;
|
|
42
41
|
displayName: string | null;
|
|
42
|
+
creatorPrincipalId: string | null;
|
|
43
43
|
} | null>;
|
|
44
44
|
/**
|
|
45
45
|
* Lists assets visible to the tenant, including those inherited from
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DB } from "./client.js";
|
|
2
|
+
import type { PrincipalKeyStore } from "./principal-key-store.js";
|
|
3
|
+
export type BackfillPrincipalKeysReport = {
|
|
4
|
+
/** Principals that were keyless and received a fresh active key. */
|
|
5
|
+
keysGenerated: number;
|
|
6
|
+
/** Principals that already held an active key and were left untouched. */
|
|
7
|
+
alreadyKeyed: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function backfillPrincipalKeys(db: DB["db"], principalKeyStore: PrincipalKeyStore): Promise<BackfillPrincipalKeysReport>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Backfill per-principal signing keys onto the principals that predate the
|
|
2
|
+
// feature.
|
|
3
|
+
//
|
|
4
|
+
// Minting a key lives only in the principal-creation owner, so every principal
|
|
5
|
+
// CREATED after that landed already has an active key. This one-shot pass keys
|
|
6
|
+
// the pre-existing population so the whole non-agent principal set matches the
|
|
7
|
+
// invariant "every non-agent principal has an active key".
|
|
8
|
+
//
|
|
9
|
+
// Scope is every `user` and `workflow` principal REGARDLESS of status, not just
|
|
10
|
+
// active ones. A status flip (e.g. an invite moving from `invited` to `active`)
|
|
11
|
+
// reuses the same principal row and does not re-mint, so an active-only pass
|
|
12
|
+
// would leave a pre-existing `invited`/`suspended` principal keyless and turn it
|
|
13
|
+
// into a keyless ACTIVE principal the moment it is activated. `agent` is a
|
|
14
|
+
// legacy/inert kind that is never keyed at creation either, so it is skipped to
|
|
15
|
+
// keep the populations consistent.
|
|
16
|
+
//
|
|
17
|
+
// Idempotent: a principal that already holds an active key is skipped, so the
|
|
18
|
+
// pass is safe to re-run or resume after a partial failure. Each principal is
|
|
19
|
+
// keyed in its own autocommit, so a partial failure leaves the earlier
|
|
20
|
+
// principals keyed. Safe to run against a LIVE hub -- nothing reads principal
|
|
21
|
+
// keys yet, the hub only mints for newly-created principals (disjoint from this
|
|
22
|
+
// pass's pre-existing set), and the `principal_key` active-key unique index
|
|
23
|
+
// blocks a double active key.
|
|
24
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
25
|
+
import { principal } from "./schema/principals.js";
|
|
26
|
+
import { principalKey } from "./schema/principal-keys.js";
|
|
27
|
+
const BACKFILLED_KINDS = ["user", "workflow"];
|
|
28
|
+
export async function backfillPrincipalKeys(db, principalKeyStore) {
|
|
29
|
+
// The left join is scoped to the active key, so `activeKeyId` is null exactly
|
|
30
|
+
// when the principal has no active key -- a principal holding only a retired
|
|
31
|
+
// key counts as keyless and is re-keyed. The active-key unique index makes at
|
|
32
|
+
// most one active row per principal, so each principal appears once.
|
|
33
|
+
const rows = await db
|
|
34
|
+
.select({ principalId: principal.id, activeKeyId: principalKey.id })
|
|
35
|
+
.from(principal)
|
|
36
|
+
.leftJoin(principalKey, and(eq(principalKey.principalId, principal.id), eq(principalKey.status, "active")))
|
|
37
|
+
.where(inArray(principal.kind, [...BACKFILLED_KINDS]));
|
|
38
|
+
const report = {
|
|
39
|
+
keysGenerated: 0,
|
|
40
|
+
alreadyKeyed: 0,
|
|
41
|
+
};
|
|
42
|
+
for (const row of rows) {
|
|
43
|
+
if (row.activeKeyId !== null) {
|
|
44
|
+
report.alreadyKeyed += 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
await principalKeyStore.generate(row.principalId);
|
|
48
|
+
report.keysGenerated += 1;
|
|
49
|
+
}
|
|
50
|
+
return report;
|
|
51
|
+
}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,9 +1,44 @@
|
|
|
1
|
+
import type { ExtractTablesWithRelations } from "drizzle-orm";
|
|
2
|
+
import type { PgDatabase, PgQueryResultHKT } from "drizzle-orm/pg-core";
|
|
1
3
|
import * as schema from "./schema/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* A drizzle database over the hub schema, typed against the driver-agnostic
|
|
6
|
+
* `PgDatabase` base rather than a single driver. `createDB` builds one over
|
|
7
|
+
* postgres-js; a caller can equally build one over pglite -- `drizzle(handle,
|
|
8
|
+
* { schema })` from `drizzle-orm/pglite`, with the schema re-exported from
|
|
9
|
+
* `@intx/db/schema` -- and pass it to the store factories. The required
|
|
10
|
+
* `$client` keeps a bare `PgTransaction` unassignable (a transaction carries no
|
|
11
|
+
* `$client`), so a parameter typed against this still rejects a tx where only a
|
|
12
|
+
* top-level database belongs.
|
|
13
|
+
*/
|
|
14
|
+
export type AnyPgDatabase = PgDatabase<PgQueryResultHKT, typeof schema, ExtractTablesWithRelations<typeof schema>> & {
|
|
15
|
+
$client: unknown;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The hub database handle: the database itself, plus `transaction` and
|
|
19
|
+
* `close`. `createDB` returns the postgres-js instantiation, but the handle is
|
|
20
|
+
* typed against `AnyPgDatabase` so the stores accept any pg driver -- a
|
|
21
|
+
* caller-built pglite database included.
|
|
22
|
+
*/
|
|
23
|
+
export interface DB {
|
|
24
|
+
db: AnyPgDatabase;
|
|
25
|
+
transaction: AnyPgDatabase["transaction"];
|
|
26
|
+
close: () => Promise<void>;
|
|
27
|
+
}
|
|
2
28
|
export declare function createDB(raw: unknown): {
|
|
3
29
|
db: import("drizzle-orm/postgres-js").PostgresJsDatabase<typeof schema> & {
|
|
4
30
|
$client: import("postgres").Sql<{}>;
|
|
5
31
|
};
|
|
6
|
-
transaction: <T>(transaction: (tx: import("drizzle-orm/pg-core").PgTransaction<import("drizzle-orm/postgres-js").PostgresJsQueryResultHKT, typeof schema,
|
|
32
|
+
transaction: <T>(transaction: (tx: import("drizzle-orm/pg-core").PgTransaction<import("drizzle-orm/postgres-js").PostgresJsQueryResultHKT, typeof schema, ExtractTablesWithRelations<typeof schema>>) => Promise<T>, config?: import("drizzle-orm/pg-core").PgTransactionConfig) => Promise<T>;
|
|
7
33
|
close: () => Promise<void>;
|
|
8
34
|
};
|
|
9
|
-
|
|
35
|
+
/**
|
|
36
|
+
* A handle that can execute queries: either the top-level `db` or a
|
|
37
|
+
* transaction handle passed into a `db.transaction` callback. Store methods
|
|
38
|
+
* that accept an optional `tx` type it against this so a caller can hand in
|
|
39
|
+
* the transaction object and have the write join the surrounding transaction.
|
|
40
|
+
* `DB["db"]` alone rejects a `PgTransaction` (it lacks the `$client` field the
|
|
41
|
+
* top-level database carries), so a bare `DB["db"]` parameter cannot accept a
|
|
42
|
+
* tx.
|
|
43
|
+
*/
|
|
44
|
+
export type DBExecutor = DB["db"] | Parameters<Parameters<DB["db"]["transaction"]>[0]>[0];
|
package/dist/client.js
CHANGED
|
@@ -16,3 +16,9 @@ export function createDB(raw) {
|
|
|
16
16
|
close: () => sql.end(),
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
// `createDB` returns the concrete postgres-js handle so its own callers keep
|
|
20
|
+
// the driver's precise result types (e.g. a typed `db.execute`). This assures
|
|
21
|
+
// at the definition site that the concrete handle still satisfies `DB`, the
|
|
22
|
+
// driver-agnostic contract the stores consume.
|
|
23
|
+
const _createDBReturnsDB = createDB;
|
|
24
|
+
void _createDBReturnsDB;
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -7,6 +7,8 @@ export const DBConfig = type({
|
|
|
7
7
|
database: "string",
|
|
8
8
|
"ssl?": "boolean",
|
|
9
9
|
"max?": "number.integer > 0",
|
|
10
|
+
// PostgreSQL statement deadline in milliseconds. Defaults to 60 seconds.
|
|
11
|
+
"statementTimeoutMs?": "0 < number.integer <= 2147483647",
|
|
10
12
|
// Postgres schema name. When set, the connection's `search_path` is
|
|
11
13
|
// pinned to this schema and migrations apply into it. This is the
|
|
12
14
|
// mechanism the integration-test harness uses to give each spawned
|
package/dist/connection.js
CHANGED
|
@@ -11,13 +11,17 @@ export function createConnection(config) {
|
|
|
11
11
|
database: config.database,
|
|
12
12
|
max: config.max ?? 10,
|
|
13
13
|
...(config.ssl !== undefined && { ssl: config.ssl }),
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
connection: {
|
|
15
|
+
TimeZone: "UTC",
|
|
16
|
+
statement_timeout: config.statementTimeoutMs ?? 60_000,
|
|
17
|
+
...(config.schema !== undefined && {
|
|
18
|
+
// Pin the connection's search_path so unqualified table
|
|
19
|
+
// references resolve to the caller's schema. The migration
|
|
20
|
+
// runner emits SQL with the schema baked into FK references,
|
|
21
|
+
// but ORM-issued queries bind table names without a schema
|
|
22
|
+
// qualifier and rely on this setting.
|
|
23
|
+
search_path: quoteIdentifier(config.schema),
|
|
24
|
+
}),
|
|
25
|
+
},
|
|
22
26
|
});
|
|
23
27
|
}
|
|
@@ -1,4 +1,95 @@
|
|
|
1
|
+
import type { CredentialBinding, CredentialCipher } from "@intx/types";
|
|
2
|
+
import type { CredentialDelivery, CredentialMaterialEntry } from "@intx/types/sidecar";
|
|
1
3
|
import type { DB } from "./client.js";
|
|
4
|
+
/**
|
|
5
|
+
* Thrown by `resolveCredentialRequirement` when more than one credential
|
|
6
|
+
* matches a requirement and no name disambiguates them. A distinct type so
|
|
7
|
+
* callers can catch *this* condition (a launch-blocking configuration error)
|
|
8
|
+
* without also swallowing the DB reads the resolver performs first -- an
|
|
9
|
+
* infrastructure failure must surface, not be mislabeled as ambiguity.
|
|
10
|
+
*/
|
|
11
|
+
export declare class AmbiguousCredentialError extends Error {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Thrown when a referenced credential is not a tenant-owned credential the given
|
|
16
|
+
* tenant can use -- it does not exist, is not reachable in the tenant's ancestor
|
|
17
|
+
* chain, or is principal-owned. A distinct type so a caller can map a client's
|
|
18
|
+
* bad credential reference to a 4xx (a launch-blocking configuration error),
|
|
19
|
+
* separate from the infrastructure faults the resolvers otherwise surface.
|
|
20
|
+
*/
|
|
21
|
+
export declare class CredentialUnauthorizedError extends Error {
|
|
22
|
+
readonly credentialId: string;
|
|
23
|
+
readonly tenantId: string;
|
|
24
|
+
constructor(credentialId: string, tenantId: string);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a credential USABLE by the launching tenant purely through ownership:
|
|
28
|
+
* it exists, is reachable in the tenant's ancestor chain, and is tenant-owned
|
|
29
|
+
* (`principalId IS NULL`). Returns the row -- the proof of authority -- or null.
|
|
30
|
+
*
|
|
31
|
+
* This is the one "usable by ownership" resolver: a tenant may use what it (or
|
|
32
|
+
* an ancestor) owns, and descendants inherit; a principal-owned credential is
|
|
33
|
+
* never usable this way, its delegation flowing from its owner instead. It
|
|
34
|
+
* wraps `resolveCredentialById` (the ancestor-chain check) with the tenant-owned
|
|
35
|
+
* gate, so callers do not re-implement the predicate. `buildSource` expands it
|
|
36
|
+
* inline only to distinguish an unresolved reference from a principal-owned one.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveTenantOwnedCredentialById(db: DB["db"], tenantId: string, credentialId: string): Promise<{
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
createdAt: Date;
|
|
42
|
+
updatedAt: Date;
|
|
43
|
+
expiresAt: Date | null;
|
|
44
|
+
providerId: string;
|
|
45
|
+
tenantId: string;
|
|
46
|
+
status: "active" | "error" | "expired" | "revoked";
|
|
47
|
+
principalId: string | null;
|
|
48
|
+
description: string | null;
|
|
49
|
+
scopes: string[] | null;
|
|
50
|
+
metadata: unknown;
|
|
51
|
+
oauthClientId: string | null;
|
|
52
|
+
type: "api_key" | "oauth_token" | "certificate" | "other";
|
|
53
|
+
secret: string;
|
|
54
|
+
refreshSecret: string | null;
|
|
55
|
+
} | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Resolve a set of inference-source credentialIds into the credential material
|
|
58
|
+
* delivered on a run's unified credential-material cell. An inference source
|
|
59
|
+
* references its credential by id only; for each DISTINCT id this resolves the
|
|
60
|
+
* secret under the SAME tenant-ownership authority `buildSource` uses -- the
|
|
61
|
+
* credential must exist, be reachable in the tenant's ancestor chain, and be
|
|
62
|
+
* tenant-owned (`principalId IS NULL`) -- then decrypts it at the single point of
|
|
63
|
+
* use. `providerKey`/`origin` come from the credential's own provider row
|
|
64
|
+
* (`provider.plugin` / `provider.apiBaseUrl`), so the material describes the
|
|
65
|
+
* credential itself, independent of any caller-supplied source fields.
|
|
66
|
+
*
|
|
67
|
+
* Fails CLOSED, by throwing, on the first credentialId that is unresolved, not
|
|
68
|
+
* tenant-owned, references a missing provider, or whose provider has no API
|
|
69
|
+
* origin to pin -- a secret is never dropped nor delivered without an origin. The
|
|
70
|
+
* single resolver for every inference source credentialId -> material, shared by
|
|
71
|
+
* the deploy composition (top-level + inline body sources) and any other caller
|
|
72
|
+
* that must materialize inference credentials for the cell.
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveInferenceMaterials(db: DB["db"], tenantId: string, credentialIds: Iterable<string>, credentialCipher: CredentialCipher): Promise<CredentialMaterialEntry[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Re-resolve the CURRENT material for a set of already-authorized credentialIds,
|
|
77
|
+
* for the reconnect resync. Unlike `resolveInferenceMaterials`, a credential
|
|
78
|
+
* that no longer exists or is `revoked` is DROPPED (omitted) rather than
|
|
79
|
+
* throwing: the resync reflects credential lifecycle, so a dead id is simply
|
|
80
|
+
* absent from the reconciled delivery and the child evicts it.
|
|
81
|
+
*
|
|
82
|
+
* A credential that IS alive but whose material cannot be resolved (its provider
|
|
83
|
+
* vanished or has no API base URL) is NOT a lifecycle removal, so it throws --
|
|
84
|
+
* the caller aborts the whole reconcile rather than delivering a partial set
|
|
85
|
+
* paired with a spurious revoke. A rotated secret is picked up because the row's
|
|
86
|
+
* current secret is decrypted here.
|
|
87
|
+
*
|
|
88
|
+
* Ids are looked up by primary key (globally unique) and come from the
|
|
89
|
+
* deployment's own persisted delivery, so no re-authorization is performed --
|
|
90
|
+
* this reflects lifecycle only.
|
|
91
|
+
*/
|
|
92
|
+
export declare function reresolveCurrentMaterials(db: DB["db"], credentialIds: Iterable<string>, credentialCipher: CredentialCipher): Promise<CredentialMaterialEntry[]>;
|
|
2
93
|
/**
|
|
3
94
|
* Resolves a provider by name, walking up the tenant hierarchy.
|
|
4
95
|
* Returns the first match (child shadows parent).
|
|
@@ -10,6 +101,7 @@ export declare function resolveProviderByName(db: DB["db"], tenantId: string, na
|
|
|
10
101
|
updatedAt: Date;
|
|
11
102
|
tenantId: string;
|
|
12
103
|
plugin: string;
|
|
104
|
+
apiBaseUrl: string | null;
|
|
13
105
|
authorizationUrl: string | null;
|
|
14
106
|
tokenUrl: string | null;
|
|
15
107
|
userInfoUrl: string | null;
|
|
@@ -45,9 +137,9 @@ export declare function resolveCredentialByName(db: DB["db"], tenantId: string,
|
|
|
45
137
|
expiresAt: Date | null;
|
|
46
138
|
providerId: string;
|
|
47
139
|
tenantId: string;
|
|
48
|
-
status: "active" | "
|
|
49
|
-
description: string | null;
|
|
140
|
+
status: "active" | "error" | "expired" | "revoked";
|
|
50
141
|
principalId: string | null;
|
|
142
|
+
description: string | null;
|
|
51
143
|
scopes: string[] | null;
|
|
52
144
|
metadata: unknown;
|
|
53
145
|
oauthClientId: string | null;
|
|
@@ -67,9 +159,9 @@ export declare function resolveCredentialById(db: DB["db"], tenantId: string, cr
|
|
|
67
159
|
expiresAt: Date | null;
|
|
68
160
|
providerId: string;
|
|
69
161
|
tenantId: string;
|
|
70
|
-
status: "active" | "
|
|
71
|
-
description: string | null;
|
|
162
|
+
status: "active" | "error" | "expired" | "revoked";
|
|
72
163
|
principalId: string | null;
|
|
164
|
+
description: string | null;
|
|
73
165
|
scopes: string[] | null;
|
|
74
166
|
metadata: unknown;
|
|
75
167
|
oauthClientId: string | null;
|
|
@@ -90,21 +182,90 @@ type CredentialRequirement = {
|
|
|
90
182
|
* catalog, not this path).
|
|
91
183
|
*/
|
|
92
184
|
export declare function resolveCredentialRequirement(db: DB["db"], tenantId: string, requirement: CredentialRequirement, creatorPrincipalId: string | null, invokerPrincipalId: string | null): Promise<{
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
185
|
+
credential: {
|
|
186
|
+
id: string;
|
|
187
|
+
name: string;
|
|
188
|
+
createdAt: Date;
|
|
189
|
+
updatedAt: Date;
|
|
190
|
+
expiresAt: Date | null;
|
|
191
|
+
providerId: string;
|
|
192
|
+
tenantId: string;
|
|
193
|
+
status: "active" | "error" | "expired" | "revoked";
|
|
194
|
+
principalId: string | null;
|
|
195
|
+
description: string | null;
|
|
196
|
+
scopes: string[] | null;
|
|
197
|
+
metadata: unknown;
|
|
198
|
+
oauthClientId: string | null;
|
|
199
|
+
type: "api_key" | "oauth_token" | "certificate" | "other";
|
|
200
|
+
secret: string;
|
|
201
|
+
refreshSecret: string | null;
|
|
202
|
+
};
|
|
203
|
+
provider: {
|
|
204
|
+
id: string;
|
|
205
|
+
name: string;
|
|
206
|
+
createdAt: Date;
|
|
207
|
+
updatedAt: Date;
|
|
208
|
+
tenantId: string;
|
|
209
|
+
plugin: string;
|
|
210
|
+
apiBaseUrl: string | null;
|
|
211
|
+
authorizationUrl: string | null;
|
|
212
|
+
tokenUrl: string | null;
|
|
213
|
+
userInfoUrl: string | null;
|
|
214
|
+
scopes: string[] | null;
|
|
215
|
+
metadata: unknown;
|
|
216
|
+
};
|
|
109
217
|
} | null>;
|
|
218
|
+
/**
|
|
219
|
+
* A launch-blocking CONFIGURATION failure for one binding: a binding no
|
|
220
|
+
* credential resolves, a provider with no API origin (can't pin an http
|
|
221
|
+
* handle), or an ambiguous match. Distinct from an infrastructure failure (a DB
|
|
222
|
+
* read fault), which `buildCredentialDelivery` THROWS rather than returning --
|
|
223
|
+
* so a caller never mistakes a transient fault for revocation.
|
|
224
|
+
*/
|
|
225
|
+
export type CredentialDeliveryFailure = {
|
|
226
|
+
code: "unresolved" | "no_origin" | "ambiguous";
|
|
227
|
+
binding: {
|
|
228
|
+
provider: string;
|
|
229
|
+
package: string;
|
|
230
|
+
handle: string;
|
|
231
|
+
};
|
|
232
|
+
message: string;
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Outcome of `buildCredentialDelivery`. `ok: true` carries the material +
|
|
236
|
+
* descriptors delivered to the tools; `delivery` is `undefined` when there are
|
|
237
|
+
* no bindings. `ok: false` carries the first launch-blocking configuration
|
|
238
|
+
* failure for the caller to map to a fail-closed response.
|
|
239
|
+
*/
|
|
240
|
+
export type BuildCredentialDeliveryResult = {
|
|
241
|
+
ok: true;
|
|
242
|
+
delivery: CredentialDelivery | undefined;
|
|
243
|
+
} | {
|
|
244
|
+
ok: false;
|
|
245
|
+
reason: CredentialDeliveryFailure;
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* Resolve a definition's credential bindings into the material + per-handle
|
|
249
|
+
* descriptors delivered to its tools. Each credential's secret is decrypted
|
|
250
|
+
* once, keyed by credentialId (a credential backing several handles is
|
|
251
|
+
* decrypted once).
|
|
252
|
+
*
|
|
253
|
+
* This path delivers credential material only; it does not mint, stamp, or
|
|
254
|
+
* carry any grant. Credential-use authorization is enforced by a separate grant
|
|
255
|
+
* layer.
|
|
256
|
+
*
|
|
257
|
+
* The workflow-deploy path (`deployCodeSourcedWorkflow`) is the only caller
|
|
258
|
+
* today, using `delivery`. Returning a discriminated result rather than an HTTP
|
|
259
|
+
* response keeps it safe to call off the request path: a configuration failure
|
|
260
|
+
* is `ok: false`, and a transient DB read fault THROWS so the caller surfaces it
|
|
261
|
+
* rather than silently dropping a still-valid credential.
|
|
262
|
+
*/
|
|
263
|
+
export declare function buildCredentialDelivery(args: {
|
|
264
|
+
db: DB["db"];
|
|
265
|
+
tenantId: string;
|
|
266
|
+
bindings: readonly CredentialBinding[];
|
|
267
|
+
creatorPrincipalId: string | null;
|
|
268
|
+
invokerPrincipalId: string | null;
|
|
269
|
+
credentialCipher: CredentialCipher;
|
|
270
|
+
}): Promise<BuildCredentialDeliveryResult>;
|
|
110
271
|
export {};
|