@intx/db 0.1.2 → 0.2.2

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 (121) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +21 -2
  3. package/dist/asset-resolution.d.ts +52 -0
  4. package/dist/asset-resolution.js +66 -0
  5. package/dist/catalog-resolution.d.ts +76 -0
  6. package/dist/catalog-resolution.js +151 -0
  7. package/dist/client.d.ts +9 -0
  8. package/dist/client.js +18 -0
  9. package/dist/config.d.ts +11 -0
  10. package/dist/config.js +16 -0
  11. package/dist/connection.d.ts +3 -0
  12. package/dist/connection.js +23 -0
  13. package/dist/credential-resolution.d.ts +110 -0
  14. package/dist/credential-resolution.js +116 -0
  15. package/dist/grant-store.d.ts +3 -0
  16. package/dist/grant-store.js +37 -0
  17. package/dist/index.d.ts +13 -0
  18. package/dist/index.js +12 -0
  19. package/dist/migrate.d.ts +36 -0
  20. package/dist/migrate.js +135 -0
  21. package/dist/model-source-resolution.d.ts +69 -0
  22. package/dist/model-source-resolution.js +165 -0
  23. package/dist/parse-row.d.ts +193 -0
  24. package/dist/parse-row.js +141 -0
  25. package/dist/pg-error.d.ts +3 -0
  26. package/dist/pg-error.js +19 -0
  27. package/dist/pricing.d.ts +15 -0
  28. package/dist/pricing.js +24 -0
  29. package/dist/schema/agent-assets.d.ts +109 -0
  30. package/dist/schema/agent-assets.js +15 -0
  31. package/dist/schema/agents.d.ts +405 -0
  32. package/dist/schema/agents.js +57 -0
  33. package/dist/schema/assets.d.ts +143 -0
  34. package/{src/schema/assets.ts → dist/schema/assets.js} +7 -16
  35. package/dist/schema/auth.d.ts +606 -0
  36. package/dist/schema/auth.js +47 -0
  37. package/dist/schema/catalog.d.ts +794 -0
  38. package/dist/schema/catalog.js +102 -0
  39. package/dist/schema/column-types.d.ts +26 -0
  40. package/dist/schema/column-types.js +15 -0
  41. package/dist/schema/credentials.d.ts +305 -0
  42. package/{src/schema/credentials.ts → dist/schema/credentials.js} +16 -22
  43. package/dist/schema/git-tokens.d.ts +256 -0
  44. package/{src/schema/git-tokens.ts → dist/schema/git-tokens.js} +15 -38
  45. package/dist/schema/grants.d.ts +211 -0
  46. package/dist/schema/grants.js +24 -0
  47. package/dist/schema/index.d.ts +21 -0
  48. package/dist/schema/index.js +21 -0
  49. package/dist/schema/instances.d.ts +262 -0
  50. package/dist/schema/instances.js +39 -0
  51. package/dist/schema/messages.d.ts +414 -0
  52. package/dist/schema/messages.js +71 -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 +18 -0
  57. package/dist/schema/principals.d.ts +128 -0
  58. package/{src/schema/principals.ts → dist/schema/principals.js} +7 -14
  59. package/dist/schema/providers.d.ts +220 -0
  60. package/{src/schema/providers.ts → dist/schema/providers.js} +5 -11
  61. package/dist/schema/roles.d.ts +242 -0
  62. package/dist/schema/roles.js +33 -0
  63. package/dist/schema/session-assets.d.ts +129 -0
  64. package/dist/schema/session-assets.js +28 -0
  65. package/dist/schema/sessions.d.ts +143 -0
  66. package/dist/schema/sessions.js +24 -0
  67. package/dist/schema/sidecar.d.ts +128 -0
  68. package/dist/schema/sidecar.js +18 -0
  69. package/dist/schema/tenants.d.ts +235 -0
  70. package/{src/schema/tenants.ts → dist/schema/tenants.js} +10 -27
  71. package/dist/schema/wallets.d.ts +354 -0
  72. package/dist/schema/wallets.js +41 -0
  73. package/dist/schema/workflow-deployments.d.ts +129 -0
  74. package/dist/schema/workflow-deployments.js +37 -0
  75. package/dist/tenant-hierarchy.d.ts +22 -0
  76. package/dist/tenant-hierarchy.js +55 -0
  77. package/migrations/0029_loose_warlock.sql +1 -0
  78. package/migrations/0030_session_asset_audit_split.sql +5 -0
  79. package/migrations/0031_gigantic_nicolaos.sql +68 -0
  80. package/migrations/0032_lethal_misty_knight.sql +1 -0
  81. package/migrations/0033_old_payback.sql +1 -0
  82. package/migrations/0034_sleepy_songbird.sql +11 -0
  83. package/migrations/0035_violet_giant_man.sql +3 -0
  84. package/migrations/0036_sharp_the_executioner.sql +2 -0
  85. package/migrations/meta/0029_snapshot.json +2664 -0
  86. package/migrations/meta/0030_snapshot.json +2670 -0
  87. package/migrations/meta/0031_snapshot.json +3100 -0
  88. package/migrations/meta/0032_snapshot.json +3106 -0
  89. package/migrations/meta/0033_snapshot.json +3112 -0
  90. package/migrations/meta/0034_snapshot.json +3198 -0
  91. package/migrations/meta/0035_snapshot.json +3225 -0
  92. package/migrations/meta/0036_snapshot.json +3237 -0
  93. package/migrations/meta/_journal.json +56 -0
  94. package/package.json +22 -11
  95. package/drizzle.config.ts +0 -23
  96. package/src/client.ts +0 -24
  97. package/src/config.ts +0 -19
  98. package/src/connection.ts +0 -27
  99. package/src/credential-resolution.ts +0 -378
  100. package/src/grant-store.ts +0 -51
  101. package/src/index.ts +0 -32
  102. package/src/migrate.test.ts +0 -35
  103. package/src/migrate.ts +0 -168
  104. package/src/parse-row.test.ts +0 -113
  105. package/src/parse-row.ts +0 -185
  106. package/src/schema/agent-assets.ts +0 -21
  107. package/src/schema/agents.ts +0 -49
  108. package/src/schema/auth.ts +0 -51
  109. package/src/schema/grants.ts +0 -26
  110. package/src/schema/index.ts +0 -19
  111. package/src/schema/instances.ts +0 -36
  112. package/src/schema/messages.ts +0 -108
  113. package/src/schema/offerings.ts +0 -20
  114. package/src/schema/roles.ts +0 -51
  115. package/src/schema/session-assets.ts +0 -49
  116. package/src/schema/sessions.ts +0 -26
  117. package/src/schema/sidecar.ts +0 -14
  118. package/src/schema/wallets.ts +0 -44
  119. package/src/tenant-hierarchy.ts +0 -34
  120. package/tsconfig.json +0 -4
  121. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,165 @@
1
+ import { and, eq } from "drizzle-orm";
2
+ import { InvokerModelPreferences, ModelRequirements, } from "@intx/types";
3
+ import { listVisibleOfferings, } from "./catalog-resolution.js";
4
+ import { resolveCredentialById } from "./credential-resolution.js";
5
+ import { agent } from "./schema/agents.js";
6
+ function byPriority(a, b) {
7
+ if (a.offering.priority !== b.offering.priority) {
8
+ return a.offering.priority - b.offering.priority;
9
+ }
10
+ // Deterministic tiebreak so the head/defaultSource never flaps across
11
+ // resolutions. Equal-priority load balancing is future work.
12
+ return a.offering.id < b.offering.id ? -1 : 1;
13
+ }
14
+ /**
15
+ * Applies a provider preference over an already-priority-sorted candidate
16
+ * list. `pin` restricts to the named providers (ordered by the preference);
17
+ * `prefer` fronts the named providers in preference order and keeps the rest
18
+ * as fallback. With no preference the priority order stands.
19
+ */
20
+ function applyPreference(candidates, preference) {
21
+ if (preference === undefined)
22
+ return candidates;
23
+ const rank = new Map(preference.order.map((name, i) => [name, i]));
24
+ // Partition by whether the preference names the provider, capturing the
25
+ // rank as we go. `ranked` only ever holds named providers, so the sort
26
+ // reads a concrete rank and never needs a fallback for a missing one.
27
+ const ranked = [];
28
+ const rest = [];
29
+ for (const offering of candidates) {
30
+ const position = rank.get(offering.provider.name);
31
+ if (position === undefined) {
32
+ rest.push(offering);
33
+ }
34
+ else {
35
+ ranked.push({ offering, rank: position });
36
+ }
37
+ }
38
+ ranked.sort((a, b) => a.rank - b.rank);
39
+ const named = ranked.map((entry) => entry.offering);
40
+ // `pin` drops every provider the preference did not name; `prefer` keeps
41
+ // the rest as fallback after the named providers.
42
+ return preference.mode === "pin" ? named : [...named, ...rest];
43
+ }
44
+ async function buildSource(db, tenantId, resolved) {
45
+ const { provider, model, offering } = resolved;
46
+ if (provider.credentialId === null) {
47
+ // No credential reference. A wallet-backed provider is a valid catalog
48
+ // row but not launchable in this credential-backed-only release;
49
+ // anything else is a misconfigured row.
50
+ if (provider.walletId !== null) {
51
+ return {
52
+ ok: false,
53
+ skip: { reason: "wallet_backed", provider: provider.name },
54
+ };
55
+ }
56
+ return {
57
+ ok: false,
58
+ skip: { reason: "provider_misconfigured", provider: provider.name },
59
+ };
60
+ }
61
+ // Resolve the secret through the tenant-scoped credential resolver so a
62
+ // provider row referencing a credential outside the tenant's ancestor
63
+ // chain cannot leak that secret (INTR-203: the chain is the authority).
64
+ const credential = await resolveCredentialById(db, tenantId, provider.credentialId);
65
+ if (credential === null) {
66
+ return {
67
+ ok: false,
68
+ skip: { reason: "credential_unresolved", provider: provider.name },
69
+ };
70
+ }
71
+ return {
72
+ ok: true,
73
+ source: {
74
+ id: offering.id,
75
+ provider: provider.plugin,
76
+ baseURL: provider.baseURL,
77
+ apiKey: credential.secret,
78
+ model: model.canonicalName,
79
+ capabilities: offering.capabilities,
80
+ },
81
+ };
82
+ }
83
+ /**
84
+ * Resolves an agent's model requirements against the tenant catalog into an
85
+ * ordered `InferenceSource[]` for the harness.
86
+ *
87
+ * For each requirement, the tenant-visible offerings for the named model are
88
+ * filtered by the required capabilities, ordered by catalog priority, then
89
+ * reordered by the creator preference and finally the invoker preference
90
+ * (invoker preferences key on the canonical model name). Each surviving
91
+ * offering is resolved to a credential-backed source; offerings that cannot
92
+ * produce one are skipped. A required model that yields no source makes the
93
+ * agent unlaunchable.
94
+ */
95
+ export async function resolveModelSources(db, tenantId, requirements, opts) {
96
+ if (requirements.length === 0) {
97
+ return { ok: false, reason: "no_requirements" };
98
+ }
99
+ const visible = await listVisibleOfferings(db, tenantId);
100
+ const sources = [];
101
+ for (const requirement of requirements) {
102
+ let candidates = visible
103
+ .filter((o) => o.model.canonicalName === requirement.model)
104
+ .sort(byPriority);
105
+ if (requirement.capabilities && requirement.capabilities.length > 0) {
106
+ const required = requirement.capabilities;
107
+ candidates = candidates.filter((o) => required.every((c) => o.offering.capabilities.includes(c)));
108
+ }
109
+ candidates = applyPreference(candidates, requirement.providers);
110
+ candidates = applyPreference(candidates, opts?.invokerPreferences?.[requirement.model]);
111
+ const skips = [];
112
+ const modelSources = [];
113
+ for (const candidate of candidates) {
114
+ const built = await buildSource(db, tenantId, candidate);
115
+ if (built.ok) {
116
+ modelSources.push(built.source);
117
+ }
118
+ else {
119
+ skips.push(built.skip);
120
+ }
121
+ }
122
+ if (modelSources.length === 0) {
123
+ return {
124
+ ok: false,
125
+ reason: "model_unavailable",
126
+ model: requirement.model,
127
+ skips,
128
+ };
129
+ }
130
+ sources.push(...modelSources);
131
+ }
132
+ return { ok: true, sources };
133
+ }
134
+ /**
135
+ * Resolves the ordered sources for a running instance from persisted state:
136
+ * the agent definition's model requirements and the invoker's launch-time
137
+ * preferences stored on the instance row. Launch, credential-rotation push,
138
+ * and sidecar reconnect all resolve through this, so a running instance's
139
+ * source list is a pure function of persisted state — re-resolution
140
+ * reproduces the launch ordering, including the invoker's reorder/restrict.
141
+ */
142
+ export async function resolveInstanceModelSources(db, tenantId, instance) {
143
+ // Scope the agent lookup to the resolving tenant, matching the launch
144
+ // route. A cross-tenant agentId resolves to nothing rather than
145
+ // contributing another tenant's model names or preferences.
146
+ const agentRow = await db.query.agent.findFirst({
147
+ where: and(eq(agent.id, instance.agentId), eq(agent.tenantId, tenantId)),
148
+ });
149
+ if (agentRow === undefined) {
150
+ return { ok: false, reason: "no_requirements" };
151
+ }
152
+ const requirements = agentRow.modelRequirements !== null
153
+ ? ModelRequirements.assert(agentRow.modelRequirements)
154
+ : [];
155
+ const preferences = instance.modelPreferences !== null
156
+ ? InvokerModelPreferences.assert(instance.modelPreferences)
157
+ : [];
158
+ const invokerPreferences = {};
159
+ for (const preference of preferences) {
160
+ invokerPreferences[preference.model] = preference.providers;
161
+ }
162
+ return resolveModelSources(db, tenantId, requirements, {
163
+ invokerPreferences,
164
+ });
165
+ }
@@ -0,0 +1,193 @@
1
+ import type { agent, agentVersion, credential, gitToken, grant, modelOffering, modelProvider, oauthClient, offering, provider, tenant, transaction, turnPart, wallet } from "./schema/index.js";
2
+ export declare const GitTokenKindValidator: import("arktype/internal/variants/string.ts").StringType<"pat" | "svc", {}>;
3
+ export declare function parseAgentRow(row: typeof agent.$inferSelect): {
4
+ contextConfig: Record<string, unknown> | null;
5
+ initialState: Record<string, unknown> | null;
6
+ modelConfig: Record<string, unknown> | null;
7
+ capabilities: Record<string, unknown> | null;
8
+ credentialRequirements: {
9
+ providerName: string;
10
+ source: "tenant" | "creator" | "invoker";
11
+ scopes?: string[];
12
+ name?: string;
13
+ }[] | null;
14
+ modelRequirements: {
15
+ model: string;
16
+ capabilities?: ("vision" | "audio-input" | "tool-use" | "extended-thinking" | "structured-output" | "long-context" | "prompt-caching")[];
17
+ providers?: {
18
+ mode: "prefer" | "pin";
19
+ order: string[];
20
+ };
21
+ }[] | null;
22
+ grantRequirements: {
23
+ resource: string;
24
+ action: string;
25
+ source: "creator" | "invoker";
26
+ effect?: "allow" | "deny" | "ask";
27
+ conditions?: Record<string, unknown> | null;
28
+ }[] | null;
29
+ toolPackages: {
30
+ name: string;
31
+ version: string;
32
+ }[];
33
+ id: string;
34
+ name: string;
35
+ createdAt: Date;
36
+ updatedAt: Date;
37
+ tenantId: string;
38
+ status: "deployed" | "stopped";
39
+ creatorPrincipalId: string;
40
+ description: string | null;
41
+ systemPrompt: string | null;
42
+ currentVersion: string;
43
+ };
44
+ export declare function parseAgentVersionRow(row: typeof agentVersion.$inferSelect): {
45
+ status: "active" | "inactive" | "failed";
46
+ id: string;
47
+ createdAt: Date;
48
+ agentId: string;
49
+ version: string;
50
+ };
51
+ export declare function parseGrantRow(row: typeof grant.$inferSelect): {
52
+ effect: "allow" | "deny" | "ask";
53
+ origin: "role" | "system" | "creator" | "invoker";
54
+ conditions: Record<string, unknown> | null;
55
+ id: string;
56
+ createdAt: Date;
57
+ updatedAt: Date;
58
+ expiresAt: Date | null;
59
+ tenantId: string;
60
+ roleId: string | null;
61
+ principalId: string | null;
62
+ resource: string;
63
+ action: string;
64
+ };
65
+ export declare function parseOfferingRow(row: typeof offering.$inferSelect): {
66
+ pricing: Record<string, unknown> | null;
67
+ schema: Record<string, unknown> | null;
68
+ id: string;
69
+ name: string;
70
+ createdAt: Date;
71
+ updatedAt: Date;
72
+ tenantId: string;
73
+ description: string | null;
74
+ agentId: string;
75
+ };
76
+ export declare function parseCredentialRow(row: typeof credential.$inferSelect): {
77
+ type: "api_key" | "oauth_token" | "certificate" | "other";
78
+ status: "active" | "expired" | "revoked" | "error";
79
+ metadata: Record<string, unknown> | null;
80
+ id: string;
81
+ name: string;
82
+ createdAt: Date;
83
+ updatedAt: Date;
84
+ expiresAt: Date | null;
85
+ providerId: string;
86
+ tenantId: string;
87
+ description: string | null;
88
+ principalId: string | null;
89
+ scopes: string[] | null;
90
+ oauthClientId: string | null;
91
+ secret: string;
92
+ refreshSecret: string | null;
93
+ };
94
+ export declare function parseProviderRow(row: typeof provider.$inferSelect): {
95
+ metadata: Record<string, unknown> | null;
96
+ id: string;
97
+ name: string;
98
+ createdAt: Date;
99
+ updatedAt: Date;
100
+ tenantId: string;
101
+ plugin: string;
102
+ authorizationUrl: string | null;
103
+ tokenUrl: string | null;
104
+ userInfoUrl: string | null;
105
+ scopes: string[] | null;
106
+ };
107
+ export declare function parseModelProviderRow(row: typeof modelProvider.$inferSelect): {
108
+ plugin: "anthropic" | "openai" | "openai-compatible" | "google-genai";
109
+ id: string;
110
+ name: string;
111
+ createdAt: Date;
112
+ updatedAt: Date;
113
+ tenantId: string;
114
+ walletId: string | null;
115
+ disabled: boolean;
116
+ baseURL: string;
117
+ credentialId: string | null;
118
+ };
119
+ export declare function parseModelOfferingRow(row: typeof modelOffering.$inferSelect): {
120
+ capabilities: ("vision" | "audio-input" | "tool-use" | "extended-thinking" | "structured-output" | "long-context" | "prompt-caching")[];
121
+ id: string;
122
+ createdAt: Date;
123
+ updatedAt: Date;
124
+ providerId: string;
125
+ tenantId: string;
126
+ disabled: boolean;
127
+ modelId: string;
128
+ priority: number;
129
+ deploymentTags: string[];
130
+ };
131
+ export declare function parseTenantRow(row: typeof tenant.$inferSelect): {
132
+ config: Record<string, unknown> | null;
133
+ domain: string;
134
+ id: string;
135
+ name: string;
136
+ createdAt: Date;
137
+ updatedAt: Date;
138
+ slug: string;
139
+ parentId: string | null;
140
+ };
141
+ export declare function parseWalletRow(row: typeof wallet.$inferSelect): {
142
+ backendType: "crypto" | "fiat" | "credits";
143
+ config: Record<string, unknown> | null;
144
+ id: string;
145
+ name: string;
146
+ createdAt: Date;
147
+ updatedAt: Date;
148
+ tenantId: string;
149
+ currency: string;
150
+ balance: string;
151
+ };
152
+ export declare function parseTransactionRow(row: typeof transaction.$inferSelect): {
153
+ direction: "inbound" | "outbound";
154
+ status: "failed" | "pending" | "completed";
155
+ id: string;
156
+ createdAt: Date;
157
+ agentId: string | null;
158
+ currency: string;
159
+ walletId: string;
160
+ amount: string;
161
+ recipientId: string | null;
162
+ senderId: string | null;
163
+ requestId: string | null;
164
+ };
165
+ export declare function parseOAuthClientRow(row: typeof oauthClient.$inferSelect): {
166
+ metadata: Record<string, unknown> | null;
167
+ id: string;
168
+ name: string;
169
+ createdAt: Date;
170
+ updatedAt: Date;
171
+ providerId: string;
172
+ tenantId: string;
173
+ clientId: string;
174
+ clientSecret: string;
175
+ redirectUris: string[] | null;
176
+ defaultScopes: string[] | null;
177
+ };
178
+ export declare function parseGitTokenRow(row: typeof gitToken.$inferSelect): {
179
+ kind: "pat" | "svc";
180
+ actions: ("init" | "writeTree" | "receivePack" | "createPack" | "resolveRef")[];
181
+ id: string;
182
+ name: string;
183
+ createdAt: Date;
184
+ userId: string;
185
+ expiresAt: Date;
186
+ tenantId: string | null;
187
+ principalId: string | null;
188
+ resource: string;
189
+ tokenHashSha256: Uint8Array<ArrayBufferLike>;
190
+ refPattern: string;
191
+ revokedAt: Date | null;
192
+ };
193
+ export declare function parseTurnPartType(partType: string): (typeof turnPart.$inferInsert)["type"];
@@ -0,0 +1,141 @@
1
+ import { type } from "arktype";
2
+ import { Capability, CredentialRequirement, GrantRequirement, grantEffects, grantOrigins, ModelProviderPlugin, ModelRequirements, } from "@intx/types";
3
+ import { RepoAction } from "@intx/types/sidecar";
4
+ import { ToolPackagePinArray } from "@intx/types/tool-packages";
5
+ const JSONObject = type("Record<string, unknown>");
6
+ const GrantEffectValidator = type.enumerated(...grantEffects);
7
+ const GrantOriginValidator = type.enumerated(...grantOrigins);
8
+ const agentVersionStatuses = ["active", "inactive", "failed"];
9
+ const AgentVersionStatusValidator = type.enumerated(...agentVersionStatuses);
10
+ const credentialTypes = [
11
+ "api_key",
12
+ "oauth_token",
13
+ "certificate",
14
+ "other",
15
+ ];
16
+ const CredentialTypeValidator = type.enumerated(...credentialTypes);
17
+ const credentialStatuses = ["active", "expired", "revoked", "error"];
18
+ const CredentialStatusValidator = type.enumerated(...credentialStatuses);
19
+ const walletBackendTypes = ["crypto", "fiat", "credits"];
20
+ const WalletBackendTypeValidator = type.enumerated(...walletBackendTypes);
21
+ const transactionDirections = ["inbound", "outbound"];
22
+ const TransactionDirectionValidator = type.enumerated(...transactionDirections);
23
+ const transactionStatuses = ["pending", "completed", "failed"];
24
+ const TransactionStatusValidator = type.enumerated(...transactionStatuses);
25
+ const gitTokenKinds = ["pat", "svc"];
26
+ export const GitTokenKindValidator = type.enumerated(...gitTokenKinds);
27
+ const turnPartTypes = [
28
+ "text",
29
+ "reasoning",
30
+ "tool",
31
+ "file",
32
+ "error",
33
+ "refusal",
34
+ "step-start",
35
+ "step-finish",
36
+ "snapshot",
37
+ "patch",
38
+ ];
39
+ const TurnPartTypeValidator = type.enumerated(...turnPartTypes);
40
+ export function parseAgentRow(row) {
41
+ return {
42
+ ...row,
43
+ contextConfig: row.contextConfig !== null ? JSONObject.assert(row.contextConfig) : null,
44
+ initialState: row.initialState !== null ? JSONObject.assert(row.initialState) : null,
45
+ modelConfig: row.modelConfig !== null ? JSONObject.assert(row.modelConfig) : null,
46
+ capabilities: row.capabilities !== null ? JSONObject.assert(row.capabilities) : null,
47
+ credentialRequirements: row.credentialRequirements !== null
48
+ ? CredentialRequirement.array().assert(row.credentialRequirements)
49
+ : null,
50
+ modelRequirements: row.modelRequirements !== null
51
+ ? ModelRequirements.assert(row.modelRequirements)
52
+ : null,
53
+ grantRequirements: row.grantRequirements !== null
54
+ ? GrantRequirement.array().assert(row.grantRequirements)
55
+ : null,
56
+ toolPackages: ToolPackagePinArray.assert(row.toolPackages),
57
+ };
58
+ }
59
+ export function parseAgentVersionRow(row) {
60
+ return {
61
+ ...row,
62
+ status: AgentVersionStatusValidator.assert(row.status),
63
+ };
64
+ }
65
+ export function parseGrantRow(row) {
66
+ return {
67
+ ...row,
68
+ effect: GrantEffectValidator.assert(row.effect),
69
+ origin: GrantOriginValidator.assert(row.origin),
70
+ conditions: row.conditions !== null ? JSONObject.assert(row.conditions) : null,
71
+ };
72
+ }
73
+ export function parseOfferingRow(row) {
74
+ return {
75
+ ...row,
76
+ pricing: row.pricing !== null ? JSONObject.assert(row.pricing) : null,
77
+ schema: row.schema !== null ? JSONObject.assert(row.schema) : null,
78
+ };
79
+ }
80
+ export function parseCredentialRow(row) {
81
+ return {
82
+ ...row,
83
+ type: CredentialTypeValidator.assert(row.type),
84
+ status: CredentialStatusValidator.assert(row.status),
85
+ metadata: row.metadata !== null ? JSONObject.assert(row.metadata) : null,
86
+ };
87
+ }
88
+ export function parseProviderRow(row) {
89
+ return {
90
+ ...row,
91
+ metadata: row.metadata !== null ? JSONObject.assert(row.metadata) : null,
92
+ };
93
+ }
94
+ export function parseModelProviderRow(row) {
95
+ return {
96
+ ...row,
97
+ plugin: ModelProviderPlugin.assert(row.plugin),
98
+ };
99
+ }
100
+ export function parseModelOfferingRow(row) {
101
+ return {
102
+ ...row,
103
+ capabilities: Capability.array().assert(row.capabilities),
104
+ };
105
+ }
106
+ export function parseTenantRow(row) {
107
+ return {
108
+ ...row,
109
+ config: row.config !== null ? JSONObject.assert(row.config) : null,
110
+ };
111
+ }
112
+ export function parseWalletRow(row) {
113
+ return {
114
+ ...row,
115
+ backendType: WalletBackendTypeValidator.assert(row.backendType),
116
+ config: row.config !== null ? JSONObject.assert(row.config) : null,
117
+ };
118
+ }
119
+ export function parseTransactionRow(row) {
120
+ return {
121
+ ...row,
122
+ direction: TransactionDirectionValidator.assert(row.direction),
123
+ status: TransactionStatusValidator.assert(row.status),
124
+ };
125
+ }
126
+ export function parseOAuthClientRow(row) {
127
+ return {
128
+ ...row,
129
+ metadata: row.metadata !== null ? JSONObject.assert(row.metadata) : null,
130
+ };
131
+ }
132
+ export function parseGitTokenRow(row) {
133
+ return {
134
+ ...row,
135
+ kind: GitTokenKindValidator.assert(row.kind),
136
+ actions: RepoAction.array().assert(row.actions),
137
+ };
138
+ }
139
+ export function parseTurnPartType(partType) {
140
+ return TurnPartTypeValidator.assert(partType);
141
+ }
@@ -0,0 +1,3 @@
1
+ export declare const PG_UNIQUE_VIOLATION = "23505";
2
+ export declare const PG_FOREIGN_KEY_VIOLATION = "23503";
3
+ export declare function pgErrorCode(err: unknown): string | undefined;
@@ -0,0 +1,19 @@
1
+ import { hasCode } from "@intx/types";
2
+ // Postgres SQLSTATE codes. https://www.postgresql.org/docs/current/errcodes-appendix.html
3
+ export const PG_UNIQUE_VIOLATION = "23505";
4
+ export const PG_FOREIGN_KEY_VIOLATION = "23503";
5
+ // Extract a Postgres SQLSTATE from an error that a driver or ORM may have
6
+ // wrapped. postgres-js sets the code on the error it throws; Drizzle
7
+ // re-wraps that as the `cause` of a DrizzleQueryError, so the code can sit
8
+ // one or more levels down the cause chain. Walk the chain (depth-bounded so
9
+ // a self-referential cause cannot loop) and return the first code found.
10
+ export function pgErrorCode(err) {
11
+ let cur = err;
12
+ for (let depth = 0; cur != null && depth < 8; depth++) {
13
+ if (hasCode(cur)) {
14
+ return cur.code;
15
+ }
16
+ cur = cur.cause;
17
+ }
18
+ return undefined;
19
+ }
@@ -0,0 +1,15 @@
1
+ import type { modelPricing } from "./schema/catalog.js";
2
+ export type ModelPricingRow = typeof modelPricing.$inferSelect;
3
+ /**
4
+ * Selects the active pricing row per currency from an offering's append-only
5
+ * price history. For each currency, the active row is the one with the
6
+ * greatest `effectiveFrom` that is at or before `asOf`; rows dated after
7
+ * `asOf` are not yet in effect. The `(offeringId, currency, effectiveFrom)`
8
+ * uniqueness on the table guarantees no ties, so the selection is
9
+ * unambiguous.
10
+ *
11
+ * Pure: `asOf` is a parameter, never read from the clock, so the same
12
+ * function serves discovery (asOf = now) and historical cost attribution
13
+ * (asOf = the call's billing timestamp).
14
+ */
15
+ export declare function resolveActivePrice(rows: ModelPricingRow[], asOf: Date): ModelPricingRow[];
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Selects the active pricing row per currency from an offering's append-only
3
+ * price history. For each currency, the active row is the one with the
4
+ * greatest `effectiveFrom` that is at or before `asOf`; rows dated after
5
+ * `asOf` are not yet in effect. The `(offeringId, currency, effectiveFrom)`
6
+ * uniqueness on the table guarantees no ties, so the selection is
7
+ * unambiguous.
8
+ *
9
+ * Pure: `asOf` is a parameter, never read from the clock, so the same
10
+ * function serves discovery (asOf = now) and historical cost attribution
11
+ * (asOf = the call's billing timestamp).
12
+ */
13
+ export function resolveActivePrice(rows, asOf) {
14
+ const byCurrency = new Map();
15
+ for (const row of rows) {
16
+ if (row.effectiveFrom > asOf)
17
+ continue;
18
+ const current = byCurrency.get(row.currency);
19
+ if (current === undefined || row.effectiveFrom > current.effectiveFrom) {
20
+ byCurrency.set(row.currency, row);
21
+ }
22
+ }
23
+ return Array.from(byCurrency.values());
24
+ }
@@ -0,0 +1,109 @@
1
+ export declare const agentAsset: import("drizzle-orm/pg-core").PgTableWithColumns<{
2
+ name: "agent_asset";
3
+ schema: undefined;
4
+ columns: {
5
+ id: import("drizzle-orm/pg-core").PgColumn<{
6
+ name: "id";
7
+ tableName: "agent_asset";
8
+ dataType: "string";
9
+ columnType: "PgText";
10
+ data: string;
11
+ driverParam: string;
12
+ notNull: true;
13
+ hasDefault: false;
14
+ isPrimaryKey: true;
15
+ isAutoincrement: false;
16
+ hasRuntimeDefault: false;
17
+ enumValues: [string, ...string[]];
18
+ baseColumn: never;
19
+ identity: undefined;
20
+ generated: undefined;
21
+ }, {}, {}>;
22
+ agentId: import("drizzle-orm/pg-core").PgColumn<{
23
+ name: "agent_id";
24
+ tableName: "agent_asset";
25
+ dataType: "string";
26
+ columnType: "PgText";
27
+ data: string;
28
+ driverParam: string;
29
+ notNull: true;
30
+ hasDefault: false;
31
+ isPrimaryKey: false;
32
+ isAutoincrement: false;
33
+ hasRuntimeDefault: false;
34
+ enumValues: [string, ...string[]];
35
+ baseColumn: never;
36
+ identity: undefined;
37
+ generated: undefined;
38
+ }, {}, {}>;
39
+ assetId: import("drizzle-orm/pg-core").PgColumn<{
40
+ name: "asset_id";
41
+ tableName: "agent_asset";
42
+ dataType: "string";
43
+ columnType: "PgText";
44
+ data: string;
45
+ driverParam: string;
46
+ notNull: true;
47
+ hasDefault: false;
48
+ isPrimaryKey: false;
49
+ isAutoincrement: false;
50
+ hasRuntimeDefault: false;
51
+ enumValues: [string, ...string[]];
52
+ baseColumn: never;
53
+ identity: undefined;
54
+ generated: undefined;
55
+ }, {}, {}>;
56
+ ref: import("drizzle-orm/pg-core").PgColumn<{
57
+ name: "ref";
58
+ tableName: "agent_asset";
59
+ dataType: "string";
60
+ columnType: "PgText";
61
+ data: string;
62
+ driverParam: string;
63
+ notNull: true;
64
+ hasDefault: false;
65
+ isPrimaryKey: false;
66
+ isAutoincrement: false;
67
+ hasRuntimeDefault: false;
68
+ enumValues: [string, ...string[]];
69
+ baseColumn: never;
70
+ identity: undefined;
71
+ generated: undefined;
72
+ }, {}, {}>;
73
+ accessMode: import("drizzle-orm/pg-core").PgColumn<{
74
+ name: "access_mode";
75
+ tableName: "agent_asset";
76
+ dataType: "string";
77
+ columnType: "PgText";
78
+ data: string;
79
+ driverParam: string;
80
+ notNull: true;
81
+ hasDefault: true;
82
+ isPrimaryKey: false;
83
+ isAutoincrement: false;
84
+ hasRuntimeDefault: false;
85
+ enumValues: [string, ...string[]];
86
+ baseColumn: never;
87
+ identity: undefined;
88
+ generated: undefined;
89
+ }, {}, {}>;
90
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
91
+ name: "created_at";
92
+ tableName: "agent_asset";
93
+ dataType: "date";
94
+ columnType: "PgTimestamp";
95
+ data: Date;
96
+ driverParam: string;
97
+ notNull: true;
98
+ hasDefault: true;
99
+ isPrimaryKey: false;
100
+ isAutoincrement: false;
101
+ hasRuntimeDefault: false;
102
+ enumValues: undefined;
103
+ baseColumn: never;
104
+ identity: undefined;
105
+ generated: undefined;
106
+ }, {}, {}>;
107
+ };
108
+ dialect: "pg";
109
+ }>;
@@ -0,0 +1,15 @@
1
+ import { pgTable, text, timestamp, unique } from "drizzle-orm/pg-core";
2
+ import { agent } from "./agents.js";
3
+ import { asset } from "./assets.js";
4
+ export const agentAsset = pgTable("agent_asset", {
5
+ id: text("id").primaryKey(),
6
+ agentId: text("agent_id")
7
+ .notNull()
8
+ .references(() => agent.id, { onDelete: "cascade" }),
9
+ assetId: text("asset_id")
10
+ .notNull()
11
+ .references(() => asset.id, { onDelete: "cascade" }),
12
+ ref: text("ref").notNull(),
13
+ accessMode: text("access_mode").notNull().default("read-only"),
14
+ createdAt: timestamp("created_at").notNull().defaultNow(),
15
+ }, (t) => [unique("agent_asset_agent_asset").on(t.agentId, t.assetId)]);