@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.
Files changed (241) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +23 -4
  3. package/dist/approval-store.d.ts +52 -0
  4. package/dist/approval-store.js +79 -0
  5. package/dist/asset-resolution.d.ts +52 -0
  6. package/dist/asset-resolution.js +66 -0
  7. package/dist/catalog-resolution.d.ts +76 -0
  8. package/dist/catalog-resolution.js +151 -0
  9. package/dist/client.d.ts +19 -0
  10. package/dist/client.js +18 -0
  11. package/dist/config.d.ts +11 -0
  12. package/dist/config.js +16 -0
  13. package/dist/connection.d.ts +3 -0
  14. package/dist/connection.js +26 -0
  15. package/dist/credential-resolution.d.ts +222 -0
  16. package/dist/credential-resolution.js +255 -0
  17. package/dist/grant-store.d.ts +3 -0
  18. package/dist/grant-store.js +59 -0
  19. package/dist/index.d.ts +22 -0
  20. package/dist/index.js +20 -0
  21. package/dist/migrate.d.ts +36 -0
  22. package/dist/migrate.js +135 -0
  23. package/dist/model-source-resolution.d.ts +115 -0
  24. package/dist/model-source-resolution.js +291 -0
  25. package/dist/parse-row.d.ts +373 -0
  26. package/dist/parse-row.js +232 -0
  27. package/dist/pg-error.d.ts +3 -0
  28. package/dist/pg-error.js +19 -0
  29. package/dist/pricing.d.ts +15 -0
  30. package/dist/pricing.js +24 -0
  31. package/dist/rekey-credential-secrets.d.ts +13 -0
  32. package/dist/rekey-credential-secrets.js +61 -0
  33. package/dist/schema/approvals.d.ts +245 -0
  34. package/dist/schema/approvals.js +52 -0
  35. package/dist/schema/assets.d.ts +143 -0
  36. package/{src/schema/assets.ts → dist/schema/assets.js} +7 -16
  37. package/dist/schema/auth.d.ts +606 -0
  38. package/dist/schema/auth.js +47 -0
  39. package/dist/schema/catalog.d.ts +811 -0
  40. package/dist/schema/catalog.js +108 -0
  41. package/dist/schema/column-types.d.ts +26 -0
  42. package/dist/schema/column-types.js +15 -0
  43. package/dist/schema/credentials.d.ts +305 -0
  44. package/{src/schema/credentials.ts → dist/schema/credentials.js} +16 -22
  45. package/dist/schema/git-tokens.d.ts +256 -0
  46. package/{src/schema/git-tokens.ts → dist/schema/git-tokens.js} +16 -39
  47. package/dist/schema/grants.d.ts +211 -0
  48. package/dist/schema/grants.js +30 -0
  49. package/dist/schema/index.d.ts +25 -0
  50. package/dist/schema/index.js +25 -0
  51. package/dist/schema/messages.d.ts +414 -0
  52. package/dist/schema/messages.js +82 -0
  53. package/dist/schema/oauth-clients.d.ts +246 -0
  54. package/{src/schema/oauth-clients.ts → dist/schema/oauth-clients.js} +8 -14
  55. package/dist/schema/offerings.d.ts +160 -0
  56. package/dist/schema/offerings.js +24 -0
  57. package/dist/schema/principals.d.ts +128 -0
  58. package/dist/schema/principals.js +23 -0
  59. package/dist/schema/providers.d.ts +237 -0
  60. package/dist/schema/providers.js +22 -0
  61. package/dist/schema/roles.d.ts +242 -0
  62. package/dist/schema/roles.js +37 -0
  63. package/dist/schema/session-assets.d.ts +92 -0
  64. package/dist/schema/session-assets.js +45 -0
  65. package/dist/schema/sessions.d.ts +143 -0
  66. package/dist/schema/sessions.js +29 -0
  67. package/dist/schema/sidecar-allocation.d.ts +406 -0
  68. package/dist/schema/sidecar-allocation.js +57 -0
  69. package/dist/schema/sidecar.d.ts +145 -0
  70. package/dist/schema/sidecar.js +28 -0
  71. package/dist/schema/signal-correlations.d.ts +177 -0
  72. package/dist/schema/signal-correlations.js +31 -0
  73. package/dist/schema/tenants.d.ts +235 -0
  74. package/{src/schema/tenants.ts → dist/schema/tenants.js} +10 -27
  75. package/dist/schema/wallets.d.ts +354 -0
  76. package/dist/schema/wallets.js +43 -0
  77. package/dist/schema/workflow-definitions.d.ts +371 -0
  78. package/dist/schema/workflow-definitions.js +97 -0
  79. package/dist/schema/workflow-run-dispatch.d.ts +328 -0
  80. package/dist/schema/workflow-run-dispatch.js +56 -0
  81. package/dist/schema/workflow-run-execution.d.ts +126 -0
  82. package/dist/schema/workflow-run-execution.js +48 -0
  83. package/dist/schema/workflow-run-launch-spec.d.ts +200 -0
  84. package/dist/schema/workflow-run-launch-spec.js +26 -0
  85. package/dist/schema/workflow-run.d.ts +230 -0
  86. package/dist/schema/workflow-run.js +102 -0
  87. package/dist/sidecar-allocation-store.d.ts +171 -0
  88. package/dist/sidecar-allocation-store.js +512 -0
  89. package/dist/signal-correlation-store.d.ts +36 -0
  90. package/dist/signal-correlation-store.js +63 -0
  91. package/dist/tenant-hierarchy.d.ts +23 -0
  92. package/dist/tenant-hierarchy.js +60 -0
  93. package/dist/workflow-definition-store.d.ts +55 -0
  94. package/dist/workflow-definition-store.js +93 -0
  95. package/dist/workflow-run-dispatch-store.d.ts +80 -0
  96. package/dist/workflow-run-dispatch-store.js +298 -0
  97. package/dist/workflow-run-launch-spec-store.d.ts +13 -0
  98. package/dist/workflow-run-launch-spec-store.js +30 -0
  99. package/dist/workflow-run-store.d.ts +54 -0
  100. package/dist/workflow-run-store.js +85 -0
  101. package/migrations/0029_loose_warlock.sql +1 -0
  102. package/migrations/0030_session_asset_audit_split.sql +5 -0
  103. package/migrations/0031_gigantic_nicolaos.sql +68 -0
  104. package/migrations/0032_lethal_misty_knight.sql +1 -0
  105. package/migrations/0033_old_payback.sql +1 -0
  106. package/migrations/0034_sleepy_songbird.sql +11 -0
  107. package/migrations/0035_violet_giant_man.sql +3 -0
  108. package/migrations/0036_sharp_the_executioner.sql +2 -0
  109. package/migrations/0037_credential_use_backfill.sql +39 -0
  110. package/migrations/0038_chilly_blacklash.sql +37 -0
  111. package/migrations/0039_quick_carnage.sql +2 -0
  112. package/migrations/0040_reshape_approval_origin.sql +24 -0
  113. package/migrations/0041_make_approval_timeout_at_nullable.sql +1 -0
  114. package/migrations/0042_youthful_mantis.sql +2 -0
  115. package/migrations/0043_signal_correlation_deployment_fk.sql +1 -0
  116. package/migrations/0044_model_offering_quirks.sql +1 -0
  117. package/migrations/0045_create_workflow_run.sql +13 -0
  118. package/migrations/0046_approval_signal_correlation_run_fk.sql +2 -0
  119. package/migrations/0047_create_workflow_definition.sql +30 -0
  120. package/migrations/0048_workflow_definition_origin_agent_id.sql +2 -0
  121. package/migrations/0049_curly_omega_flight.sql +2 -0
  122. package/migrations/0050_late_crystal.sql +10 -0
  123. package/migrations/0051_funny_madelyne_pryor.sql +1 -0
  124. package/migrations/0052_drop_inference_turn_instance_fk.sql +1 -0
  125. package/migrations/0053_session_mail_session_id_index.sql +1 -0
  126. package/migrations/0054_rekey_instance_grants_to_workflow_run.sql +10 -0
  127. package/migrations/0055_backfill_anchor_workflow_runs.sql +69 -0
  128. package/migrations/0056_repoint_deployment_fks_to_anchor_run.sql +32 -0
  129. package/migrations/0057_drop_workflow_deployment_projection.sql +22 -0
  130. package/migrations/0058_repoint_offering_fk_to_definition.sql +41 -0
  131. package/migrations/0059_repoint_transaction_fk_to_run.sql +10 -0
  132. package/migrations/0060_drop_session_mail_instance_fk.sql +6 -0
  133. package/migrations/0061_drop_session_asset_instance_fk.sql +7 -0
  134. package/migrations/0062_drop_agent_asset_table.sql +11 -0
  135. package/migrations/0063_repoint_agent_role_fk_to_definition.sql +39 -0
  136. package/migrations/0064_repoint_agent_session_fk_to_definition.sql +47 -0
  137. package/migrations/0065_add_workflow_definition_model_requirements.sql +37 -0
  138. package/migrations/0066_rekey_agent_definition_principals_to_workflow.sql +27 -0
  139. package/migrations/0067_add_workflow_definition_kind.sql +10 -0
  140. package/migrations/0068_drop_agent_tables_and_origin_agent_id.sql +31 -0
  141. package/migrations/0069_drop_workflow_definition_kind.sql +10 -0
  142. package/migrations/0070_flashy_proteus.sql +13 -0
  143. package/migrations/0072_add_workflow_definition_credential_bindings.sql +1 -0
  144. package/migrations/0073_grant_target_exactly_one_check.sql +13 -0
  145. package/migrations/0074_add_provider_api_base_url.sql +1 -0
  146. package/migrations/0075_workflow_run_launch_spec.sql +17 -0
  147. package/migrations/0076_sidecar_allocation.sql +40 -0
  148. package/migrations/0077_workflow_run_dispatch.sql +29 -0
  149. package/migrations/0078_workflow_run_dispatch_kind.sql +2 -0
  150. package/migrations/0079_rename_workflow_run_deployment_id_to_anchor_run_id.sql +4 -0
  151. package/migrations/0080_rename_correlation_approval_deployment_id_to_anchor_run_id.sql +9 -0
  152. package/migrations/0081_workflow_definition_content_hash_and_approved_wire_hash.sql +4 -0
  153. package/migrations/0082_blue_black_queen.sql +1 -0
  154. package/migrations/0083_replace_launch_spec_snapshot_with_frozen_bundle.sql +3 -0
  155. package/migrations/0084_delete_orphaned_credential_grants.sql +22 -0
  156. package/migrations/meta/0029_snapshot.json +2664 -0
  157. package/migrations/meta/0030_snapshot.json +2670 -0
  158. package/migrations/meta/0031_snapshot.json +3100 -0
  159. package/migrations/meta/0032_snapshot.json +3106 -0
  160. package/migrations/meta/0033_snapshot.json +3112 -0
  161. package/migrations/meta/0034_snapshot.json +3198 -0
  162. package/migrations/meta/0035_snapshot.json +3225 -0
  163. package/migrations/meta/0036_snapshot.json +3237 -0
  164. package/migrations/meta/0037_snapshot.json +3237 -0
  165. package/migrations/meta/0038_snapshot.json +3470 -0
  166. package/migrations/meta/0039_snapshot.json +3470 -0
  167. package/migrations/meta/0040_snapshot.json +3489 -0
  168. package/migrations/meta/0041_snapshot.json +3489 -0
  169. package/migrations/meta/0042_snapshot.json +3489 -0
  170. package/migrations/meta/0043_snapshot.json +3498 -0
  171. package/migrations/meta/0044_snapshot.json +3504 -0
  172. package/migrations/meta/0045_snapshot.json +3589 -0
  173. package/migrations/meta/0046_snapshot.json +3607 -0
  174. package/migrations/meta/0047_snapshot.json +3832 -0
  175. package/migrations/meta/0048_snapshot.json +3853 -0
  176. package/migrations/meta/0049_snapshot.json +3854 -0
  177. package/migrations/meta/0050_snapshot.json +3924 -0
  178. package/migrations/meta/0051_snapshot.json +3940 -0
  179. package/migrations/meta/0052_snapshot.json +3931 -0
  180. package/migrations/meta/0053_snapshot.json +3952 -0
  181. package/migrations/meta/0054_snapshot.json +3952 -0
  182. package/migrations/meta/0055_snapshot.json +3952 -0
  183. package/migrations/meta/0056_snapshot.json +3952 -0
  184. package/migrations/meta/0057_snapshot.json +3839 -0
  185. package/migrations/meta/0058_snapshot.json +3839 -0
  186. package/migrations/meta/0059_snapshot.json +3839 -0
  187. package/migrations/meta/0060_snapshot.json +3830 -0
  188. package/migrations/meta/0061_snapshot.json +3821 -0
  189. package/migrations/meta/0062_snapshot.json +3723 -0
  190. package/migrations/meta/0063_snapshot.json +3723 -0
  191. package/migrations/meta/0064_snapshot.json +3723 -0
  192. package/migrations/meta/0065_snapshot.json +3729 -0
  193. package/migrations/meta/0066_snapshot.json +3729 -0
  194. package/migrations/meta/0067_snapshot.json +3736 -0
  195. package/migrations/meta/0068_snapshot.json +3347 -0
  196. package/migrations/meta/0069_snapshot.json +3340 -0
  197. package/migrations/meta/0070_snapshot.json +3444 -0
  198. package/migrations/meta/0072_snapshot.json +3450 -0
  199. package/migrations/meta/0073_snapshot.json +3455 -0
  200. package/migrations/meta/0074_snapshot.json +3461 -0
  201. package/migrations/meta/0075_snapshot.json +3567 -0
  202. package/migrations/meta/0076_snapshot.json +3851 -0
  203. package/migrations/meta/0077_snapshot.json +4067 -0
  204. package/migrations/meta/0078_snapshot.json +4078 -0
  205. package/migrations/meta/0079_snapshot.json +4078 -0
  206. package/migrations/meta/0080_snapshot.json +4078 -0
  207. package/migrations/meta/0081_snapshot.json +4096 -0
  208. package/migrations/meta/0082_snapshot.json +4102 -0
  209. package/migrations/meta/0083_snapshot.json +4096 -0
  210. package/migrations/meta/0084_snapshot.json +4096 -0
  211. package/migrations/meta/_journal.json +385 -0
  212. package/package.json +25 -11
  213. package/drizzle.config.ts +0 -23
  214. package/src/client.ts +0 -24
  215. package/src/config.ts +0 -19
  216. package/src/connection.ts +0 -27
  217. package/src/credential-resolution.ts +0 -378
  218. package/src/grant-store.ts +0 -51
  219. package/src/index.ts +0 -32
  220. package/src/migrate.test.ts +0 -35
  221. package/src/migrate.ts +0 -168
  222. package/src/parse-row.test.ts +0 -113
  223. package/src/parse-row.ts +0 -185
  224. package/src/schema/agent-assets.ts +0 -21
  225. package/src/schema/agents.ts +0 -49
  226. package/src/schema/auth.ts +0 -51
  227. package/src/schema/grants.ts +0 -26
  228. package/src/schema/index.ts +0 -19
  229. package/src/schema/instances.ts +0 -36
  230. package/src/schema/messages.ts +0 -108
  231. package/src/schema/offerings.ts +0 -20
  232. package/src/schema/principals.ts +0 -28
  233. package/src/schema/providers.ts +0 -23
  234. package/src/schema/roles.ts +0 -51
  235. package/src/schema/session-assets.ts +0 -49
  236. package/src/schema/sessions.ts +0 -26
  237. package/src/schema/sidecar.ts +0 -14
  238. package/src/schema/wallets.ts +0 -44
  239. package/src/tenant-hierarchy.ts +0 -34
  240. package/tsconfig.json +0 -4
  241. 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
+ }
@@ -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
+ }
@@ -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,3 @@
1
+ import postgres from "postgres";
2
+ import type { DBConfig } from "./config.js";
3
+ export declare function createConnection(config: DBConfig): postgres.Sql<{}>;
@@ -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 {};