@intx/db 0.1.2 → 0.3.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 +176 -0
- package/README.md +23 -4
- package/dist/approval-store.d.ts +52 -0
- package/dist/approval-store.js +79 -0
- package/dist/asset-resolution.d.ts +52 -0
- package/dist/asset-resolution.js +66 -0
- package/dist/catalog-resolution.d.ts +76 -0
- package/dist/catalog-resolution.js +151 -0
- package/dist/client.d.ts +19 -0
- package/dist/client.js +18 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +16 -0
- package/dist/connection.d.ts +3 -0
- package/dist/connection.js +26 -0
- package/dist/credential-resolution.d.ts +222 -0
- package/dist/credential-resolution.js +255 -0
- package/dist/grant-store.d.ts +3 -0
- package/dist/grant-store.js +59 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +20 -0
- package/dist/migrate.d.ts +36 -0
- package/dist/migrate.js +135 -0
- package/dist/model-source-resolution.d.ts +115 -0
- package/dist/model-source-resolution.js +291 -0
- package/dist/parse-row.d.ts +373 -0
- package/dist/parse-row.js +232 -0
- package/dist/pg-error.d.ts +3 -0
- package/dist/pg-error.js +19 -0
- package/dist/pricing.d.ts +15 -0
- package/dist/pricing.js +24 -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 +52 -0
- package/dist/schema/assets.d.ts +143 -0
- package/{src/schema/assets.ts → dist/schema/assets.js} +7 -16
- package/dist/schema/auth.d.ts +606 -0
- package/dist/schema/auth.js +47 -0
- package/dist/schema/catalog.d.ts +811 -0
- package/dist/schema/catalog.js +108 -0
- package/dist/schema/column-types.d.ts +26 -0
- package/dist/schema/column-types.js +15 -0
- package/dist/schema/credentials.d.ts +305 -0
- package/{src/schema/credentials.ts → dist/schema/credentials.js} +16 -22
- package/dist/schema/git-tokens.d.ts +256 -0
- package/{src/schema/git-tokens.ts → dist/schema/git-tokens.js} +16 -39
- package/dist/schema/grants.d.ts +211 -0
- package/dist/schema/grants.js +30 -0
- package/dist/schema/index.d.ts +25 -0
- package/dist/schema/index.js +25 -0
- package/dist/schema/messages.d.ts +414 -0
- package/dist/schema/messages.js +82 -0
- package/dist/schema/oauth-clients.d.ts +246 -0
- package/{src/schema/oauth-clients.ts → dist/schema/oauth-clients.js} +8 -14
- package/dist/schema/offerings.d.ts +160 -0
- package/dist/schema/offerings.js +24 -0
- package/dist/schema/principals.d.ts +128 -0
- package/dist/schema/principals.js +23 -0
- package/dist/schema/providers.d.ts +237 -0
- package/dist/schema/providers.js +22 -0
- package/dist/schema/roles.d.ts +242 -0
- package/dist/schema/roles.js +37 -0
- package/dist/schema/session-assets.d.ts +92 -0
- package/dist/schema/session-assets.js +45 -0
- package/dist/schema/sessions.d.ts +143 -0
- package/dist/schema/sessions.js +29 -0
- package/dist/schema/sidecar-allocation.d.ts +406 -0
- package/dist/schema/sidecar-allocation.js +57 -0
- package/dist/schema/sidecar.d.ts +145 -0
- package/dist/schema/sidecar.js +28 -0
- package/dist/schema/signal-correlations.d.ts +177 -0
- package/dist/schema/signal-correlations.js +31 -0
- package/dist/schema/tenants.d.ts +235 -0
- package/{src/schema/tenants.ts → dist/schema/tenants.js} +10 -27
- package/dist/schema/wallets.d.ts +354 -0
- package/dist/schema/wallets.js +43 -0
- package/dist/schema/workflow-definitions.d.ts +371 -0
- package/dist/schema/workflow-definitions.js +97 -0
- package/dist/schema/workflow-run-dispatch.d.ts +328 -0
- package/dist/schema/workflow-run-dispatch.js +56 -0
- package/dist/schema/workflow-run-execution.d.ts +126 -0
- 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/workflow-run.d.ts +230 -0
- package/dist/schema/workflow-run.js +102 -0
- package/dist/sidecar-allocation-store.d.ts +171 -0
- package/dist/sidecar-allocation-store.js +512 -0
- package/dist/signal-correlation-store.d.ts +36 -0
- package/dist/signal-correlation-store.js +63 -0
- package/dist/tenant-hierarchy.d.ts +23 -0
- package/dist/tenant-hierarchy.js +60 -0
- package/dist/workflow-definition-store.d.ts +55 -0
- package/dist/workflow-definition-store.js +93 -0
- package/dist/workflow-run-dispatch-store.d.ts +80 -0
- package/dist/workflow-run-dispatch-store.js +298 -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/0029_loose_warlock.sql +1 -0
- package/migrations/0030_session_asset_audit_split.sql +5 -0
- package/migrations/0031_gigantic_nicolaos.sql +68 -0
- package/migrations/0032_lethal_misty_knight.sql +1 -0
- package/migrations/0033_old_payback.sql +1 -0
- package/migrations/0034_sleepy_songbird.sql +11 -0
- package/migrations/0035_violet_giant_man.sql +3 -0
- package/migrations/0036_sharp_the_executioner.sql +2 -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/meta/0029_snapshot.json +2664 -0
- package/migrations/meta/0030_snapshot.json +2670 -0
- package/migrations/meta/0031_snapshot.json +3100 -0
- package/migrations/meta/0032_snapshot.json +3106 -0
- package/migrations/meta/0033_snapshot.json +3112 -0
- package/migrations/meta/0034_snapshot.json +3198 -0
- package/migrations/meta/0035_snapshot.json +3225 -0
- package/migrations/meta/0036_snapshot.json +3237 -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/_journal.json +385 -0
- package/package.json +25 -11
- package/drizzle.config.ts +0 -23
- package/src/client.ts +0 -24
- package/src/config.ts +0 -19
- package/src/connection.ts +0 -27
- package/src/credential-resolution.ts +0 -378
- package/src/grant-store.ts +0 -51
- package/src/index.ts +0 -32
- package/src/migrate.test.ts +0 -35
- package/src/migrate.ts +0 -168
- package/src/parse-row.test.ts +0 -113
- package/src/parse-row.ts +0 -185
- package/src/schema/agent-assets.ts +0 -21
- package/src/schema/agents.ts +0 -49
- package/src/schema/auth.ts +0 -51
- package/src/schema/grants.ts +0 -26
- package/src/schema/index.ts +0 -19
- package/src/schema/instances.ts +0 -36
- package/src/schema/messages.ts +0 -108
- package/src/schema/offerings.ts +0 -20
- package/src/schema/principals.ts +0 -28
- package/src/schema/providers.ts +0 -23
- package/src/schema/roles.ts +0 -51
- package/src/schema/session-assets.ts +0 -49
- package/src/schema/sessions.ts +0 -26
- package/src/schema/sidecar.ts +0 -14
- package/src/schema/wallets.ts +0 -44
- package/src/tenant-hierarchy.ts +0 -34
- package/tsconfig.json +0 -4
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
import { model, modelOffering, modelProvider } from "./schema/catalog.js";
|
|
3
|
+
import { getAncestorChain } from "./tenant-hierarchy.js";
|
|
4
|
+
/**
|
|
5
|
+
* Lists the models visible to a tenant, walking the ancestor chain
|
|
6
|
+
* leaf-to-root. The first row to claim a `canonicalName` wins (a
|
|
7
|
+
* descendant shadows an ancestor). A winning row marked `disabled`
|
|
8
|
+
* suppresses the name for the tenant and its descendants, so it is
|
|
9
|
+
* omitted from the result.
|
|
10
|
+
*
|
|
11
|
+
* Scoping derives entirely from the ancestor chain; the denormalized
|
|
12
|
+
* `tenantId` on referencing rows is never the scoping authority.
|
|
13
|
+
*/
|
|
14
|
+
export async function listVisibleModels(db, tenantId) {
|
|
15
|
+
const chain = await getAncestorChain(db, tenantId);
|
|
16
|
+
const byKey = new Map();
|
|
17
|
+
for (const tid of chain) {
|
|
18
|
+
const rows = await db.query.model.findMany({
|
|
19
|
+
where: eq(model.tenantId, tid),
|
|
20
|
+
});
|
|
21
|
+
for (const row of rows) {
|
|
22
|
+
if (byKey.has(row.canonicalName))
|
|
23
|
+
continue;
|
|
24
|
+
byKey.set(row.canonicalName, {
|
|
25
|
+
row,
|
|
26
|
+
origin: { tenantId: tid, direct: tid === tenantId },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return Array.from(byKey.values()).filter((entry) => !entry.row.disabled);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Lists the model providers visible to a tenant. Same leaf-to-root
|
|
34
|
+
* shadowing and disable-suppression as {@link listVisibleModels},
|
|
35
|
+
* keyed on the provider `name`.
|
|
36
|
+
*/
|
|
37
|
+
export async function listVisibleProviders(db, tenantId) {
|
|
38
|
+
const chain = await getAncestorChain(db, tenantId);
|
|
39
|
+
const byKey = new Map();
|
|
40
|
+
for (const tid of chain) {
|
|
41
|
+
const rows = await db.query.modelProvider.findMany({
|
|
42
|
+
where: eq(modelProvider.tenantId, tid),
|
|
43
|
+
});
|
|
44
|
+
for (const row of rows) {
|
|
45
|
+
if (byKey.has(row.name))
|
|
46
|
+
continue;
|
|
47
|
+
byKey.set(row.name, {
|
|
48
|
+
row,
|
|
49
|
+
origin: { tenantId: tid, direct: tid === tenantId },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return Array.from(byKey.values()).filter((entry) => !entry.row.disabled);
|
|
54
|
+
}
|
|
55
|
+
// A NUL separator cannot collide: it never appears in a Postgres `text`
|
|
56
|
+
// value, so distinct (canonicalName, providerName) pairs never map to the
|
|
57
|
+
// same composite key even when a name contains spaces or punctuation.
|
|
58
|
+
const KEY_SEPARATOR = "\u0000";
|
|
59
|
+
function offeringKey(canonicalName, providerName) {
|
|
60
|
+
return `${canonicalName}${KEY_SEPARATOR}${providerName}`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Lists the offerings visible to a tenant.
|
|
64
|
+
*
|
|
65
|
+
* An offering's cross-tenant identity is `(model canonicalName, provider
|
|
66
|
+
* name)`, not its row ids — a child that shadows a model or provider must
|
|
67
|
+
* shadow the inherited offerings for that pairing. So each offering's
|
|
68
|
+
* `modelId`/`providerId` are dereferenced to their canonical identity
|
|
69
|
+
* (across every tenant in the chain, since the referents may be inherited)
|
|
70
|
+
* and the chain is walked leaf-to-root with that identity as the key:
|
|
71
|
+
* first wins, `disabled` suppresses.
|
|
72
|
+
*
|
|
73
|
+
* Visibility then cascades from the model/provider passes: an offering
|
|
74
|
+
* survives only if both its model `canonicalName` and provider `name` are
|
|
75
|
+
* themselves visible. Disabling a provider therefore removes every
|
|
76
|
+
* inherited offering against it, even offerings the disabling tenant never
|
|
77
|
+
* touched. The cascade is applied after the model and provider passes
|
|
78
|
+
* complete, never interleaved.
|
|
79
|
+
*
|
|
80
|
+
* The returned `model`/`provider` are the entries *visible to the
|
|
81
|
+
* resolving tenant* (resolved by canonicalName/name), so shadowed
|
|
82
|
+
* configuration applies to inherited offerings.
|
|
83
|
+
*/
|
|
84
|
+
export async function listVisibleOfferings(db, tenantId) {
|
|
85
|
+
const chain = await getAncestorChain(db, tenantId);
|
|
86
|
+
const visibleModels = new Map((await listVisibleModels(db, tenantId)).map((m) => [
|
|
87
|
+
m.row.canonicalName,
|
|
88
|
+
m,
|
|
89
|
+
]));
|
|
90
|
+
const visibleProviders = new Map((await listVisibleProviders(db, tenantId)).map((p) => [p.row.name, p]));
|
|
91
|
+
// Dereference offering referents to their canonical identity. The
|
|
92
|
+
// referents may live on any tenant in the chain (an offering can be
|
|
93
|
+
// inherited), so the id maps span every tenant, including rows that are
|
|
94
|
+
// themselves shadowed or disabled — the maps answer "what does this id
|
|
95
|
+
// name", and the cascade below decides visibility.
|
|
96
|
+
const modelNameById = new Map();
|
|
97
|
+
const providerNameById = new Map();
|
|
98
|
+
for (const tid of chain) {
|
|
99
|
+
for (const row of await db.query.model.findMany({
|
|
100
|
+
where: eq(model.tenantId, tid),
|
|
101
|
+
})) {
|
|
102
|
+
modelNameById.set(row.id, row.canonicalName);
|
|
103
|
+
}
|
|
104
|
+
for (const row of await db.query.modelProvider.findMany({
|
|
105
|
+
where: eq(modelProvider.tenantId, tid),
|
|
106
|
+
})) {
|
|
107
|
+
providerNameById.set(row.id, row.name);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const byKey = new Map();
|
|
111
|
+
for (const tid of chain) {
|
|
112
|
+
const rows = await db.query.modelOffering.findMany({
|
|
113
|
+
where: eq(modelOffering.tenantId, tid),
|
|
114
|
+
});
|
|
115
|
+
for (const row of rows) {
|
|
116
|
+
const canonicalName = modelNameById.get(row.modelId);
|
|
117
|
+
const providerName = providerNameById.get(row.providerId);
|
|
118
|
+
if (canonicalName === undefined || providerName === undefined)
|
|
119
|
+
continue;
|
|
120
|
+
const key = offeringKey(canonicalName, providerName);
|
|
121
|
+
if (byKey.has(key))
|
|
122
|
+
continue;
|
|
123
|
+
byKey.set(key, {
|
|
124
|
+
row,
|
|
125
|
+
origin: { tenantId: tid, direct: tid === tenantId },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const resolved = [];
|
|
130
|
+
for (const { row, origin } of byKey.values()) {
|
|
131
|
+
if (row.disabled)
|
|
132
|
+
continue;
|
|
133
|
+
const canonicalName = modelNameById.get(row.modelId);
|
|
134
|
+
const providerName = providerNameById.get(row.providerId);
|
|
135
|
+
if (canonicalName === undefined || providerName === undefined)
|
|
136
|
+
continue;
|
|
137
|
+
const visibleModel = visibleModels.get(canonicalName);
|
|
138
|
+
const visibleProvider = visibleProviders.get(providerName);
|
|
139
|
+
// Cascade: the offering survives only if its model and provider are
|
|
140
|
+
// both visible (a disabled model or provider removes its offerings).
|
|
141
|
+
if (visibleModel === undefined || visibleProvider === undefined)
|
|
142
|
+
continue;
|
|
143
|
+
resolved.push({
|
|
144
|
+
offering: row,
|
|
145
|
+
model: visibleModel.row,
|
|
146
|
+
provider: visibleProvider.row,
|
|
147
|
+
origin,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return resolved;
|
|
151
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as schema from "./schema/index.js";
|
|
2
|
+
export declare function createDB(raw: unknown): {
|
|
3
|
+
db: import("drizzle-orm/postgres-js").PostgresJsDatabase<typeof schema> & {
|
|
4
|
+
$client: import("postgres").Sql<{}>;
|
|
5
|
+
};
|
|
6
|
+
transaction: <T>(transaction: (tx: import("drizzle-orm/pg-core").PgTransaction<import("drizzle-orm/postgres-js").PostgresJsQueryResultHKT, typeof schema, import("drizzle-orm").ExtractTablesWithRelations<typeof schema>>) => Promise<T>, config?: import("drizzle-orm/pg-core").PgTransactionConfig) => Promise<T>;
|
|
7
|
+
close: () => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
export type DB = ReturnType<typeof createDB>;
|
|
10
|
+
/**
|
|
11
|
+
* A handle that can execute queries: either the top-level `db` or a
|
|
12
|
+
* transaction handle passed into a `db.transaction` callback. Store methods
|
|
13
|
+
* that accept an optional `tx` type it against this so a caller can hand in
|
|
14
|
+
* the transaction object and have the write join the surrounding transaction.
|
|
15
|
+
* `DB["db"]` alone rejects a `PgTransaction` (it lacks the `$client` field the
|
|
16
|
+
* top-level database carries), so a bare `DB["db"]` parameter cannot accept a
|
|
17
|
+
* tx.
|
|
18
|
+
*/
|
|
19
|
+
export type DBExecutor = DB["db"] | Parameters<Parameters<DB["db"]["transaction"]>[0]>[0];
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
import { drizzle } from "drizzle-orm/postgres-js";
|
|
3
|
+
import { DBConfig } from "./config.js";
|
|
4
|
+
import { createConnection } from "./connection.js";
|
|
5
|
+
import * as schema from "./schema/index.js";
|
|
6
|
+
export function createDB(raw) {
|
|
7
|
+
const config = DBConfig(raw);
|
|
8
|
+
if (config instanceof type.errors) {
|
|
9
|
+
throw new Error(`Invalid database config: ${config.summary}`);
|
|
10
|
+
}
|
|
11
|
+
const sql = createConnection(config);
|
|
12
|
+
const db = drizzle(sql, { schema });
|
|
13
|
+
return {
|
|
14
|
+
db,
|
|
15
|
+
transaction: db.transaction.bind(db),
|
|
16
|
+
close: () => sql.end(),
|
|
17
|
+
};
|
|
18
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const DBConfig: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
user: string;
|
|
5
|
+
password: string;
|
|
6
|
+
database: string;
|
|
7
|
+
ssl?: boolean;
|
|
8
|
+
max?: number;
|
|
9
|
+
schema?: string;
|
|
10
|
+
}, {}>;
|
|
11
|
+
export type DBConfig = typeof DBConfig.infer;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
export const DBConfig = type({
|
|
3
|
+
host: "string",
|
|
4
|
+
port: "number.integer > 0",
|
|
5
|
+
user: "string",
|
|
6
|
+
password: "string",
|
|
7
|
+
database: "string",
|
|
8
|
+
"ssl?": "boolean",
|
|
9
|
+
"max?": "number.integer > 0",
|
|
10
|
+
// Postgres schema name. When set, the connection's `search_path` is
|
|
11
|
+
// pinned to this schema and migrations apply into it. This is the
|
|
12
|
+
// mechanism the integration-test harness uses to give each spawned
|
|
13
|
+
// hub a dedicated, droppable schema. When unset, the connection uses
|
|
14
|
+
// postgres' default `search_path` (which begins with `public`).
|
|
15
|
+
"schema?": "string",
|
|
16
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import postgres from "postgres";
|
|
2
|
+
function quoteIdentifier(name) {
|
|
3
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
4
|
+
}
|
|
5
|
+
export function createConnection(config) {
|
|
6
|
+
return postgres({
|
|
7
|
+
host: config.host,
|
|
8
|
+
port: config.port,
|
|
9
|
+
user: config.user,
|
|
10
|
+
password: config.password,
|
|
11
|
+
database: config.database,
|
|
12
|
+
max: config.max ?? 10,
|
|
13
|
+
...(config.ssl !== undefined && { ssl: config.ssl }),
|
|
14
|
+
connection: {
|
|
15
|
+
TimeZone: "UTC",
|
|
16
|
+
...(config.schema !== undefined && {
|
|
17
|
+
// Pin the connection's search_path so unqualified table
|
|
18
|
+
// references resolve to the caller's schema. The migration
|
|
19
|
+
// runner emits SQL with the schema baked into FK references,
|
|
20
|
+
// but ORM-issued queries bind table names without a schema
|
|
21
|
+
// qualifier and rely on this setting.
|
|
22
|
+
search_path: quoteIdentifier(config.schema),
|
|
23
|
+
}),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import type { CredentialBinding, CredentialCipher } from "@intx/types";
|
|
2
|
+
import type { CredentialDelivery } from "@intx/types/sidecar";
|
|
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
|
+
* Resolve a credential USABLE by the launching tenant purely through ownership:
|
|
16
|
+
* it exists, is reachable in the tenant's ancestor chain, and is tenant-owned
|
|
17
|
+
* (`principalId IS NULL`). Returns the row -- the proof of authority -- or null.
|
|
18
|
+
*
|
|
19
|
+
* This is the one "usable by ownership" resolver: a tenant may use what it (or
|
|
20
|
+
* an ancestor) owns, and descendants inherit; a principal-owned credential is
|
|
21
|
+
* never usable this way, its delegation flowing from its owner instead. It
|
|
22
|
+
* wraps `resolveCredentialById` (the ancestor-chain check) with the tenant-owned
|
|
23
|
+
* gate, so callers do not re-implement the predicate. `buildSource` expands it
|
|
24
|
+
* inline only to distinguish an unresolved reference from a principal-owned one.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveTenantOwnedCredentialById(db: DB["db"], tenantId: string, credentialId: string): Promise<{
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
createdAt: Date;
|
|
30
|
+
updatedAt: Date;
|
|
31
|
+
expiresAt: Date | null;
|
|
32
|
+
providerId: string;
|
|
33
|
+
tenantId: string;
|
|
34
|
+
status: "active" | "error" | "expired" | "revoked";
|
|
35
|
+
description: string | null;
|
|
36
|
+
principalId: string | null;
|
|
37
|
+
scopes: string[] | null;
|
|
38
|
+
metadata: unknown;
|
|
39
|
+
oauthClientId: string | null;
|
|
40
|
+
type: "api_key" | "oauth_token" | "certificate" | "other";
|
|
41
|
+
secret: string;
|
|
42
|
+
refreshSecret: string | null;
|
|
43
|
+
} | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Resolves a provider by name, walking up the tenant hierarchy.
|
|
46
|
+
* Returns the first match (child shadows parent).
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveProviderByName(db: DB["db"], tenantId: string, name: string): Promise<{
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
createdAt: Date;
|
|
52
|
+
updatedAt: Date;
|
|
53
|
+
tenantId: string;
|
|
54
|
+
plugin: string;
|
|
55
|
+
apiBaseUrl: string | null;
|
|
56
|
+
authorizationUrl: string | null;
|
|
57
|
+
tokenUrl: string | null;
|
|
58
|
+
userInfoUrl: string | null;
|
|
59
|
+
scopes: string[] | null;
|
|
60
|
+
metadata: unknown;
|
|
61
|
+
} | null>;
|
|
62
|
+
/**
|
|
63
|
+
* Resolves an OAuth client for a provider, walking up the tenant hierarchy.
|
|
64
|
+
* Returns the first match (child shadows parent).
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolveOAuthClient(db: DB["db"], tenantId: string, providerId: string): Promise<{
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
createdAt: Date;
|
|
70
|
+
updatedAt: Date;
|
|
71
|
+
providerId: string;
|
|
72
|
+
tenantId: string;
|
|
73
|
+
metadata: unknown;
|
|
74
|
+
clientId: string;
|
|
75
|
+
clientSecret: string;
|
|
76
|
+
redirectUris: string[] | null;
|
|
77
|
+
defaultScopes: string[] | null;
|
|
78
|
+
} | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Resolves a credential by name, walking up the tenant hierarchy.
|
|
81
|
+
* Returns the first match (child shadows parent).
|
|
82
|
+
*/
|
|
83
|
+
export declare function resolveCredentialByName(db: DB["db"], tenantId: string, name: string): Promise<{
|
|
84
|
+
id: string;
|
|
85
|
+
name: string;
|
|
86
|
+
createdAt: Date;
|
|
87
|
+
updatedAt: Date;
|
|
88
|
+
expiresAt: Date | null;
|
|
89
|
+
providerId: string;
|
|
90
|
+
tenantId: string;
|
|
91
|
+
status: "active" | "error" | "expired" | "revoked";
|
|
92
|
+
description: string | null;
|
|
93
|
+
principalId: string | null;
|
|
94
|
+
scopes: string[] | null;
|
|
95
|
+
metadata: unknown;
|
|
96
|
+
oauthClientId: string | null;
|
|
97
|
+
type: "api_key" | "oauth_token" | "certificate" | "other";
|
|
98
|
+
secret: string;
|
|
99
|
+
refreshSecret: string | null;
|
|
100
|
+
} | null>;
|
|
101
|
+
/**
|
|
102
|
+
* Resolves a credential by ID, validating that it belongs to the
|
|
103
|
+
* given tenant or one of its ancestors.
|
|
104
|
+
*/
|
|
105
|
+
export declare function resolveCredentialById(db: DB["db"], tenantId: string, credentialId: string): Promise<{
|
|
106
|
+
id: string;
|
|
107
|
+
name: string;
|
|
108
|
+
createdAt: Date;
|
|
109
|
+
updatedAt: Date;
|
|
110
|
+
expiresAt: Date | null;
|
|
111
|
+
providerId: string;
|
|
112
|
+
tenantId: string;
|
|
113
|
+
status: "active" | "error" | "expired" | "revoked";
|
|
114
|
+
description: string | null;
|
|
115
|
+
principalId: string | null;
|
|
116
|
+
scopes: string[] | null;
|
|
117
|
+
metadata: unknown;
|
|
118
|
+
oauthClientId: string | null;
|
|
119
|
+
type: "api_key" | "oauth_token" | "certificate" | "other";
|
|
120
|
+
secret: string;
|
|
121
|
+
refreshSecret: string | null;
|
|
122
|
+
} | null>;
|
|
123
|
+
type CredentialRequirement = {
|
|
124
|
+
providerName: string;
|
|
125
|
+
scopes?: string[];
|
|
126
|
+
source: "tenant" | "creator" | "invoker";
|
|
127
|
+
name?: string;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Resolves a credential matching an agent definition requirement.
|
|
131
|
+
* Used at agent launch time by the control plane to satisfy a definition's
|
|
132
|
+
* tool and integration credentials (inference sources resolve through the
|
|
133
|
+
* catalog, not this path).
|
|
134
|
+
*/
|
|
135
|
+
export declare function resolveCredentialRequirement(db: DB["db"], tenantId: string, requirement: CredentialRequirement, creatorPrincipalId: string | null, invokerPrincipalId: string | null): Promise<{
|
|
136
|
+
credential: {
|
|
137
|
+
id: string;
|
|
138
|
+
name: string;
|
|
139
|
+
createdAt: Date;
|
|
140
|
+
updatedAt: Date;
|
|
141
|
+
expiresAt: Date | null;
|
|
142
|
+
providerId: string;
|
|
143
|
+
tenantId: string;
|
|
144
|
+
status: "active" | "error" | "expired" | "revoked";
|
|
145
|
+
description: string | null;
|
|
146
|
+
principalId: string | null;
|
|
147
|
+
scopes: string[] | null;
|
|
148
|
+
metadata: unknown;
|
|
149
|
+
oauthClientId: string | null;
|
|
150
|
+
type: "api_key" | "oauth_token" | "certificate" | "other";
|
|
151
|
+
secret: string;
|
|
152
|
+
refreshSecret: string | null;
|
|
153
|
+
};
|
|
154
|
+
provider: {
|
|
155
|
+
id: string;
|
|
156
|
+
name: string;
|
|
157
|
+
createdAt: Date;
|
|
158
|
+
updatedAt: Date;
|
|
159
|
+
tenantId: string;
|
|
160
|
+
plugin: string;
|
|
161
|
+
apiBaseUrl: string | null;
|
|
162
|
+
authorizationUrl: string | null;
|
|
163
|
+
tokenUrl: string | null;
|
|
164
|
+
userInfoUrl: string | null;
|
|
165
|
+
scopes: string[] | null;
|
|
166
|
+
metadata: unknown;
|
|
167
|
+
};
|
|
168
|
+
} | null>;
|
|
169
|
+
/**
|
|
170
|
+
* A launch-blocking CONFIGURATION failure for one binding: a binding no
|
|
171
|
+
* credential resolves, a provider with no API origin (can't pin an http
|
|
172
|
+
* handle), or an ambiguous match. Distinct from an infrastructure failure (a DB
|
|
173
|
+
* read fault), which `buildCredentialDelivery` THROWS rather than returning --
|
|
174
|
+
* so a caller never mistakes a transient fault for revocation.
|
|
175
|
+
*/
|
|
176
|
+
export type CredentialDeliveryFailure = {
|
|
177
|
+
code: "unresolved" | "no_origin" | "ambiguous";
|
|
178
|
+
binding: {
|
|
179
|
+
provider: string;
|
|
180
|
+
package: string;
|
|
181
|
+
handle: string;
|
|
182
|
+
};
|
|
183
|
+
message: string;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Outcome of `buildCredentialDelivery`. `ok: true` carries the material +
|
|
187
|
+
* descriptors delivered to the tools; `delivery` is `undefined` when there are
|
|
188
|
+
* no bindings. `ok: false` carries the first launch-blocking configuration
|
|
189
|
+
* failure for the caller to map to a fail-closed response.
|
|
190
|
+
*/
|
|
191
|
+
export type BuildCredentialDeliveryResult = {
|
|
192
|
+
ok: true;
|
|
193
|
+
delivery: CredentialDelivery | undefined;
|
|
194
|
+
} | {
|
|
195
|
+
ok: false;
|
|
196
|
+
reason: CredentialDeliveryFailure;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Resolve a definition's credential bindings into the material + per-handle
|
|
200
|
+
* descriptors delivered to its tools. Each credential's secret is decrypted
|
|
201
|
+
* once, keyed by credentialId (a credential backing several handles is
|
|
202
|
+
* decrypted once).
|
|
203
|
+
*
|
|
204
|
+
* This path delivers credential material only; it does not mint, stamp, or
|
|
205
|
+
* carry any grant. Credential-use authorization is enforced by a separate grant
|
|
206
|
+
* layer.
|
|
207
|
+
*
|
|
208
|
+
* The workflow-deploy path (`deployCodeSourcedWorkflow`) is the only caller
|
|
209
|
+
* today, using `delivery`. Returning a discriminated result rather than an HTTP
|
|
210
|
+
* response keeps it safe to call off the request path: a configuration failure
|
|
211
|
+
* is `ok: false`, and a transient DB read fault THROWS so the caller surfaces it
|
|
212
|
+
* rather than silently dropping a still-valid credential.
|
|
213
|
+
*/
|
|
214
|
+
export declare function buildCredentialDelivery(args: {
|
|
215
|
+
db: DB["db"];
|
|
216
|
+
tenantId: string;
|
|
217
|
+
bindings: readonly CredentialBinding[];
|
|
218
|
+
creatorPrincipalId: string | null;
|
|
219
|
+
invokerPrincipalId: string | null;
|
|
220
|
+
credentialCipher: CredentialCipher;
|
|
221
|
+
}): Promise<BuildCredentialDeliveryResult>;
|
|
222
|
+
export {};
|