@sixb/pg 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/agents/rows.d.ts +3 -1
- package/dist/agents/rows.d.ts.map +1 -1
- package/dist/agents/threads.d.ts +3 -2
- package/dist/agents/threads.d.ts.map +1 -1
- package/dist/auth-storage/access-tokens.d.ts.map +1 -1
- package/dist/auth-storage/device-authorizations.d.ts.map +1 -1
- package/dist/auth-storage/rows.d.ts +6 -3
- package/dist/auth-storage/rows.d.ts.map +1 -1
- package/dist/auth-storage/sessions.d.ts +8 -1
- package/dist/auth-storage/sessions.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +917 -122
- package/dist/index.js.map +26 -23
- package/dist/migrations.d.ts.map +1 -1
- package/dist/objects/query-compiler.d.ts +8 -1
- package/dist/objects/query-compiler.d.ts.map +1 -1
- package/dist/objects/read-scope.d.ts +1 -0
- package/dist/objects/read-scope.d.ts.map +1 -1
- package/dist/objects/reader.d.ts +1 -0
- package/dist/objects/reader.d.ts.map +1 -1
- package/dist/objects/rows.d.ts +1 -0
- package/dist/objects/rows.d.ts.map +1 -1
- package/dist/objects/storage.d.ts +1 -1
- package/dist/objects/storage.d.ts.map +1 -1
- package/dist/ontology-storage/index.d.ts +4 -0
- package/dist/ontology-storage/index.d.ts.map +1 -1
- package/dist/ontology-storage/materializations.d.ts +1 -2
- package/dist/ontology-storage/materializations.d.ts.map +1 -1
- package/dist/ontology-storage/shared.d.ts +2 -1
- package/dist/ontology-storage/shared.d.ts.map +1 -1
- package/dist/ontology-storage/vector-indexing.d.ts +20 -0
- package/dist/ontology-storage/vector-indexing.d.ts.map +1 -0
- package/dist/ontology-storage/vectors.d.ts +16 -0
- package/dist/ontology-storage/vectors.d.ts.map +1 -0
- package/dist/pg-ai-cost-storage.d.ts.map +1 -1
- package/dist/pg-file-upload-session-storage.d.ts +6 -0
- package/dist/pg-file-upload-session-storage.d.ts.map +1 -0
- package/dist/pg-workflow-intervention-storage.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/agents/rows.ts +21 -0
- package/src/agents/threads.ts +47 -2
- package/src/auth-storage/access-tokens.ts +10 -14
- package/src/auth-storage/auth-storage.ts +4 -6
- package/src/auth-storage/device-authorizations.ts +3 -4
- package/src/auth-storage/rows.ts +17 -7
- package/src/auth-storage/sessions.ts +82 -4
- package/src/auth-storage/shared.ts +8 -2
- package/src/index.ts +5 -0
- package/src/migrations/041-agent-thread-workspaces.sql +2 -0
- package/src/migrations/042-vector-profiles.sql +28 -0
- package/src/migrations/043-vector-indexing.sql +24 -0
- package/src/migrations/044-vector-batching.sql +3 -0
- package/src/migrations/045-agent-thread-sandbox-state.sql +2 -0
- package/src/migrations/046-workflow-intervention-principals.sql +15 -0
- package/src/migrations/047-ontology-commit-attribution.sql +50 -0
- package/src/migrations/048-file-upload-sessions.sql +34 -0
- package/src/migrations/049-native-sessions.sql +19 -0
- package/src/migrations.ts +26 -0
- package/src/objects/query-compiler.ts +102 -11
- package/src/objects/read-scope.ts +26 -25
- package/src/objects/reader.ts +33 -1
- package/src/objects/rows.ts +5 -1
- package/src/objects/storage.ts +22 -2
- package/src/ontology-storage/index.ts +15 -0
- package/src/ontology-storage/materializations.ts +28 -58
- package/src/ontology-storage/shared.ts +7 -3
- package/src/ontology-storage/vector-indexing.ts +168 -0
- package/src/ontology-storage/vectors.ts +172 -0
- package/src/pg-ai-cost-storage.ts +4 -0
- package/src/pg-file-upload-session-storage.ts +143 -0
- package/src/pg-workflow-intervention-storage.ts +11 -15
package/dist/index.js
CHANGED
|
@@ -125,6 +125,7 @@ function canStartPgTransaction(sql) {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
// src/agents/rows.ts
|
|
128
|
+
import { snapshotAgentThreadSandboxParams } from "@sixb/core/internal/agent-run-storage-provider";
|
|
128
129
|
import { parseSixbFailure } from "@sixb/core/internal/errors";
|
|
129
130
|
import {
|
|
130
131
|
AGENT_RUN_FAILURE_CODES,
|
|
@@ -136,6 +137,12 @@ function rowToThreadRecord(row) {
|
|
|
136
137
|
projectId: row.project_id,
|
|
137
138
|
ownerPrincipal: { type: row.owner_principal_type, id: row.owner_principal_id },
|
|
138
139
|
title: row.title ?? undefined,
|
|
140
|
+
...row.sandbox_state == null ? {} : {
|
|
141
|
+
sandboxState: typeof row.sandbox_state === "string" ? JSON.parse(row.sandbox_state) : row.sandbox_state
|
|
142
|
+
},
|
|
143
|
+
...row.sandbox_params == null ? {} : {
|
|
144
|
+
sandboxParams: snapshotAgentThreadSandboxParams(typeof row.sandbox_params === "string" ? JSON.parse(row.sandbox_params) : row.sandbox_params)
|
|
145
|
+
},
|
|
139
146
|
status: row.status,
|
|
140
147
|
activeRunId: row.active_run_id,
|
|
141
148
|
lastMessageAt: row.last_message_at ? new Date(row.last_message_at) : undefined,
|
|
@@ -974,6 +981,10 @@ class PgAgentRunStore {
|
|
|
974
981
|
}
|
|
975
982
|
|
|
976
983
|
// src/agents/threads.ts
|
|
984
|
+
import {
|
|
985
|
+
snapshotAgentThreadSandboxParams as snapshotAgentThreadSandboxParams2,
|
|
986
|
+
transitionAgentThreadSandbox
|
|
987
|
+
} from "@sixb/core/internal/agent-run-storage-provider";
|
|
977
988
|
import {
|
|
978
989
|
AgentStorageError as AgentStorageError4
|
|
979
990
|
} from "@sixb/core/storage";
|
|
@@ -982,7 +993,24 @@ class PgAgentThreadStore {
|
|
|
982
993
|
constructor(sql) {
|
|
983
994
|
this.sql = sql;
|
|
984
995
|
}
|
|
996
|
+
async transitionSandbox(input) {
|
|
997
|
+
return runPgTransaction(this.sql, async (tx) => {
|
|
998
|
+
const runs = input.action === "recreate" ? [] : await tx`
|
|
999
|
+
SELECT * FROM agent_runs WHERE project_id = ${input.projectId} AND id = ${input.runId}
|
|
1000
|
+
FOR UPDATE
|
|
1001
|
+
`;
|
|
1002
|
+
const [thread] = await tx`
|
|
1003
|
+
SELECT * FROM agent_threads WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
1004
|
+
FOR UPDATE
|
|
1005
|
+
`;
|
|
1006
|
+
const state = transitionAgentThreadSandbox(thread ? rowToThreadRecord(thread) : null, runs[0] ? rowToRunRecord(runs[0]) : null, input);
|
|
1007
|
+
await tx`UPDATE agent_threads SET sandbox_state = ${JSON.stringify(state)}::text::jsonb
|
|
1008
|
+
WHERE project_id = ${input.projectId} AND id = ${input.id}`;
|
|
1009
|
+
return state;
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
985
1012
|
async create(input) {
|
|
1013
|
+
const sandboxParams = input.sandboxParams === undefined ? null : JSON.stringify(snapshotAgentThreadSandboxParams2(input.sandboxParams));
|
|
986
1014
|
const createdAt = input.createdAt ?? new Date;
|
|
987
1015
|
const updatedAt = input.updatedAt ?? createdAt;
|
|
988
1016
|
try {
|
|
@@ -993,6 +1021,7 @@ class PgAgentThreadStore {
|
|
|
993
1021
|
owner_principal_type,
|
|
994
1022
|
owner_principal_id,
|
|
995
1023
|
title,
|
|
1024
|
+
sandbox_params,
|
|
996
1025
|
status,
|
|
997
1026
|
created_at,
|
|
998
1027
|
updated_at
|
|
@@ -1002,6 +1031,7 @@ class PgAgentThreadStore {
|
|
|
1002
1031
|
${input.ownerPrincipal.type},
|
|
1003
1032
|
${input.ownerPrincipal.id},
|
|
1004
1033
|
${input.title ?? null},
|
|
1034
|
+
${sandboxParams}::text::jsonb,
|
|
1005
1035
|
${input.status ?? "active"},
|
|
1006
1036
|
${createdAt},
|
|
1007
1037
|
${updatedAt}
|
|
@@ -1132,7 +1162,14 @@ function rowToSessionRecord(row) {
|
|
|
1132
1162
|
revokedAt: row.revoked_at ? toDate(row.revoked_at) : undefined,
|
|
1133
1163
|
lastSeenAt: row.last_seen_at ? toDate(row.last_seen_at) : undefined,
|
|
1134
1164
|
userAgent: row.user_agent ?? undefined,
|
|
1135
|
-
ipAddress: row.ip_address ?? undefined
|
|
1165
|
+
ipAddress: row.ip_address ?? undefined,
|
|
1166
|
+
bearer: row.refresh_token_hash !== null && row.client_name !== null && row.access_expires_at !== null ? {
|
|
1167
|
+
clientName: row.client_name,
|
|
1168
|
+
accessExpiresAt: toDate(row.access_expires_at),
|
|
1169
|
+
refreshTokenHash: row.refresh_token_hash,
|
|
1170
|
+
previousRefreshTokenHash: row.previous_refresh_token_hash ?? undefined,
|
|
1171
|
+
refreshedAt: row.refreshed_at ? toDate(row.refreshed_at) : undefined
|
|
1172
|
+
} : undefined
|
|
1136
1173
|
};
|
|
1137
1174
|
}
|
|
1138
1175
|
function rowToAccessTokenRecord(row) {
|
|
@@ -1141,8 +1178,7 @@ function rowToAccessTokenRecord(row) {
|
|
|
1141
1178
|
projectId: row.project_id,
|
|
1142
1179
|
name: row.name,
|
|
1143
1180
|
kind: row.kind,
|
|
1144
|
-
|
|
1145
|
-
subjectId: row.subject_id,
|
|
1181
|
+
subject: { type: row.subject_type, id: row.subject_id },
|
|
1146
1182
|
tokenHash: row.token_hash,
|
|
1147
1183
|
groupIds: parseOptionalStringArray(row.group_ids),
|
|
1148
1184
|
createdByPrincipal: principalFromColumns2(row),
|
|
@@ -1217,8 +1253,6 @@ function rowToDeviceAuthorizationRecord(row) {
|
|
|
1217
1253
|
deviceCodeHash: row.device_code_hash,
|
|
1218
1254
|
userCode: row.user_code,
|
|
1219
1255
|
clientName: row.client_name,
|
|
1220
|
-
tokenName: row.token_name,
|
|
1221
|
-
tokenExpiresAt: toDate(row.token_expires_at),
|
|
1222
1256
|
status: row.status,
|
|
1223
1257
|
approvedUserId: row.approved_user_id ?? undefined,
|
|
1224
1258
|
approvedSessionId: row.approved_session_id ?? undefined,
|
|
@@ -1529,7 +1563,10 @@ async function createSession(sql, input) {
|
|
|
1529
1563
|
expires_at,
|
|
1530
1564
|
absolute_expires_at,
|
|
1531
1565
|
user_agent,
|
|
1532
|
-
ip_address
|
|
1566
|
+
ip_address,
|
|
1567
|
+
client_name,
|
|
1568
|
+
access_expires_at,
|
|
1569
|
+
refresh_token_hash
|
|
1533
1570
|
) VALUES (
|
|
1534
1571
|
${projectId},
|
|
1535
1572
|
${id},
|
|
@@ -1541,7 +1578,10 @@ async function createSession(sql, input) {
|
|
|
1541
1578
|
${input.expiresAt},
|
|
1542
1579
|
${input.absoluteExpiresAt ?? null},
|
|
1543
1580
|
${input.userAgent ?? null},
|
|
1544
|
-
${input.ipAddress ?? null}
|
|
1581
|
+
${input.ipAddress ?? null},
|
|
1582
|
+
${input.bearer ? assertNonEmpty(input.bearer.clientName, "Session client name") : null},
|
|
1583
|
+
${input.bearer?.accessExpiresAt ?? null},
|
|
1584
|
+
${input.bearer ? assertNonEmpty(input.bearer.refreshTokenHash, "Refresh token hash") : null}
|
|
1545
1585
|
)
|
|
1546
1586
|
RETURNING *
|
|
1547
1587
|
`;
|
|
@@ -1733,10 +1773,10 @@ class PgAuthAccessTokenStore {
|
|
|
1733
1773
|
const id = assertNonEmpty(input.id, "Access token id");
|
|
1734
1774
|
const projectId = assertNonEmpty(input.projectId, "Project id");
|
|
1735
1775
|
const name = assertNonEmpty(input.name, "Access token name");
|
|
1736
|
-
const subjectId = assertNonEmpty(input.
|
|
1776
|
+
const subjectId = assertNonEmpty(input.subject.id, "Access token subject id");
|
|
1737
1777
|
const tokenHash = assertNonEmpty(input.tokenHash, "Access token hash");
|
|
1738
1778
|
assertKindMatchesSubject(input);
|
|
1739
|
-
await this.assertSubjectExists(projectId, input.
|
|
1779
|
+
await this.assertSubjectExists(projectId, input.subject.type, subjectId);
|
|
1740
1780
|
const groupIds = input.groupIds === undefined ? undefined : normalizeGroupIds(input.groupIds);
|
|
1741
1781
|
try {
|
|
1742
1782
|
const [row] = await this.sql`
|
|
@@ -1760,7 +1800,7 @@ class PgAuthAccessTokenStore {
|
|
|
1760
1800
|
${id},
|
|
1761
1801
|
${name},
|
|
1762
1802
|
${input.kind},
|
|
1763
|
-
${input.
|
|
1803
|
+
${input.subject.type},
|
|
1764
1804
|
${subjectId},
|
|
1765
1805
|
${tokenHash},
|
|
1766
1806
|
${serializeOptionalStringArray(groupIds)},
|
|
@@ -1795,13 +1835,9 @@ class PgAuthAccessTokenStore {
|
|
|
1795
1835
|
whereClauses.push(`kind = $${nextIndex++}`);
|
|
1796
1836
|
params.push(input.kind);
|
|
1797
1837
|
}
|
|
1798
|
-
if (input.
|
|
1799
|
-
whereClauses.push(`subject_type = $${nextIndex++}`);
|
|
1800
|
-
params.push(input.
|
|
1801
|
-
}
|
|
1802
|
-
if (input.subjectId) {
|
|
1803
|
-
whereClauses.push(`subject_id = $${nextIndex++}`);
|
|
1804
|
-
params.push(input.subjectId);
|
|
1838
|
+
if (input.subject) {
|
|
1839
|
+
whereClauses.push(`subject_type = $${nextIndex++}`, `subject_id = $${nextIndex++}`);
|
|
1840
|
+
params.push(input.subject.type, input.subject.id);
|
|
1805
1841
|
}
|
|
1806
1842
|
if (!input.includeRevoked) {
|
|
1807
1843
|
whereClauses.push("revoked_at IS NULL");
|
|
@@ -1889,10 +1925,10 @@ class PgAuthAccessTokenStore {
|
|
|
1889
1925
|
}
|
|
1890
1926
|
}
|
|
1891
1927
|
function assertKindMatchesSubject(input) {
|
|
1892
|
-
if (input.kind === "personal" && input.
|
|
1928
|
+
if (input.kind === "personal" && input.subject.type === "user" || input.kind === "serviceAccount" && input.subject.type === "serviceAccount") {
|
|
1893
1929
|
return;
|
|
1894
1930
|
}
|
|
1895
|
-
throw new AuthStorageError2("invalid_input", `[Sixb] Access token kind '${input.kind}' cannot target subject type '${input.
|
|
1931
|
+
throw new AuthStorageError2("invalid_input", `[Sixb] Access token kind '${input.kind}' cannot target subject type '${input.subject.type}'.`);
|
|
1896
1932
|
}
|
|
1897
1933
|
|
|
1898
1934
|
// src/auth-storage/device-authorizations.ts
|
|
@@ -1919,16 +1955,15 @@ class PgAuthDeviceAuthorizationStore {
|
|
|
1919
1955
|
try {
|
|
1920
1956
|
const [row] = await tx`
|
|
1921
1957
|
INSERT INTO auth_device_authorizations (
|
|
1922
|
-
project_id, id, device_code_hash, user_code, client_name,
|
|
1923
|
-
|
|
1958
|
+
project_id, id, device_code_hash, user_code, client_name, status, created_at,
|
|
1959
|
+
expires_at
|
|
1924
1960
|
) VALUES (
|
|
1925
1961
|
${assertNonEmpty(input.projectId, "Project id")},
|
|
1926
1962
|
${assertNonEmpty(input.id, "Device authorization id")},
|
|
1927
1963
|
${assertNonEmpty(input.deviceCodeHash, "Device code hash")},
|
|
1928
1964
|
${assertNonEmpty(input.userCode, "User code")},
|
|
1929
1965
|
${assertNonEmpty(input.clientName, "Client name")},
|
|
1930
|
-
${
|
|
1931
|
-
${input.tokenExpiresAt}, 'pending', ${input.createdAt}, ${input.expiresAt}
|
|
1966
|
+
'pending', ${input.createdAt}, ${input.expiresAt}
|
|
1932
1967
|
) RETURNING *
|
|
1933
1968
|
`;
|
|
1934
1969
|
return rowToDeviceAuthorizationRecord(row);
|
|
@@ -2670,11 +2705,53 @@ class PgAuthSessionStore {
|
|
|
2670
2705
|
}
|
|
2671
2706
|
async findValidByTokenHash(params) {
|
|
2672
2707
|
const row = await getSessionRowById(this.sql, params);
|
|
2673
|
-
if (!row || row.
|
|
2708
|
+
if (!row || row.refresh_token_hash !== null || row.audience !== params.audience || row.token_hash !== params.tokenHash || !isLiveSessionRow(row, params.now)) {
|
|
2709
|
+
return null;
|
|
2710
|
+
}
|
|
2711
|
+
return rowToSessionRecord(row);
|
|
2712
|
+
}
|
|
2713
|
+
async findValidByAccessTokenHash(params) {
|
|
2714
|
+
const row = await getSessionRowById(this.sql, params);
|
|
2715
|
+
if (!row || row.access_expires_at === null || row.token_hash !== params.tokenHash || new Date(row.access_expires_at) <= params.now || !isLiveSessionRow(row, params.now)) {
|
|
2674
2716
|
return null;
|
|
2675
2717
|
}
|
|
2676
2718
|
return rowToSessionRecord(row);
|
|
2677
2719
|
}
|
|
2720
|
+
async rotateRefreshToken(params) {
|
|
2721
|
+
return runPgTransaction(this.sql, async (tx) => {
|
|
2722
|
+
const row = await getSessionRowById(tx, params, { forUpdate: true });
|
|
2723
|
+
if (!row?.refresh_token_hash || !isLiveSessionRow(row, params.now)) {
|
|
2724
|
+
return { status: "invalid" };
|
|
2725
|
+
}
|
|
2726
|
+
const replacedRecently = row.previous_refresh_token_hash === params.refreshTokenHash && row.refreshed_at !== null && params.now.getTime() - new Date(row.refreshed_at).getTime() <= params.reuseGraceMs;
|
|
2727
|
+
if (row.refresh_token_hash !== params.refreshTokenHash && !replacedRecently) {
|
|
2728
|
+
if (row.previous_refresh_token_hash !== params.refreshTokenHash) {
|
|
2729
|
+
return { status: "invalid" };
|
|
2730
|
+
}
|
|
2731
|
+
await tx`
|
|
2732
|
+
UPDATE auth_sessions SET revoked_at = ${params.now}
|
|
2733
|
+
WHERE project_id = ${params.projectId} AND id = ${params.id}
|
|
2734
|
+
`;
|
|
2735
|
+
return { status: "reused" };
|
|
2736
|
+
}
|
|
2737
|
+
const [rotated] = await tx`
|
|
2738
|
+
UPDATE auth_sessions
|
|
2739
|
+
SET token_hash = ${params.next.tokenHash},
|
|
2740
|
+
access_expires_at = ${params.next.accessExpiresAt},
|
|
2741
|
+
previous_refresh_token_hash = refresh_token_hash,
|
|
2742
|
+
refresh_token_hash = ${params.next.refreshTokenHash},
|
|
2743
|
+
refreshed_at = ${params.now},
|
|
2744
|
+
last_seen_at = ${params.now},
|
|
2745
|
+
expires_at = GREATEST(
|
|
2746
|
+
expires_at,
|
|
2747
|
+
LEAST(${params.next.expiresAt}, COALESCE(absolute_expires_at, ${params.next.expiresAt}))
|
|
2748
|
+
)
|
|
2749
|
+
WHERE project_id = ${params.projectId} AND id = ${params.id}
|
|
2750
|
+
RETURNING *
|
|
2751
|
+
`;
|
|
2752
|
+
return rotated ? { status: "rotated", session: rowToSessionRecord(rotated) } : { status: "invalid" };
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2678
2755
|
async renewIfValid(params) {
|
|
2679
2756
|
const [row] = await this.sql`
|
|
2680
2757
|
UPDATE auth_sessions
|
|
@@ -2690,6 +2767,7 @@ class PgAuthSessionStore {
|
|
|
2690
2767
|
AND id = ${params.id}
|
|
2691
2768
|
AND audience = ${params.audience}
|
|
2692
2769
|
AND token_hash = ${params.tokenHash}
|
|
2770
|
+
AND refresh_token_hash IS NULL
|
|
2693
2771
|
AND revoked_at IS NULL
|
|
2694
2772
|
AND expires_at > ${params.now}
|
|
2695
2773
|
AND (absolute_expires_at IS NULL OR absolute_expires_at > ${params.now})
|
|
@@ -2737,6 +2815,9 @@ class PgAuthSessionStore {
|
|
|
2737
2815
|
});
|
|
2738
2816
|
}
|
|
2739
2817
|
}
|
|
2818
|
+
function isLiveSessionRow(row, now) {
|
|
2819
|
+
return row.revoked_at === null && new Date(row.expires_at) > now && (row.absolute_expires_at === null || new Date(row.absolute_expires_at) > now);
|
|
2820
|
+
}
|
|
2740
2821
|
|
|
2741
2822
|
// src/auth-storage/users.ts
|
|
2742
2823
|
import { AuthStorageError as AuthStorageError10 } from "@sixb/core/storage";
|
|
@@ -2898,7 +2979,7 @@ class PgAuthStorage {
|
|
|
2898
2979
|
throw new AuthStorageError11("missing_device_authorization", `[Sixb] Device authorization '${input.id}' not found for project '${input.projectId}'.`);
|
|
2899
2980
|
}
|
|
2900
2981
|
assertCompletableDeviceAuthorization(authorization, input);
|
|
2901
|
-
const
|
|
2982
|
+
const session = await createSession(tx, input.session);
|
|
2902
2983
|
const [consumed] = await tx`
|
|
2903
2984
|
UPDATE auth_device_authorizations
|
|
2904
2985
|
SET status = 'consumed', consumed_at = ${input.completedAt}
|
|
@@ -2914,7 +2995,7 @@ class PgAuthStorage {
|
|
|
2914
2995
|
status: "consumed",
|
|
2915
2996
|
consumedAt: new Date(input.completedAt)
|
|
2916
2997
|
},
|
|
2917
|
-
|
|
2998
|
+
session
|
|
2918
2999
|
};
|
|
2919
3000
|
});
|
|
2920
3001
|
}
|
|
@@ -3376,7 +3457,7 @@ function assertCompletableDeviceAuthorization(authorization, input) {
|
|
|
3376
3457
|
if (authorization.status === "denied") {
|
|
3377
3458
|
throw new AuthStorageError11("device_authorization_denied", "[Sixb] Device authorization was denied.");
|
|
3378
3459
|
}
|
|
3379
|
-
if (authorization.status !== "approved" || authorization.expiresAt <= input.completedAt || !authorization.approvedUserId || !authorization.approvedSessionId || input.
|
|
3460
|
+
if (authorization.status !== "approved" || authorization.expiresAt <= input.completedAt || !authorization.approvedUserId || !authorization.approvedSessionId || input.session.projectId !== input.projectId || input.session.userId !== authorization.approvedUserId) {
|
|
3380
3461
|
throw new AuthStorageError11("invalid_device_authorization", "[Sixb] Device authorization is invalid.");
|
|
3381
3462
|
}
|
|
3382
3463
|
}
|
|
@@ -7140,6 +7221,173 @@ ALTER TABLE projection_runs ADD COLUMN source_changes_read BIGINT
|
|
|
7140
7221
|
CHECK (source_changes_read IS NULL OR source_changes_read >= 0);
|
|
7141
7222
|
`;
|
|
7142
7223
|
|
|
7224
|
+
// src/migrations/041-agent-thread-workspaces.sql
|
|
7225
|
+
var _041_agent_thread_workspaces_default = `ALTER TABLE agent_threads ADD COLUMN sandbox_params JSONB
|
|
7226
|
+
CHECK (sandbox_params IS NULL OR jsonb_typeof(sandbox_params) = 'object');
|
|
7227
|
+
`;
|
|
7228
|
+
|
|
7229
|
+
// src/migrations/042-vector-profiles.sql
|
|
7230
|
+
var _042_vector_profiles_default = `-- Transactional derived state. Search extensions are not required for persistence.
|
|
7231
|
+
CREATE TABLE object_vectors (
|
|
7232
|
+
project_id TEXT NOT NULL,
|
|
7233
|
+
object_type_id TEXT NOT NULL,
|
|
7234
|
+
primary_id TEXT NOT NULL,
|
|
7235
|
+
profile TEXT NOT NULL CHECK (length(btrim(profile)) > 0),
|
|
7236
|
+
configuration TEXT NOT NULL,
|
|
7237
|
+
source TEXT[] NOT NULL,
|
|
7238
|
+
source_fingerprint TEXT NOT NULL,
|
|
7239
|
+
embedding REAL[] NOT NULL,
|
|
7240
|
+
last_commit_id TEXT NOT NULL,
|
|
7241
|
+
PRIMARY KEY (project_id, object_type_id, primary_id, profile),
|
|
7242
|
+
FOREIGN KEY (project_id, object_type_id, primary_id)
|
|
7243
|
+
REFERENCES objects (project_id, object_type_id, primary_id) ON DELETE CASCADE,
|
|
7244
|
+
FOREIGN KEY (project_id, last_commit_id)
|
|
7245
|
+
REFERENCES ontology_commits (project_id, id) DEFERRABLE INITIALLY DEFERRED,
|
|
7246
|
+
CONSTRAINT object_vectors_sources CHECK (
|
|
7247
|
+
cardinality(source) > 0 AND array_ndims(source) = 1 AND array_lower(source, 1) = 1
|
|
7248
|
+
AND array_position(source, NULL) IS NULL
|
|
7249
|
+
),
|
|
7250
|
+
CONSTRAINT object_vectors_values CHECK (
|
|
7251
|
+
cardinality(embedding) BETWEEN 1 AND 16000
|
|
7252
|
+
AND array_ndims(embedding) = 1 AND array_lower(embedding, 1) = 1
|
|
7253
|
+
AND array_position(embedding, NULL) IS NULL
|
|
7254
|
+
AND '-Infinity'::real < ALL(embedding) AND 'Infinity'::real > ALL(embedding)
|
|
7255
|
+
AND 0::real <> ANY(embedding)
|
|
7256
|
+
)
|
|
7257
|
+
);
|
|
7258
|
+
`;
|
|
7259
|
+
|
|
7260
|
+
// src/migrations/043-vector-indexing.sql
|
|
7261
|
+
var _043_vector_indexing_default = `CREATE TABLE object_vector_indexing (
|
|
7262
|
+
project_id TEXT NOT NULL,
|
|
7263
|
+
id TEXT NOT NULL,
|
|
7264
|
+
object_type_id TEXT NOT NULL,
|
|
7265
|
+
primary_id TEXT NOT NULL,
|
|
7266
|
+
profile TEXT NOT NULL,
|
|
7267
|
+
request JSONB NOT NULL,
|
|
7268
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'ready', 'failed')),
|
|
7269
|
+
available_at TIMESTAMPTZ NOT NULL,
|
|
7270
|
+
dispatch_at TIMESTAMPTZ NOT NULL,
|
|
7271
|
+
values_json JSONB,
|
|
7272
|
+
error TEXT,
|
|
7273
|
+
PRIMARY KEY (project_id, id),
|
|
7274
|
+
UNIQUE (project_id, object_type_id, primary_id, profile)
|
|
7275
|
+
);
|
|
7276
|
+
CREATE INDEX object_vector_indexing_due ON object_vector_indexing (project_id, dispatch_at, id)
|
|
7277
|
+
WHERE status <> 'failed';
|
|
7278
|
+
|
|
7279
|
+
ALTER TABLE executions DROP CONSTRAINT executions_authority_kernel_operation_check;
|
|
7280
|
+
ALTER TABLE executions ADD CONSTRAINT executions_authority_kernel_operation_check
|
|
7281
|
+
CHECK (authority_kernel_operation IS NULL OR authority_kernel_operation IN ('ontology.recover', 'ontology.indexVectors'));
|
|
7282
|
+
ALTER TABLE executions DROP CONSTRAINT executions_source_kind_check;
|
|
7283
|
+
ALTER TABLE executions ADD CONSTRAINT executions_source_kind_check
|
|
7284
|
+
CHECK (source_kind IN ('http', 'webhook', 'schedule', 'event', 'datasetVersion', 'execution', 'ontologyCommit'));
|
|
7285
|
+
`;
|
|
7286
|
+
|
|
7287
|
+
// src/migrations/044-vector-batching.sql
|
|
7288
|
+
var _044_vector_batching_default = `ALTER TABLE object_vector_indexing ADD COLUMN batch_id TEXT;
|
|
7289
|
+
CREATE INDEX object_vector_indexing_batch ON object_vector_indexing (project_id, batch_id, id)
|
|
7290
|
+
WHERE batch_id IS NOT NULL;
|
|
7291
|
+
`;
|
|
7292
|
+
|
|
7293
|
+
// src/migrations/045-agent-thread-sandbox-state.sql
|
|
7294
|
+
var _045_agent_thread_sandbox_state_default = `ALTER TABLE agent_threads ADD COLUMN sandbox_state JSONB
|
|
7295
|
+
CHECK (sandbox_state IS NULL OR jsonb_typeof(sandbox_state) = 'object');
|
|
7296
|
+
`;
|
|
7297
|
+
|
|
7298
|
+
// src/migrations/046-workflow-intervention-principals.sql
|
|
7299
|
+
var _046_workflow_intervention_principals_default = `-- Intervention actors were stored as { principalType, principalId }. Rewrite them to the
|
|
7300
|
+
-- canonical Principal shape { type, id } used by every other stored principal.
|
|
7301
|
+
UPDATE workflow_interventions
|
|
7302
|
+
SET submitted_by = jsonb_build_object(
|
|
7303
|
+
'type', submitted_by->>'principalType',
|
|
7304
|
+
'id', submitted_by->>'principalId'
|
|
7305
|
+
)
|
|
7306
|
+
WHERE submitted_by->>'principalType' IS NOT NULL;
|
|
7307
|
+
|
|
7308
|
+
UPDATE workflow_interventions
|
|
7309
|
+
SET cancelled_by = jsonb_build_object(
|
|
7310
|
+
'type', cancelled_by->>'principalType',
|
|
7311
|
+
'id', cancelled_by->>'principalId'
|
|
7312
|
+
)
|
|
7313
|
+
WHERE cancelled_by->>'principalType' IS NOT NULL;
|
|
7314
|
+
`;
|
|
7315
|
+
|
|
7316
|
+
// src/migrations/047-ontology-commit-attribution.sql
|
|
7317
|
+
var _047_ontology_commit_attribution_default = `-- Commits and their events name who requested the write and what ran it, replacing the
|
|
7318
|
+
-- authority-only \`actor\`. Both are copied from the commit's execution, which stays canonical and
|
|
7319
|
+
-- is immutable, so the backfill is exact.
|
|
7320
|
+
ALTER TABLE ontology_commits
|
|
7321
|
+
ADD COLUMN requested_by JSONB,
|
|
7322
|
+
ADD COLUMN executor JSONB;
|
|
7323
|
+
|
|
7324
|
+
UPDATE ontology_commits c SET
|
|
7325
|
+
requested_by = CASE
|
|
7326
|
+
WHEN e.requested_by_user_id IS NOT NULL
|
|
7327
|
+
THEN jsonb_build_object('type', 'user', 'id', e.requested_by_user_id)
|
|
7328
|
+
WHEN e.requested_by_service_account_id IS NOT NULL
|
|
7329
|
+
THEN jsonb_build_object('type', 'serviceAccount', 'id', e.requested_by_service_account_id)
|
|
7330
|
+
END,
|
|
7331
|
+
executor = CASE e.executor_kind
|
|
7332
|
+
WHEN 'request' THEN jsonb_build_object('type', 'request', 'requestId', e.executor_id)
|
|
7333
|
+
WHEN 'agent' THEN jsonb_build_object('type', 'agent', 'runId', e.executor_id)
|
|
7334
|
+
WHEN 'kernel' THEN jsonb_build_object(
|
|
7335
|
+
'type', 'kernel',
|
|
7336
|
+
'operation',
|
|
7337
|
+
CASE e.authority_kernel_operation
|
|
7338
|
+
WHEN 'ontology.recover'
|
|
7339
|
+
THEN jsonb_build_object('type', 'ontology.recover', 'recoveryId', e.executor_id)
|
|
7340
|
+
ELSE jsonb_build_object('type', 'ontology.indexVectors', 'indexingId', e.executor_id)
|
|
7341
|
+
END
|
|
7342
|
+
)
|
|
7343
|
+
ELSE jsonb_build_object(
|
|
7344
|
+
'type', 'primitive',
|
|
7345
|
+
'kind', e.executor_kind,
|
|
7346
|
+
'id', e.authority_primitive_id,
|
|
7347
|
+
'runId', e.executor_id
|
|
7348
|
+
)
|
|
7349
|
+
END
|
|
7350
|
+
FROM executions e
|
|
7351
|
+
WHERE e.project_id = c.project_id AND e.id = c.execution_id;
|
|
7352
|
+
|
|
7353
|
+
ALTER TABLE ontology_commits ALTER COLUMN executor SET NOT NULL;
|
|
7354
|
+
|
|
7355
|
+
-- Events not yet published would otherwise reach consumers in the retired shape.
|
|
7356
|
+
UPDATE ontology_outbox o SET envelope =
|
|
7357
|
+
(o.envelope - 'actor')
|
|
7358
|
+
|| jsonb_build_object('executor', c.executor)
|
|
7359
|
+
|| CASE
|
|
7360
|
+
WHEN c.requested_by IS NULL THEN '{}'::jsonb
|
|
7361
|
+
ELSE jsonb_build_object('requestedBy', c.requested_by)
|
|
7362
|
+
END
|
|
7363
|
+
FROM ontology_commits c
|
|
7364
|
+
WHERE c.project_id = o.project_id AND c.id = o.commit_id;
|
|
7365
|
+
|
|
7366
|
+
ALTER TABLE ontology_commits DROP COLUMN actor;
|
|
7367
|
+
`;
|
|
7368
|
+
|
|
7369
|
+
// src/migrations/049-native-sessions.sql
|
|
7370
|
+
var _049_native_sessions_default = `-- Native clients, such as the CLI, hold their session as bearer tokens: a
|
|
7371
|
+
-- short-lived access token, whose hash is \`token_hash\`, and a rotating refresh token. Browser
|
|
7372
|
+
-- sessions leave these columns NULL; \`refresh_token_hash IS NULL\` is what marks a cookie session.
|
|
7373
|
+
ALTER TABLE auth_sessions
|
|
7374
|
+
ADD COLUMN client_name TEXT,
|
|
7375
|
+
ADD COLUMN access_expires_at TIMESTAMPTZ,
|
|
7376
|
+
ADD COLUMN refresh_token_hash TEXT,
|
|
7377
|
+
ADD COLUMN previous_refresh_token_hash TEXT,
|
|
7378
|
+
ADD COLUMN refreshed_at TIMESTAMPTZ,
|
|
7379
|
+
ADD CONSTRAINT auth_sessions_bearer_state CHECK (
|
|
7380
|
+
(refresh_token_hash IS NULL) = (client_name IS NULL)
|
|
7381
|
+
AND (refresh_token_hash IS NULL) = (access_expires_at IS NULL)
|
|
7382
|
+
AND (refresh_token_hash IS NOT NULL OR previous_refresh_token_hash IS NULL)
|
|
7383
|
+
);
|
|
7384
|
+
|
|
7385
|
+
-- The device flow now starts a session instead of issuing a personal access token.
|
|
7386
|
+
ALTER TABLE auth_device_authorizations
|
|
7387
|
+
DROP COLUMN token_name,
|
|
7388
|
+
DROP COLUMN token_expires_at;
|
|
7389
|
+
`;
|
|
7390
|
+
|
|
7143
7391
|
// src/migrations/037-execution-requester-groups.sql
|
|
7144
7392
|
var _037_execution_requester_groups_default = `ALTER TABLE executions ADD COLUMN requester_group_ids JSONB NOT NULL DEFAULT '[]'::jsonb;
|
|
7145
7393
|
|
|
@@ -7178,6 +7426,43 @@ ALTER TABLE connector_authorization_attempts
|
|
|
7178
7426
|
ALTER COLUMN code_verifier DROP NOT NULL;
|
|
7179
7427
|
`;
|
|
7180
7428
|
|
|
7429
|
+
// src/migrations/048-file-upload-sessions.sql
|
|
7430
|
+
var _048_file_upload_sessions_default = `-- Durable staged-upload sessions, so an upload survives restarts and spans API replicas.
|
|
7431
|
+
CREATE TABLE file_upload_sessions (
|
|
7432
|
+
id TEXT PRIMARY KEY CHECK (length(trim(id)) > 0),
|
|
7433
|
+
project_id TEXT NOT NULL CHECK (length(trim(project_id)) > 0),
|
|
7434
|
+
owner_principal_type TEXT NOT NULL
|
|
7435
|
+
CHECK (owner_principal_type IN ('user', 'serviceAccount', 'system')),
|
|
7436
|
+
owner_principal_id TEXT NOT NULL CHECK (length(owner_principal_id) > 0),
|
|
7437
|
+
strategy TEXT NOT NULL CHECK (strategy IN ('server', 'direct-put', 'multipart')),
|
|
7438
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'aborted')),
|
|
7439
|
+
file_name TEXT,
|
|
7440
|
+
media_type TEXT,
|
|
7441
|
+
logical_path TEXT,
|
|
7442
|
+
expected_size_bytes BIGINT CHECK (expected_size_bytes IS NULL OR expected_size_bytes >= 0),
|
|
7443
|
+
expected_digest TEXT,
|
|
7444
|
+
provider_upload JSONB CHECK (provider_upload IS NULL OR jsonb_typeof(provider_upload) = 'object'),
|
|
7445
|
+
signed_parts JSONB NOT NULL CHECK (jsonb_typeof(signed_parts) = 'array'),
|
|
7446
|
+
file_ref JSONB CHECK (file_ref IS NULL OR jsonb_typeof(file_ref) = 'object'),
|
|
7447
|
+
created_at TIMESTAMPTZ NOT NULL,
|
|
7448
|
+
expires_at TIMESTAMPTZ NOT NULL,
|
|
7449
|
+
completed_at TIMESTAMPTZ,
|
|
7450
|
+
aborted_at TIMESTAMPTZ,
|
|
7451
|
+
-- Derived by core (fileUploadSessionReapAt); NULL while an abandoned upload awaits its abort.
|
|
7452
|
+
reap_at TIMESTAMPTZ,
|
|
7453
|
+
CHECK ((status = 'completed') = (completed_at IS NOT NULL)),
|
|
7454
|
+
CHECK ((status = 'aborted') = (aborted_at IS NOT NULL))
|
|
7455
|
+
);
|
|
7456
|
+
|
|
7457
|
+
CREATE INDEX idx_file_upload_sessions_reap
|
|
7458
|
+
ON file_upload_sessions (reap_at)
|
|
7459
|
+
WHERE reap_at IS NOT NULL;
|
|
7460
|
+
|
|
7461
|
+
CREATE INDEX idx_file_upload_sessions_abandoned
|
|
7462
|
+
ON file_upload_sessions (project_id, expires_at)
|
|
7463
|
+
WHERE status = 'pending' AND provider_upload IS NOT NULL;
|
|
7464
|
+
`;
|
|
7465
|
+
|
|
7181
7466
|
// src/migrations.ts
|
|
7182
7467
|
var POSTGRES_STORAGE_ADAPTER_ID = "SixbPostgresStorage";
|
|
7183
7468
|
function pgSql(id, sqlText) {
|
|
@@ -7392,17 +7677,38 @@ var postgresStorageMigrations = defineMigrations({
|
|
|
7392
7677
|
pgSql("037-execution-requester-groups", _037_execution_requester_groups_default),
|
|
7393
7678
|
pgSql("038-outbox-publication-order", _038_outbox_publication_order_default),
|
|
7394
7679
|
pgSql("039-projection-source-roots", _039_projection_source_roots_default),
|
|
7395
|
-
pgSql("040-connector-optional-pkce", _040_connector_optional_pkce_default)
|
|
7680
|
+
pgSql("040-connector-optional-pkce", _040_connector_optional_pkce_default),
|
|
7681
|
+
pgSql("041-agent-thread-workspaces", _041_agent_thread_workspaces_default),
|
|
7682
|
+
pgSql("042-vector-profiles", _042_vector_profiles_default),
|
|
7683
|
+
pgSql("043-vector-indexing", _043_vector_indexing_default),
|
|
7684
|
+
pgSql("044-vector-batching", _044_vector_batching_default),
|
|
7685
|
+
pgSql("045-agent-thread-sandbox-state", _045_agent_thread_sandbox_state_default),
|
|
7686
|
+
pgSql("046-workflow-intervention-principals", _046_workflow_intervention_principals_default),
|
|
7687
|
+
pgSql("047-ontology-commit-attribution", _047_ontology_commit_attribution_default),
|
|
7688
|
+
pgSql("048-file-upload-sessions", _048_file_upload_sessions_default),
|
|
7689
|
+
pgSql("049-native-sessions", _049_native_sessions_default)
|
|
7396
7690
|
]
|
|
7397
7691
|
});
|
|
7398
7692
|
|
|
7693
|
+
// src/objects/storage.ts
|
|
7694
|
+
import { hasVectorProfile as hasVectorProfile3 } from "@sixb/core/internal/query";
|
|
7695
|
+
|
|
7399
7696
|
// src/objects/query-compiler.ts
|
|
7400
7697
|
import {
|
|
7401
7698
|
ObjectQueryExecutionError
|
|
7402
7699
|
} from "@sixb/core";
|
|
7700
|
+
import {
|
|
7701
|
+
hasVectorProfile,
|
|
7702
|
+
isVectorProfileQuery,
|
|
7703
|
+
normalizeVector,
|
|
7704
|
+
vectorSearchCandidateLimit
|
|
7705
|
+
} from "@sixb/core/internal/query";
|
|
7403
7706
|
var PAGE_TOKEN_PREFIX = "keyset:";
|
|
7404
7707
|
var DEFAULT_EXPANSION_FANOUT = 1000;
|
|
7405
7708
|
function compilePgObjectQuery(projectId, query, options = {}) {
|
|
7709
|
+
if (hasVectorProfile(query) && !isVectorProfileQuery(query)) {
|
|
7710
|
+
throw new ObjectQueryExecutionError("unsupported_vector_composition", "Vector search supports one profile with filters before ranking and limit/project after.");
|
|
7711
|
+
}
|
|
7406
7712
|
const source = options.source ?? DEFAULT_OBJECT_QUERY_SOURCE;
|
|
7407
7713
|
const compiled = source.wrapQuery(compileObjectQueryInternal(projectId, query, {
|
|
7408
7714
|
probeLimit: options.includeTotal === false,
|
|
@@ -7412,6 +7718,7 @@ function compilePgObjectQuery(projectId, query, options = {}) {
|
|
|
7412
7718
|
...compiled,
|
|
7413
7719
|
sql: numberPlaceholders(compiled.sql),
|
|
7414
7720
|
totalSql: numberPlaceholders(compiled.totalSql),
|
|
7721
|
+
vectorProbe: compiled.vectorProbe ? { ...compiled.vectorProbe, sql: numberPlaceholders(compiled.vectorProbe.sql) } : undefined,
|
|
7415
7722
|
hasMoreProbe: compiled.hasMoreProbe ? {
|
|
7416
7723
|
...compiled.hasMoreProbe,
|
|
7417
7724
|
sql: numberPlaceholders(compiled.hasMoreProbe.sql)
|
|
@@ -7489,8 +7796,56 @@ function compileObjectQueryInternal(projectId, query, ctx) {
|
|
|
7489
7796
|
case "expand":
|
|
7490
7797
|
return compileExpand(projectId, query.input, query.expansions, ctx);
|
|
7491
7798
|
case "vector":
|
|
7492
|
-
|
|
7493
|
-
}
|
|
7799
|
+
return compileVector(projectId, query, ctx);
|
|
7800
|
+
}
|
|
7801
|
+
}
|
|
7802
|
+
function compileVector(projectId, query, ctx) {
|
|
7803
|
+
if (typeof query.vector === "string" || !isVectorProfileQuery(query) || !query.configuration || !Number.isSafeInteger(query.k) || query.k < 1 || query.k > 1000 || query.vector.length < 1 || query.vector.length > 16000) {
|
|
7804
|
+
throw new ObjectQueryExecutionError("invalid_vector_query", "A validated named vector profile is required.");
|
|
7805
|
+
}
|
|
7806
|
+
const input = compileObjectQueryInternal(projectId, query.input, exactContext(ctx));
|
|
7807
|
+
const permissions = ctx.source.objectPropertyPermissionsTable;
|
|
7808
|
+
const permissionJoin = permissions ? `JOIN (
|
|
7809
|
+
SELECT project_id, object_type_id, primary_id, array_agg(property_id) AS property_ids
|
|
7810
|
+
FROM ${permissions}
|
|
7811
|
+
GROUP BY project_id, object_type_id, primary_id
|
|
7812
|
+
) AS vector_permissions ON vector_permissions.project_id = vectors.project_id
|
|
7813
|
+
AND vector_permissions.object_type_id = vectors.object_type_id
|
|
7814
|
+
AND vector_permissions.primary_id = vectors.primary_id` : "";
|
|
7815
|
+
const authorized = permissions ? `AND vectors.source <@ vector_permissions.property_ids` : "";
|
|
7816
|
+
const candidates = `FROM (${input.sql}) AS input
|
|
7817
|
+
JOIN object_vectors AS vectors ON vectors.project_id = input.project_id
|
|
7818
|
+
AND vectors.object_type_id = input.object_type_id AND vectors.primary_id = input.primary_id
|
|
7819
|
+
${permissionJoin}
|
|
7820
|
+
WHERE vectors.profile = ? AND vectors.configuration = ?
|
|
7821
|
+
AND cardinality(vectors.embedding) = ? ${authorized}`;
|
|
7822
|
+
const candidateArgs = [...input.args, query.profile, query.configuration, query.vector.length];
|
|
7823
|
+
const limit = vectorSearchCandidateLimit(query.vector.length);
|
|
7824
|
+
const values = normalizeVector(query.vector, query.vector.length);
|
|
7825
|
+
const order = compileOrder([
|
|
7826
|
+
{ kind: "column", column: "_vector_score", direction: "desc" },
|
|
7827
|
+
...identityOrderFields().map((field) => ({ ...field, binary: true }))
|
|
7828
|
+
]);
|
|
7829
|
+
const sql = `SELECT * FROM (SELECT input.*, 1 - (vectors.embedding::public.vector OPERATOR(public.<=>) ?::public.vector) AS _vector_score
|
|
7830
|
+
${candidates}) AS ranked ORDER BY ${order.sql} LIMIT ?`;
|
|
7831
|
+
const args = [JSON.stringify(values), ...candidateArgs, query.k];
|
|
7832
|
+
return {
|
|
7833
|
+
sql,
|
|
7834
|
+
args,
|
|
7835
|
+
totalSql: `SELECT COUNT(*)::bigint AS total FROM (SELECT 1 ${candidates} LIMIT ?) AS eligible`,
|
|
7836
|
+
totalArgs: [...candidateArgs, query.k],
|
|
7837
|
+
order,
|
|
7838
|
+
vectorProbe: {
|
|
7839
|
+
sql: `SELECT COUNT(*)::bigint AS total FROM (SELECT 1 ${candidates} LIMIT ?) AS candidates`,
|
|
7840
|
+
args: [...candidateArgs, limit + 1],
|
|
7841
|
+
limit
|
|
7842
|
+
},
|
|
7843
|
+
hasMore: () => false,
|
|
7844
|
+
trimRows: identityRows,
|
|
7845
|
+
nextPageToken: () => {
|
|
7846
|
+
return;
|
|
7847
|
+
}
|
|
7848
|
+
};
|
|
7494
7849
|
}
|
|
7495
7850
|
function compileStart(projectId, query, ctx) {
|
|
7496
7851
|
if (query.includeSubtypes === true) {
|
|
@@ -7578,6 +7933,7 @@ function compileWhere(projectId, inputQuery, predicate, ctx) {
|
|
|
7578
7933
|
WHERE ${predicate.sql}
|
|
7579
7934
|
`,
|
|
7580
7935
|
totalArgs: [...input.args, ...predicate.args],
|
|
7936
|
+
vectorProbe: input.vectorProbe,
|
|
7581
7937
|
order: input.order,
|
|
7582
7938
|
hasMore: () => false,
|
|
7583
7939
|
trimRows: identityRows,
|
|
@@ -7604,7 +7960,7 @@ function compileSort(projectId, inputQuery, fields, ctx) {
|
|
|
7604
7960
|
input.created_at,
|
|
7605
7961
|
input.updated_at,
|
|
7606
7962
|
input.version,
|
|
7607
|
-
input.last_commit_id
|
|
7963
|
+
input.last_commit_id${input.vectorProbe ? ", input._vector_score" : ""}
|
|
7608
7964
|
FROM (${input.sql}) AS input
|
|
7609
7965
|
ORDER BY ${order.sql}
|
|
7610
7966
|
`,
|
|
@@ -7635,6 +7991,7 @@ function compileLimit(projectId, inputQuery, rawLimit, ctx) {
|
|
|
7635
7991
|
FROM (${input.sql}) AS input
|
|
7636
7992
|
`,
|
|
7637
7993
|
totalArgs: input.args,
|
|
7994
|
+
vectorProbe: input.vectorProbe,
|
|
7638
7995
|
order: input.order,
|
|
7639
7996
|
hasMore: (rowCount, total) => total === undefined ? ctx.probeLimit && rowCount > limit : limit < total,
|
|
7640
7997
|
trimRows: ctx.probeLimit ? (rows) => rows.slice(0, limit) : identityRows,
|
|
@@ -7663,6 +8020,7 @@ function compilePage(projectId, inputQuery, rawPageSize, pageToken, ctx) {
|
|
|
7663
8020
|
FROM (${input.sql}) AS input
|
|
7664
8021
|
`,
|
|
7665
8022
|
totalArgs: input.args,
|
|
8023
|
+
vectorProbe: input.vectorProbe,
|
|
7666
8024
|
order: input.order,
|
|
7667
8025
|
hasMore: (rowCount) => rowCount > pageSize,
|
|
7668
8026
|
trimRows: (rows) => rows.slice(0, pageSize),
|
|
@@ -7739,6 +8097,7 @@ function compileExpand(projectId, inputQuery, expansions, ctx) {
|
|
|
7739
8097
|
args: [...expand.args, ...input.args, ...inputOrder.args],
|
|
7740
8098
|
totalSql: input.totalSql,
|
|
7741
8099
|
totalArgs: input.totalArgs,
|
|
8100
|
+
vectorProbe: input.vectorProbe,
|
|
7742
8101
|
order: input.order,
|
|
7743
8102
|
hasMoreProbe: input.hasMoreProbe,
|
|
7744
8103
|
hasMore: input.hasMore,
|
|
@@ -7904,13 +8263,14 @@ function compileProject(projectId, inputQuery, properties, ctx) {
|
|
|
7904
8263
|
input.created_at,
|
|
7905
8264
|
input.updated_at,
|
|
7906
8265
|
input.version,
|
|
7907
|
-
input.last_commit_id
|
|
8266
|
+
input.last_commit_id${input.vectorProbe ? ", input._vector_score" : ""}
|
|
7908
8267
|
FROM (${input.sql}) AS input
|
|
7909
8268
|
ORDER BY ${inputOrder.sql}
|
|
7910
8269
|
`,
|
|
7911
8270
|
args: [...projection.args, ...input.args, ...inputOrder.args],
|
|
7912
8271
|
totalSql: input.totalSql,
|
|
7913
8272
|
totalArgs: input.totalArgs,
|
|
8273
|
+
vectorProbe: input.vectorProbe,
|
|
7914
8274
|
order: outputOrder,
|
|
7915
8275
|
hasMoreProbe: input.hasMoreProbe,
|
|
7916
8276
|
hasMore: input.hasMore,
|
|
@@ -7941,7 +8301,7 @@ function compileAggregateSource(projectId, query, source) {
|
|
|
7941
8301
|
case "page":
|
|
7942
8302
|
return compileRowQueryAggregateSource(projectId, query, source);
|
|
7943
8303
|
case "vector":
|
|
7944
|
-
|
|
8304
|
+
return compileRowQueryAggregateSource(projectId, query, source);
|
|
7945
8305
|
}
|
|
7946
8306
|
}
|
|
7947
8307
|
function compileAggregateStart(projectId, query, source) {
|
|
@@ -8310,7 +8670,7 @@ function compileOrder(fields, qualifier, propertyColumn = "properties") {
|
|
|
8310
8670
|
const args = [];
|
|
8311
8671
|
for (const field of fields) {
|
|
8312
8672
|
if (field.kind === "column") {
|
|
8313
|
-
clauses.push(`${columnExpression(field.column, qualifier)} ${field.direction.toUpperCase()}`);
|
|
8673
|
+
clauses.push(`${columnExpression(field.column, qualifier)}${field.binary ? ' COLLATE "C"' : ""} ${field.direction.toUpperCase()}`);
|
|
8314
8674
|
continue;
|
|
8315
8675
|
}
|
|
8316
8676
|
const direction = field.direction === "desc" ? "DESC" : "ASC";
|
|
@@ -8519,6 +8879,8 @@ function isPlainObject(value) {
|
|
|
8519
8879
|
}
|
|
8520
8880
|
|
|
8521
8881
|
// src/objects/reader.ts
|
|
8882
|
+
import { ObjectQueryExecutionError as ObjectQueryExecutionError2 } from "@sixb/core";
|
|
8883
|
+
import { hasVectorProfile as hasVectorProfile2 } from "@sixb/core/internal/query";
|
|
8522
8884
|
import { linkBatchKey, objectBatchKey } from "@sixb/core/storage";
|
|
8523
8885
|
|
|
8524
8886
|
// src/objects/rows.ts
|
|
@@ -8535,7 +8897,10 @@ function rowToObject(row) {
|
|
|
8535
8897
|
};
|
|
8536
8898
|
}
|
|
8537
8899
|
function queryRowToObject(row) {
|
|
8538
|
-
const base =
|
|
8900
|
+
const base = {
|
|
8901
|
+
...rowToObject(row),
|
|
8902
|
+
...row._vector_score === undefined ? {} : { score: row._vector_score }
|
|
8903
|
+
};
|
|
8539
8904
|
const links = reviveExpandedLinks(row._expand);
|
|
8540
8905
|
return links ? { ...base, links } : base;
|
|
8541
8906
|
}
|
|
@@ -8610,7 +8975,23 @@ class PgObjectReader {
|
|
|
8610
8975
|
this.sql = sql;
|
|
8611
8976
|
this.source = source;
|
|
8612
8977
|
}
|
|
8978
|
+
async assertVectorSearch(params) {
|
|
8979
|
+
if (!hasVectorProfile2(params.query))
|
|
8980
|
+
return;
|
|
8981
|
+
const compiled = compilePgObjectQuery(params.projectId, params.query, { source: this.source });
|
|
8982
|
+
if (!compiled.vectorProbe)
|
|
8983
|
+
return;
|
|
8984
|
+
const extensions = await this.sql.unsafe("SELECT EXISTS (SELECT 1 FROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace WHERE e.extname = 'vector' AND n.nspname = 'public') AS ready");
|
|
8985
|
+
if (!extensions[0]?.ready)
|
|
8986
|
+
throw new ObjectQueryExecutionError2("vector_extension_missing", "PostgreSQL vector search requires pgvector installed in schema public (CREATE EXTENSION vector WITH SCHEMA public).");
|
|
8987
|
+
const probe = compiled.vectorProbe;
|
|
8988
|
+
const [row] = await this.sql.unsafe(probe.sql, probe.args);
|
|
8989
|
+
if (Number(row?.total ?? 0) > probe.limit) {
|
|
8990
|
+
throw new ObjectQueryExecutionError2("vector_work_limit_exceeded", `Exact vector search supports at most ${probe.limit} eligible vectors at this dimension. Narrow the query filters.`);
|
|
8991
|
+
}
|
|
8992
|
+
}
|
|
8613
8993
|
async queryObjects(params) {
|
|
8994
|
+
await this.assertVectorSearch(params);
|
|
8614
8995
|
const sql = this.sql;
|
|
8615
8996
|
const source = this.source;
|
|
8616
8997
|
const compiled = compilePgObjectQuery(params.projectId, params.query, {
|
|
@@ -8629,6 +9010,7 @@ class PgObjectReader {
|
|
|
8629
9010
|
};
|
|
8630
9011
|
}
|
|
8631
9012
|
async countObjects(params) {
|
|
9013
|
+
await this.assertVectorSearch(params);
|
|
8632
9014
|
const sql = this.sql;
|
|
8633
9015
|
const source = this.source;
|
|
8634
9016
|
const compiled = compilePgObjectCountQuery(params.projectId, stripOuterRowShape(params.query), {
|
|
@@ -8638,6 +9020,7 @@ class PgObjectReader {
|
|
|
8638
9020
|
return { count: Number(row?.count ?? 0) };
|
|
8639
9021
|
}
|
|
8640
9022
|
async existsObjects(params) {
|
|
9023
|
+
await this.assertVectorSearch(params);
|
|
8641
9024
|
const sql = this.sql;
|
|
8642
9025
|
const source = this.source;
|
|
8643
9026
|
const compiled = compilePgObjectExistsQuery(params.projectId, stripOuterRowShape(params.query), { source });
|
|
@@ -8645,6 +9028,7 @@ class PgObjectReader {
|
|
|
8645
9028
|
return { exists: row !== undefined };
|
|
8646
9029
|
}
|
|
8647
9030
|
async facetObjects(params) {
|
|
9031
|
+
await this.assertVectorSearch(params);
|
|
8648
9032
|
const sql = this.sql;
|
|
8649
9033
|
const source = this.source;
|
|
8650
9034
|
const facets = [];
|
|
@@ -9032,6 +9416,7 @@ ${sql}`,
|
|
|
9032
9416
|
wrapQuery: (query) => ({
|
|
9033
9417
|
...query,
|
|
9034
9418
|
...wrapStatement(query.sql, query.args),
|
|
9419
|
+
vectorProbe: query.vectorProbe ? { ...query.vectorProbe, ...wrapStatement(query.vectorProbe.sql, query.vectorProbe.args) } : undefined,
|
|
9035
9420
|
totalSql: `${compiled.sql}
|
|
9036
9421
|
${query.totalSql}`,
|
|
9037
9422
|
totalArgs: [...compiled.args, ...query.totalArgs],
|
|
@@ -9153,32 +9538,29 @@ function compileSelectedReadScopeCte(scopeJson, projectId) {
|
|
|
9153
9538
|
SELECT DISTINCT project_id, object_type_id, primary_id
|
|
9154
9539
|
FROM _sixb_scope_reachable
|
|
9155
9540
|
),
|
|
9541
|
+
_sixb_scope_object_grants AS (
|
|
9542
|
+
SELECT reachable.project_id, reachable.object_type_id, reachable.primary_id,
|
|
9543
|
+
array_agg(DISTINCT selected_property.value) FILTER (WHERE selected_property.value IS NOT NULL) AS property_ids
|
|
9544
|
+
FROM _sixb_scope_reachable AS reachable
|
|
9545
|
+
LEFT JOIN _sixb_scope_object_selections AS selection
|
|
9546
|
+
ON selection.node_id = reachable.node_id
|
|
9547
|
+
AND selection.object_type_id = reachable.object_type_id
|
|
9548
|
+
LEFT JOIN LATERAL jsonb_array_elements_text(selection.property_ids) AS selected_property(value) ON true
|
|
9549
|
+
GROUP BY reachable.project_id, reachable.object_type_id, reachable.primary_id
|
|
9550
|
+
),
|
|
9156
9551
|
_sixb_scope_objects AS (
|
|
9157
|
-
SELECT
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
AND permission.property_id = property.key
|
|
9170
|
-
),
|
|
9171
|
-
'{}'::jsonb
|
|
9172
|
-
) AS properties,
|
|
9173
|
-
stored.created_at,
|
|
9174
|
-
stored.updated_at,
|
|
9175
|
-
stored.version,
|
|
9176
|
-
stored.last_commit_id
|
|
9177
|
-
FROM objects AS stored
|
|
9178
|
-
JOIN _sixb_scope_object_ids AS visible
|
|
9179
|
-
ON visible.project_id = stored.project_id
|
|
9180
|
-
AND visible.object_type_id = stored.object_type_id
|
|
9181
|
-
AND visible.primary_id = stored.primary_id
|
|
9552
|
+
SELECT stored.project_id, stored.object_type_id, stored.primary_id,
|
|
9553
|
+
COALESCE((
|
|
9554
|
+
SELECT jsonb_object_agg(property.key, property.value)
|
|
9555
|
+
FROM jsonb_each(stored.properties) AS property(key, value)
|
|
9556
|
+
WHERE property.key = ANY(grants.property_ids)
|
|
9557
|
+
), '{}'::jsonb) AS properties,
|
|
9558
|
+
stored.created_at, stored.updated_at, stored.version, stored.last_commit_id
|
|
9559
|
+
FROM _sixb_scope_object_grants AS grants
|
|
9560
|
+
JOIN objects AS stored
|
|
9561
|
+
ON stored.project_id = grants.project_id
|
|
9562
|
+
AND stored.object_type_id = grants.object_type_id
|
|
9563
|
+
AND stored.primary_id = grants.primary_id
|
|
9182
9564
|
),
|
|
9183
9565
|
_sixb_scope_reached_links(
|
|
9184
9566
|
project_id,
|
|
@@ -9385,6 +9767,7 @@ var PG_OBJECT_QUERY_CAPABILITIES = {
|
|
|
9385
9767
|
refs: true,
|
|
9386
9768
|
filter: true,
|
|
9387
9769
|
text: true,
|
|
9770
|
+
vector: true,
|
|
9388
9771
|
sort: true,
|
|
9389
9772
|
limit: true,
|
|
9390
9773
|
page: true,
|
|
@@ -9427,7 +9810,8 @@ var PG_OBJECT_QUERY_CAPABILITIES = {
|
|
|
9427
9810
|
double: { equality: true, ordering: true },
|
|
9428
9811
|
decimal: { equality: true, ordering: true },
|
|
9429
9812
|
date: { equality: true, ordering: true },
|
|
9430
|
-
timestamp: { equality: true, ordering: true }
|
|
9813
|
+
timestamp: { equality: true, ordering: true },
|
|
9814
|
+
userRef: { equality: true }
|
|
9431
9815
|
},
|
|
9432
9816
|
limits: {
|
|
9433
9817
|
totalCount: true,
|
|
@@ -9437,7 +9821,7 @@ var PG_OBJECT_QUERY_CAPABILITIES = {
|
|
|
9437
9821
|
"PostgreSQL object query pushdown supports start/refs/filter/text/sort/limit/page/traverse/set/project/expand over JSONB properties and object links.",
|
|
9438
9822
|
"expand hydrates linked objects in-database (top-N per parent via LATERAL + jsonb_agg); core resolves each expansion's cardinality before pushdown, and a mixed/unresolved one stays on the fallback.",
|
|
9439
9823
|
"Exact decimal predicates, ordering, and keyset pagination use PostgreSQL numeric casts.",
|
|
9440
|
-
"Relevance sorting
|
|
9824
|
+
"Relevance sorting and unresolved start.includeSubtypes remain planner fallback or rejection cases."
|
|
9441
9825
|
]
|
|
9442
9826
|
};
|
|
9443
9827
|
|
|
@@ -9455,15 +9839,23 @@ class PgObjectStorage {
|
|
|
9455
9839
|
return createPgSelectedReader(this.sql, params, () => this.queryCapabilities());
|
|
9456
9840
|
}
|
|
9457
9841
|
async queryObjects(params) {
|
|
9842
|
+
if (hasVectorProfile3(params.query))
|
|
9843
|
+
return runPgRepeatableReadTransaction(this.sql, (tx) => new PgObjectReader(tx, DEFAULT_OBJECT_QUERY_SOURCE).queryObjects(params));
|
|
9458
9844
|
return this.reader.queryObjects(params);
|
|
9459
9845
|
}
|
|
9460
9846
|
async countObjects(params) {
|
|
9847
|
+
if (hasVectorProfile3(params.query))
|
|
9848
|
+
return runPgRepeatableReadTransaction(this.sql, (tx) => new PgObjectReader(tx, DEFAULT_OBJECT_QUERY_SOURCE).countObjects(params));
|
|
9461
9849
|
return this.reader.countObjects(params);
|
|
9462
9850
|
}
|
|
9463
9851
|
async existsObjects(params) {
|
|
9852
|
+
if (hasVectorProfile3(params.query))
|
|
9853
|
+
return runPgRepeatableReadTransaction(this.sql, (tx) => new PgObjectReader(tx, DEFAULT_OBJECT_QUERY_SOURCE).existsObjects(params));
|
|
9464
9854
|
return this.reader.existsObjects(params);
|
|
9465
9855
|
}
|
|
9466
9856
|
async facetObjects(params) {
|
|
9857
|
+
if (hasVectorProfile3(params.query))
|
|
9858
|
+
return runPgRepeatableReadTransaction(this.sql, (tx) => new PgObjectReader(tx, DEFAULT_OBJECT_QUERY_SOURCE).facetObjects(params));
|
|
9467
9859
|
return this.reader.facetObjects(params);
|
|
9468
9860
|
}
|
|
9469
9861
|
async getByPrimaryId(params) {
|
|
@@ -9622,9 +10014,10 @@ function commitRecord(row) {
|
|
|
9622
10014
|
requestHash: row.request_hash,
|
|
9623
10015
|
executionId: row.execution_id,
|
|
9624
10016
|
origin: structuredClone(row.origin),
|
|
9625
|
-
...row.
|
|
9626
|
-
|
|
10017
|
+
...row.requested_by === null ? {} : {
|
|
10018
|
+
requestedBy: structuredClone(row.requested_by)
|
|
9627
10019
|
},
|
|
10020
|
+
executor: structuredClone(row.executor),
|
|
9628
10021
|
ontologyRevision: row.ontology_revision,
|
|
9629
10022
|
...row.projection_revision === null ? {} : { projectionRevision: row.projection_revision },
|
|
9630
10023
|
...row.ownership_hash === null ? {} : { ownershipHash: row.ownership_hash },
|
|
@@ -9766,12 +10159,16 @@ import {
|
|
|
9766
10159
|
linkRefSortKey,
|
|
9767
10160
|
linkScopeSortKey as linkScopeSortKey2,
|
|
9768
10161
|
MaterializationConflictError as MaterializationConflictError6,
|
|
10162
|
+
MaterializationValidationError as MaterializationValidationError2,
|
|
9769
10163
|
objectRefKey as objectRefKey3,
|
|
9770
10164
|
objectRefSortKey,
|
|
9771
10165
|
telemetryPointKey as telemetryPointKey3,
|
|
9772
10166
|
telemetryPointSortKey as telemetryPointSortKey2
|
|
9773
10167
|
} from "@sixb/core/internal/materialization";
|
|
9774
10168
|
import {
|
|
10169
|
+
assertExpectedLinkRevision,
|
|
10170
|
+
assertExpectedLinkScopeRevision,
|
|
10171
|
+
assertExpectedObjectRevision,
|
|
9775
10172
|
assertMaterializationFinalizationCorrelation,
|
|
9776
10173
|
assertMaterializationHeader,
|
|
9777
10174
|
assertMaterializationLaneCompletion,
|
|
@@ -11692,6 +12089,12 @@ class PgOntologyMaterializationStorage {
|
|
|
11692
12089
|
this.sessions = new PgMaterializationSessions(sql, context);
|
|
11693
12090
|
this.writer = new PgMaterializationWriter(sql);
|
|
11694
12091
|
}
|
|
12092
|
+
assertVectorSession(session, projectId, commitId) {
|
|
12093
|
+
const active = this.sessions.require(session);
|
|
12094
|
+
if (active.header.commit.projectId !== projectId || commitId !== undefined && active.header.commit.id !== commitId) {
|
|
12095
|
+
throw new MaterializationValidationError2("Vector mutation does not belong to this materialization session.");
|
|
12096
|
+
}
|
|
12097
|
+
}
|
|
11695
12098
|
async begin(input) {
|
|
11696
12099
|
assertMaterializationHeader(input);
|
|
11697
12100
|
const session = await this.sessions.create(input);
|
|
@@ -11702,17 +12105,15 @@ class PgOntologyMaterializationStorage {
|
|
|
11702
12105
|
await this.assertSources(input.expected.sources, input.commit.projectId);
|
|
11703
12106
|
const objectRevisions = await reader.effectiveObjectRevisions(input.expected.objects.map((expected) => expected.ref), true);
|
|
11704
12107
|
for (const expected of input.expected.objects) {
|
|
11705
|
-
|
|
12108
|
+
assertExpectedObjectRevision(objectRevisions.get(objectRefKey3(expected.ref)) ?? null, expected);
|
|
11706
12109
|
}
|
|
11707
12110
|
const linkRevisions = await reader.effectiveLinkLastCommits(input.expected.links.map((expected) => expected.ref), true);
|
|
11708
12111
|
for (const expected of input.expected.links) {
|
|
11709
|
-
|
|
12112
|
+
assertExpectedLinkRevision(linkRevisions.get(linkRefKey3(expected.ref)), expected);
|
|
11710
12113
|
}
|
|
11711
12114
|
const linkScopeRevisions = await reader.linkScopeRevisions(input.expected.linkScopes);
|
|
11712
12115
|
for (const [index, expected] of input.expected.linkScopes.entries()) {
|
|
11713
|
-
|
|
11714
|
-
throw new MaterializationConflictError6("effective-state", `Expected link scope changed for ${expected.source.objectTypeId}:${expected.source.primaryId}.${expected.linkId}.`);
|
|
11715
|
-
}
|
|
12116
|
+
assertExpectedLinkScopeRevision(linkScopeRevisions[index]?.fingerprint, expected);
|
|
11716
12117
|
}
|
|
11717
12118
|
const points = await reader.exactPoints(input.expected.points, true);
|
|
11718
12119
|
const pointRevisions = new Map(points.map((point) => [telemetryPointKey3(point.series, point.at), point.lastCommitId]));
|
|
@@ -11972,28 +12373,6 @@ class PgOntologyMaterializationStorage {
|
|
|
11972
12373
|
throw new MaterializationConflictError6("projection-fence", `Source '${expected.source.projectionId}' changed.`);
|
|
11973
12374
|
}
|
|
11974
12375
|
}
|
|
11975
|
-
assertObject(row, expected) {
|
|
11976
|
-
if (!expected.exists) {
|
|
11977
|
-
if (row) {
|
|
11978
|
-
throw new MaterializationConflictError6("effective-state", `Expected object ${objectRefKey3(expected.ref)} to be absent.`);
|
|
11979
|
-
}
|
|
11980
|
-
return;
|
|
11981
|
-
}
|
|
11982
|
-
if (!row || row.version !== expected.version || row.lastCommitId !== expected.lastCommitId) {
|
|
11983
|
-
throw new MaterializationConflictError6("effective-state", `Expected object ${objectRefKey3(expected.ref)} changed.`);
|
|
11984
|
-
}
|
|
11985
|
-
}
|
|
11986
|
-
assertLink(lastCommitId, expected) {
|
|
11987
|
-
if (!expected.exists) {
|
|
11988
|
-
if (lastCommitId !== undefined) {
|
|
11989
|
-
throw new MaterializationConflictError6("effective-state", `Expected link ${linkRefKey3(expected.ref)} to be absent.`);
|
|
11990
|
-
}
|
|
11991
|
-
return;
|
|
11992
|
-
}
|
|
11993
|
-
if (lastCommitId === undefined || lastCommitId !== expected.lastCommitId) {
|
|
11994
|
-
throw new MaterializationConflictError6("effective-state", `Expected link ${linkRefKey3(expected.ref)} changed.`);
|
|
11995
|
-
}
|
|
11996
|
-
}
|
|
11997
12376
|
async assertFinalization(session, input) {
|
|
11998
12377
|
const { commit } = session.header;
|
|
11999
12378
|
const { result } = input.finalization;
|
|
@@ -12229,18 +12608,19 @@ class PgOntologyMaterializationStorage {
|
|
|
12229
12608
|
async insertCommit(header, input) {
|
|
12230
12609
|
const { commit } = header;
|
|
12231
12610
|
const origin = originColumns(commit.origin);
|
|
12232
|
-
const
|
|
12611
|
+
const requestedBy = commit.requestedBy === undefined ? null : jsonParameter2(this.sql, commit.requestedBy);
|
|
12233
12612
|
const rows = await this.sql`
|
|
12234
12613
|
INSERT INTO ontology_commits (
|
|
12235
12614
|
project_id, id, idempotency_key, request_hash, execution_id,
|
|
12236
|
-
origin_kind, origin_run_id, origin_batch_ordinal, origin,
|
|
12615
|
+
origin_kind, origin_run_id, origin_batch_ordinal, origin, requested_by, executor,
|
|
12237
12616
|
ontology_revision, projection_revision, ownership_hash,
|
|
12238
12617
|
intent, result, committed_at
|
|
12239
12618
|
) VALUES (
|
|
12240
12619
|
${commit.projectId}, ${commit.id}, ${commit.idempotencyKey}, ${commit.requestHash},
|
|
12241
12620
|
${commit.executionId},
|
|
12242
12621
|
${origin.kind}, ${origin.runId}, ${origin.batchOrdinal},
|
|
12243
|
-
${jsonParameter2(this.sql, commit.origin)}, ${
|
|
12622
|
+
${jsonParameter2(this.sql, commit.origin)}, ${requestedBy},
|
|
12623
|
+
${jsonParameter2(this.sql, commit.executor)}, ${commit.ontologyRevision},
|
|
12244
12624
|
${commit.projectionRevision ?? null}, ${commit.ownershipHash ?? null},
|
|
12245
12625
|
${jsonParameter2(this.sql, commit.intent)},
|
|
12246
12626
|
${jsonParameter2(this.sql, input.finalization.result)}, ${commit.committedAt}
|
|
@@ -12299,7 +12679,7 @@ function databaseCount(value) {
|
|
|
12299
12679
|
import { serializeSixbFailure as serializeSixbFailure2 } from "@sixb/core/internal/errors";
|
|
12300
12680
|
import {
|
|
12301
12681
|
MaterializationConflictError as MaterializationConflictError7,
|
|
12302
|
-
MaterializationValidationError as
|
|
12682
|
+
MaterializationValidationError as MaterializationValidationError3
|
|
12303
12683
|
} from "@sixb/core/internal/materialization";
|
|
12304
12684
|
import { ONTOLOGY_OUTBOX_FAILURE_CODES as ONTOLOGY_OUTBOX_FAILURE_CODES2 } from "@sixb/core/storage";
|
|
12305
12685
|
class PgOntologyOutboxStorage {
|
|
@@ -12315,7 +12695,7 @@ class PgOntologyOutboxStorage {
|
|
|
12315
12695
|
const leaseExpiry = assertTimestamp(input.leaseExpiresAt, "Ontology outbox lease expiry");
|
|
12316
12696
|
assertNonblank(input.leaseId, "Ontology outbox lease id");
|
|
12317
12697
|
if (leaseExpiry <= now) {
|
|
12318
|
-
throw new
|
|
12698
|
+
throw new MaterializationValidationError3("Ontology outbox lease expiry must be later than the claim time.");
|
|
12319
12699
|
}
|
|
12320
12700
|
const rows = await sql`
|
|
12321
12701
|
WITH candidates AS (
|
|
@@ -12466,7 +12846,7 @@ function validateLeaseIds(ids) {
|
|
|
12466
12846
|
for (const id of ids) {
|
|
12467
12847
|
assertNonblank(id, "Ontology outbox event id");
|
|
12468
12848
|
if (seen.has(id)) {
|
|
12469
|
-
throw new
|
|
12849
|
+
throw new MaterializationValidationError3(`Ontology outbox lease batch repeats event '${id}'.`);
|
|
12470
12850
|
}
|
|
12471
12851
|
seen.add(id);
|
|
12472
12852
|
}
|
|
@@ -12481,7 +12861,7 @@ function leaseConflict() {
|
|
|
12481
12861
|
}
|
|
12482
12862
|
|
|
12483
12863
|
// src/ontology-storage/sources.ts
|
|
12484
|
-
import { MaterializationValidationError as
|
|
12864
|
+
import { MaterializationValidationError as MaterializationValidationError4 } from "@sixb/core/internal/materialization";
|
|
12485
12865
|
import {
|
|
12486
12866
|
assertSourceBeginInput as assertBeginInput,
|
|
12487
12867
|
assertSourceExecutionIdentity as assertExecutionIdentity,
|
|
@@ -12641,7 +13021,7 @@ class PgOntologySourceStorage {
|
|
|
12641
13021
|
throw sourceConflict(`Source materialization '${input.materializationId}' cannot transition from '${manifest.status}' to 'ready'.`);
|
|
12642
13022
|
}
|
|
12643
13023
|
if (input.readyAt < toIsoString2(manifest.created_at)) {
|
|
12644
|
-
throw new
|
|
13024
|
+
throw new MaterializationValidationError4("Source readyAt cannot precede source createdAt.");
|
|
12645
13025
|
}
|
|
12646
13026
|
if (input.assertionCount >= 1000 || input.rootCount >= 1000) {
|
|
12647
13027
|
await sql`ANALYZE ontology_source_rows, ontology_source_roots`;
|
|
@@ -12739,7 +13119,7 @@ class PgOntologySourceStorage {
|
|
|
12739
13119
|
}
|
|
12740
13120
|
async transitionToAbandoned(sql, manifest, abandonedAt) {
|
|
12741
13121
|
if (abandonedAt < toIsoString2(manifest.created_at) || manifest.ready_at !== null && abandonedAt < toIsoString2(manifest.ready_at)) {
|
|
12742
|
-
throw new
|
|
13122
|
+
throw new MaterializationValidationError4("Source abandonedAt cannot precede source creation or readiness.");
|
|
12743
13123
|
}
|
|
12744
13124
|
const rows = await sql`
|
|
12745
13125
|
UPDATE ontology_sources
|
|
@@ -12777,7 +13157,7 @@ class PgOntologySourceStorage {
|
|
|
12777
13157
|
const minimum = counts?.min_ordinal === null ? null : Number(counts?.min_ordinal);
|
|
12778
13158
|
const maximum = counts?.max_ordinal === null ? null : Number(counts?.max_ordinal);
|
|
12779
13159
|
if (assertions !== assertionCount || roots !== rootCount || ordinals !== rootCount || rootCount > 0 && (minimum !== 0 || maximum !== rootCount - 1)) {
|
|
12780
|
-
throw new
|
|
13160
|
+
throw new MaterializationValidationError4("Source ready counts do not match the staged roots and assertions.");
|
|
12781
13161
|
}
|
|
12782
13162
|
await assertSourceRootCoverage(sql, manifest);
|
|
12783
13163
|
const [invalid] = manifest.projection_kind === "link" ? await sql`
|
|
@@ -12813,7 +13193,7 @@ class PgOntologySourceStorage {
|
|
|
12813
13193
|
LIMIT 1
|
|
12814
13194
|
`;
|
|
12815
13195
|
if (invalid) {
|
|
12816
|
-
throw new
|
|
13196
|
+
throw new MaterializationValidationError4(manifest.projection_kind === "link" ? "Link projection roots must contain exactly their matching link assertion." : "Object projection roots must contain exactly their matching object assertion plus links sourced from that root.");
|
|
12817
13197
|
}
|
|
12818
13198
|
}
|
|
12819
13199
|
async findStageRows(sql, input, rows) {
|
|
@@ -12945,17 +13325,300 @@ function numberOrNull(value) {
|
|
|
12945
13325
|
return value === null ? null : Number(value);
|
|
12946
13326
|
}
|
|
12947
13327
|
|
|
13328
|
+
// src/ontology-storage/vector-indexing.ts
|
|
13329
|
+
import { parseSixbFailure as parseSixbFailure3 } from "@sixb/core/internal/errors";
|
|
13330
|
+
import {
|
|
13331
|
+
VECTOR_INDEXING_FAILURE_CODES
|
|
13332
|
+
} from "@sixb/core/storage";
|
|
13333
|
+
class PgVectorIndexingStorage {
|
|
13334
|
+
sql;
|
|
13335
|
+
run;
|
|
13336
|
+
assertSession;
|
|
13337
|
+
constructor(sql, run, assertSession) {
|
|
13338
|
+
this.sql = sql;
|
|
13339
|
+
this.run = run;
|
|
13340
|
+
this.assertSession = assertSession;
|
|
13341
|
+
}
|
|
13342
|
+
async schedule(input) {
|
|
13343
|
+
this.assertSession(input.session, input.projectId);
|
|
13344
|
+
if (input.deleted.length)
|
|
13345
|
+
await this.sql`
|
|
13346
|
+
DELETE FROM object_vector_indexing AS work
|
|
13347
|
+
USING jsonb_array_elements(${jsonParameter2(this.sql, input.deleted)}::jsonb) AS deleted(ref)
|
|
13348
|
+
WHERE work.project_id = ${input.projectId}
|
|
13349
|
+
AND work.object_type_id = deleted.ref->>'objectTypeId'
|
|
13350
|
+
AND work.primary_id = deleted.ref->>'primaryId'
|
|
13351
|
+
`;
|
|
13352
|
+
if (input.requests.length)
|
|
13353
|
+
await this.sql`
|
|
13354
|
+
INSERT INTO object_vector_indexing (
|
|
13355
|
+
project_id, id, object_type_id, primary_id, profile, batch_id, request, status, available_at, dispatch_at
|
|
13356
|
+
)
|
|
13357
|
+
SELECT ${input.projectId}, entry->>'id', entry#>>'{ref,objectTypeId}',
|
|
13358
|
+
entry#>>'{ref,primaryId}', entry->>'profile', entry->>'batchId', entry - 'batchId', 'pending',
|
|
13359
|
+
${input.availableAt}::timestamptz, ${input.availableAt}::timestamptz
|
|
13360
|
+
FROM jsonb_array_elements(${jsonParameter2(this.sql, input.requests)}::jsonb) AS pending(entry)
|
|
13361
|
+
ON CONFLICT (project_id, object_type_id, primary_id, profile) DO UPDATE SET
|
|
13362
|
+
id = EXCLUDED.id, batch_id = EXCLUDED.batch_id, request = EXCLUDED.request, status = 'pending',
|
|
13363
|
+
available_at = EXCLUDED.available_at, dispatch_at = EXCLUDED.dispatch_at,
|
|
13364
|
+
values_json = NULL, error = NULL
|
|
13365
|
+
`;
|
|
13366
|
+
}
|
|
13367
|
+
async complete(input) {
|
|
13368
|
+
this.assertSession(input.session, input.projectId);
|
|
13369
|
+
if (!input.entries.length)
|
|
13370
|
+
return;
|
|
13371
|
+
await this.sql`
|
|
13372
|
+
DELETE FROM object_vector_indexing AS work
|
|
13373
|
+
USING jsonb_array_elements(${jsonParameter2(this.sql, input.entries)}::jsonb) AS completed(entry)
|
|
13374
|
+
WHERE work.project_id = ${input.projectId}
|
|
13375
|
+
AND work.object_type_id = entry#>>'{ref,objectTypeId}'
|
|
13376
|
+
AND work.primary_id = entry#>>'{ref,primaryId}'
|
|
13377
|
+
AND work.profile = entry->>'profile'
|
|
13378
|
+
AND work.request->>'configuration' = entry->>'configuration'
|
|
13379
|
+
AND work.request->>'sourceFingerprint' = entry->>'sourceFingerprint'
|
|
13380
|
+
`;
|
|
13381
|
+
}
|
|
13382
|
+
async dispatched(input) {
|
|
13383
|
+
if (!input.ids.length)
|
|
13384
|
+
return;
|
|
13385
|
+
await this.run(async (sql) => {
|
|
13386
|
+
await sql`UPDATE object_vector_indexing SET dispatch_at = ${input.nextDispatchAt} WHERE project_id = ${input.projectId} AND id = ANY(${sql.array([...input.ids])}::text[])`;
|
|
13387
|
+
});
|
|
13388
|
+
}
|
|
13389
|
+
async get(input) {
|
|
13390
|
+
return this.run(async (sql) => {
|
|
13391
|
+
const rows = await sql`SELECT batch_id, request, status, available_at, values_json, error FROM object_vector_indexing WHERE project_id = ${input.projectId} AND id = ${input.id}`;
|
|
13392
|
+
return rows[0] ? decode(rows[0]) : null;
|
|
13393
|
+
});
|
|
13394
|
+
}
|
|
13395
|
+
async getBatch(input) {
|
|
13396
|
+
return this.run(async (sql) => (await sql`
|
|
13397
|
+
SELECT batch_id, request, status, available_at, values_json, error
|
|
13398
|
+
FROM object_vector_indexing WHERE project_id = ${input.projectId}
|
|
13399
|
+
AND batch_id = ${input.batchId} ORDER BY id`).map(decode));
|
|
13400
|
+
}
|
|
13401
|
+
async getBatchMember(input) {
|
|
13402
|
+
return this.run(async (sql) => {
|
|
13403
|
+
const rows = await sql`
|
|
13404
|
+
SELECT batch_id, request, status, available_at, values_json, error
|
|
13405
|
+
FROM object_vector_indexing WHERE project_id = ${input.projectId}
|
|
13406
|
+
AND object_type_id = ${input.ref.objectTypeId} AND primary_id = ${input.ref.primaryId}
|
|
13407
|
+
AND profile = ${input.profile} AND batch_id = ${input.batchId}`;
|
|
13408
|
+
return rows[0] ? decode(rows[0]) : null;
|
|
13409
|
+
});
|
|
13410
|
+
}
|
|
13411
|
+
async updateBatch(input) {
|
|
13412
|
+
if (!input.updates.length)
|
|
13413
|
+
return true;
|
|
13414
|
+
return this.run(async (sql) => {
|
|
13415
|
+
const rows = await sql`
|
|
13416
|
+
WITH changes AS MATERIALIZED (
|
|
13417
|
+
SELECT item FROM jsonb_array_elements(${jsonParameter2(sql, input.updates)}::jsonb) AS entries(item)
|
|
13418
|
+
), locked AS MATERIALIZED (
|
|
13419
|
+
SELECT work.id FROM object_vector_indexing AS work
|
|
13420
|
+
JOIN changes ON work.id = item->>'id' AND work.status = item->>'expectedStatus'
|
|
13421
|
+
WHERE work.project_id = ${input.projectId} ORDER BY work.id FOR UPDATE OF work
|
|
13422
|
+
)
|
|
13423
|
+
UPDATE object_vector_indexing AS work SET
|
|
13424
|
+
status = changes.item->>'status', available_at = (changes.item->>'availableAt')::timestamptz,
|
|
13425
|
+
values_json = COALESCE(changes.item->'values', work.values_json),
|
|
13426
|
+
error = (changes.item->'error')::text
|
|
13427
|
+
FROM changes, locked
|
|
13428
|
+
WHERE work.project_id = ${input.projectId} AND work.id = locked.id
|
|
13429
|
+
AND work.id = changes.item->>'id'
|
|
13430
|
+
AND (${!input.requireAll} OR (SELECT count(*) FROM locked) = ${input.updates.length})
|
|
13431
|
+
RETURNING work.id`;
|
|
13432
|
+
return !input.requireAll || rows.length === input.updates.length;
|
|
13433
|
+
});
|
|
13434
|
+
}
|
|
13435
|
+
async listDue(input) {
|
|
13436
|
+
return this.run(async (sql) => (await sql`SELECT batch_id, request, status, available_at, NULL AS values_json, error FROM object_vector_indexing WHERE project_id = ${input.projectId} AND status <> 'failed' AND dispatch_at <= ${input.now} ORDER BY dispatch_at, id LIMIT ${input.limit}`).map(decode));
|
|
13437
|
+
}
|
|
13438
|
+
async update(input) {
|
|
13439
|
+
return this.run(async (sql) => (await sql`
|
|
13440
|
+
UPDATE object_vector_indexing SET status = ${input.status}, available_at = ${input.availableAt},
|
|
13441
|
+
values_json = COALESCE(${input.values ? jsonParameter2(sql, input.values) : null}, values_json), error = ${input.error ? JSON.stringify(input.error) : null}
|
|
13442
|
+
WHERE project_id = ${input.projectId} AND id = ${input.id} AND status = ${input.expectedStatus} RETURNING id
|
|
13443
|
+
`).length === 1);
|
|
13444
|
+
}
|
|
13445
|
+
async remove(input) {
|
|
13446
|
+
await this.run(async (sql) => {
|
|
13447
|
+
await sql`DELETE FROM object_vector_indexing WHERE project_id = ${input.projectId} AND id = ${input.id}`;
|
|
13448
|
+
});
|
|
13449
|
+
}
|
|
13450
|
+
}
|
|
13451
|
+
function decode(row) {
|
|
13452
|
+
return {
|
|
13453
|
+
...row.request,
|
|
13454
|
+
...row.batch_id ? { batchId: row.batch_id } : {},
|
|
13455
|
+
status: row.status,
|
|
13456
|
+
availableAt: new Date(row.available_at).toISOString(),
|
|
13457
|
+
...row.values_json ? { values: row.values_json } : {},
|
|
13458
|
+
...row.error ? {
|
|
13459
|
+
error: parseSixbFailure3(row.error, VECTOR_INDEXING_FAILURE_CODES)
|
|
13460
|
+
} : {}
|
|
13461
|
+
};
|
|
13462
|
+
}
|
|
13463
|
+
|
|
13464
|
+
// src/ontology-storage/vectors.ts
|
|
13465
|
+
import { MaterializationConflictError as MaterializationConflictError8 } from "@sixb/core/internal/materialization";
|
|
13466
|
+
class PgOntologyVectorStorage {
|
|
13467
|
+
sql;
|
|
13468
|
+
runRootOperation;
|
|
13469
|
+
assertSession;
|
|
13470
|
+
constructor(sql, runRootOperation, assertSession) {
|
|
13471
|
+
this.sql = sql;
|
|
13472
|
+
this.runRootOperation = runRootOperation;
|
|
13473
|
+
this.assertSession = assertSession;
|
|
13474
|
+
}
|
|
13475
|
+
async list(input) {
|
|
13476
|
+
return this.runRootOperation(async (sql) => {
|
|
13477
|
+
const rows = await sql`
|
|
13478
|
+
SELECT profile, configuration, source, source_fingerprint, last_commit_id
|
|
13479
|
+
FROM object_vectors
|
|
13480
|
+
WHERE project_id = ${input.projectId}
|
|
13481
|
+
AND object_type_id = ${input.ref.objectTypeId} AND primary_id = ${input.ref.primaryId}
|
|
13482
|
+
ORDER BY profile
|
|
13483
|
+
`;
|
|
13484
|
+
return rows.map((row) => ({
|
|
13485
|
+
ref: { ...input.ref },
|
|
13486
|
+
profile: row.profile,
|
|
13487
|
+
configuration: row.configuration,
|
|
13488
|
+
source: row.source,
|
|
13489
|
+
sourceFingerprint: row.source_fingerprint,
|
|
13490
|
+
lastCommitId: row.last_commit_id
|
|
13491
|
+
}));
|
|
13492
|
+
});
|
|
13493
|
+
}
|
|
13494
|
+
async listBatch(input) {
|
|
13495
|
+
if (!input.refs.length)
|
|
13496
|
+
return [];
|
|
13497
|
+
return this.runRootOperation(async (sql) => {
|
|
13498
|
+
const rows = await sql`
|
|
13499
|
+
SELECT stored.object_type_id, stored.primary_id, stored.profile, stored.configuration,
|
|
13500
|
+
stored.source, stored.source_fingerprint, stored.last_commit_id
|
|
13501
|
+
FROM (SELECT DISTINCT ref->>'objectTypeId' AS object_type_id, ref->>'primaryId' AS primary_id
|
|
13502
|
+
FROM jsonb_array_elements(${jsonParameter2(sql, input.refs)}::jsonb) AS requested(ref)) AS requested
|
|
13503
|
+
JOIN object_vectors AS stored ON stored.project_id = ${input.projectId}
|
|
13504
|
+
AND stored.object_type_id = requested.object_type_id AND stored.primary_id = requested.primary_id
|
|
13505
|
+
ORDER BY stored.object_type_id, stored.primary_id, stored.profile
|
|
13506
|
+
`;
|
|
13507
|
+
return rows.map((row) => ({
|
|
13508
|
+
ref: { objectTypeId: row.object_type_id, primaryId: row.primary_id },
|
|
13509
|
+
profile: row.profile,
|
|
13510
|
+
configuration: row.configuration,
|
|
13511
|
+
source: row.source,
|
|
13512
|
+
sourceFingerprint: row.source_fingerprint,
|
|
13513
|
+
lastCommitId: row.last_commit_id
|
|
13514
|
+
}));
|
|
13515
|
+
});
|
|
13516
|
+
}
|
|
13517
|
+
async removeBatch(input) {
|
|
13518
|
+
this.assertSession(input.session, input.projectId);
|
|
13519
|
+
if (!input.entries.length)
|
|
13520
|
+
return;
|
|
13521
|
+
const removed = await this.sql`
|
|
13522
|
+
DELETE FROM object_vectors AS stored
|
|
13523
|
+
USING jsonb_array_elements(${jsonParameter2(this.sql, input.entries)}::jsonb) AS requested(entry)
|
|
13524
|
+
WHERE stored.project_id = ${input.projectId}
|
|
13525
|
+
AND stored.object_type_id = entry#>>'{ref,objectTypeId}'
|
|
13526
|
+
AND stored.primary_id = entry#>>'{ref,primaryId}' AND stored.profile = entry->>'profile'
|
|
13527
|
+
AND stored.last_commit_id = entry->>'expectedCommitId'
|
|
13528
|
+
RETURNING stored.profile
|
|
13529
|
+
`;
|
|
13530
|
+
if (removed.length !== input.entries.length)
|
|
13531
|
+
throw vectorConflict();
|
|
13532
|
+
}
|
|
13533
|
+
async write(input) {
|
|
13534
|
+
await this.writeBatch({ session: input.session, projectId: input.projectId, entries: [input] });
|
|
13535
|
+
}
|
|
13536
|
+
async writeBatch(input) {
|
|
13537
|
+
const entries = input.entries.map(({ value, expectedCommitId }) => {
|
|
13538
|
+
this.assertSession(input.session, input.projectId, value.lastCommitId);
|
|
13539
|
+
return {
|
|
13540
|
+
object_type_id: value.ref.objectTypeId,
|
|
13541
|
+
primary_id: value.ref.primaryId,
|
|
13542
|
+
profile: value.profile,
|
|
13543
|
+
configuration: value.configuration,
|
|
13544
|
+
source: [...value.source],
|
|
13545
|
+
source_fingerprint: value.sourceFingerprint,
|
|
13546
|
+
embedding: [...value.values],
|
|
13547
|
+
last_commit_id: value.lastCommitId,
|
|
13548
|
+
expected_commit_id: expectedCommitId
|
|
13549
|
+
};
|
|
13550
|
+
});
|
|
13551
|
+
const inserts = entries.filter((entry) => entry.expected_commit_id === null);
|
|
13552
|
+
const updates = entries.filter((entry) => entry.expected_commit_id !== null);
|
|
13553
|
+
if (inserts.length) {
|
|
13554
|
+
const rows = await this.sql`
|
|
13555
|
+
INSERT INTO object_vectors (
|
|
13556
|
+
project_id, object_type_id, primary_id, profile, configuration,
|
|
13557
|
+
source, source_fingerprint, embedding, last_commit_id
|
|
13558
|
+
)
|
|
13559
|
+
SELECT ${input.projectId}, object_type_id, primary_id, profile, configuration,
|
|
13560
|
+
source, source_fingerprint, embedding, last_commit_id
|
|
13561
|
+
FROM jsonb_to_recordset(${jsonParameter2(this.sql, inserts)}::jsonb) AS incoming(
|
|
13562
|
+
object_type_id text, primary_id text, profile text, configuration text,
|
|
13563
|
+
source text[], source_fingerprint text, embedding real[], last_commit_id text
|
|
13564
|
+
)
|
|
13565
|
+
ORDER BY object_type_id, primary_id, profile
|
|
13566
|
+
ON CONFLICT (project_id, object_type_id, primary_id, profile) DO NOTHING
|
|
13567
|
+
RETURNING profile`;
|
|
13568
|
+
if (rows.length !== inserts.length)
|
|
13569
|
+
throw vectorConflict();
|
|
13570
|
+
}
|
|
13571
|
+
if (updates.length) {
|
|
13572
|
+
const rows = await this.sql`
|
|
13573
|
+
UPDATE object_vectors AS stored SET
|
|
13574
|
+
configuration = incoming.configuration, source = incoming.source,
|
|
13575
|
+
source_fingerprint = incoming.source_fingerprint, embedding = incoming.embedding,
|
|
13576
|
+
last_commit_id = incoming.last_commit_id
|
|
13577
|
+
FROM jsonb_to_recordset(${jsonParameter2(this.sql, updates)}::jsonb) AS incoming(
|
|
13578
|
+
object_type_id text, primary_id text, profile text, configuration text,
|
|
13579
|
+
source text[], source_fingerprint text, embedding real[], last_commit_id text,
|
|
13580
|
+
expected_commit_id text
|
|
13581
|
+
)
|
|
13582
|
+
WHERE stored.project_id = ${input.projectId}
|
|
13583
|
+
AND stored.object_type_id = incoming.object_type_id AND stored.primary_id = incoming.primary_id
|
|
13584
|
+
AND stored.profile = incoming.profile AND stored.last_commit_id = incoming.expected_commit_id
|
|
13585
|
+
RETURNING stored.profile`;
|
|
13586
|
+
if (rows.length !== updates.length)
|
|
13587
|
+
throw vectorConflict();
|
|
13588
|
+
}
|
|
13589
|
+
}
|
|
13590
|
+
async remove(input) {
|
|
13591
|
+
this.assertSession(input.session, input.projectId);
|
|
13592
|
+
const rows = await this.sql`
|
|
13593
|
+
DELETE FROM object_vectors
|
|
13594
|
+
WHERE project_id = ${input.projectId}
|
|
13595
|
+
AND object_type_id = ${input.ref.objectTypeId} AND primary_id = ${input.ref.primaryId}
|
|
13596
|
+
AND profile = ${input.profile} AND last_commit_id = ${input.expectedCommitId}
|
|
13597
|
+
RETURNING profile
|
|
13598
|
+
`;
|
|
13599
|
+
if (rows.length !== 1)
|
|
13600
|
+
throw vectorConflict();
|
|
13601
|
+
}
|
|
13602
|
+
}
|
|
13603
|
+
function vectorConflict() {
|
|
13604
|
+
return new MaterializationConflictError8("effective-state", "Vector changed since it was prepared.");
|
|
13605
|
+
}
|
|
13606
|
+
|
|
12948
13607
|
// src/ontology-storage/index.ts
|
|
12949
13608
|
class PgOntologyStorage {
|
|
12950
13609
|
commits;
|
|
12951
13610
|
sources;
|
|
12952
13611
|
materializations;
|
|
12953
13612
|
outbox;
|
|
13613
|
+
vectorIndexing;
|
|
13614
|
+
vectors;
|
|
12954
13615
|
constructor(input) {
|
|
12955
13616
|
this.commits = new PgOntologyCommitStorage(input.runRootOperation);
|
|
12956
13617
|
this.sources = new PgOntologySourceStorage(input.runRootOperation);
|
|
12957
13618
|
this.materializations = new PgOntologyMaterializationStorage(input.sql, input.transactionContext);
|
|
12958
13619
|
this.outbox = new PgOntologyOutboxStorage(input.runRootOperation);
|
|
13620
|
+
this.vectorIndexing = new PgVectorIndexingStorage(input.sql, input.runRootOperation, (session, projectId) => this.materializations.assertVectorSession(session, projectId));
|
|
13621
|
+
this.vectors = new PgOntologyVectorStorage(input.sql, input.runRootOperation, (session, projectId, commitId) => this.materializations.assertVectorSession(session, projectId, commitId));
|
|
12959
13622
|
}
|
|
12960
13623
|
deactivateSessions() {
|
|
12961
13624
|
this.materializations.deactivateSessions();
|
|
@@ -13925,6 +14588,8 @@ class PgAiCostStorage {
|
|
|
13925
14588
|
COUNT(*)::text AS model_call_count,
|
|
13926
14589
|
COUNT(*) FILTER (WHERE reporting_status <> 'unavailable')::text
|
|
13927
14590
|
AS reported_usage_call_count,
|
|
14591
|
+
COUNT(*) FILTER (WHERE input_tokens IS NOT NULL AND output_tokens IS NOT NULL)::text
|
|
14592
|
+
AS complete_usage_call_count,
|
|
13928
14593
|
COUNT(input_tokens)::text AS input_tokens_count,
|
|
13929
14594
|
SUM(input_tokens)::text AS input_tokens_sum,
|
|
13930
14595
|
COUNT(output_tokens)::text AS output_tokens_count,
|
|
@@ -14066,6 +14731,7 @@ function aggregateFragmentFromRow(row) {
|
|
|
14066
14731
|
modelCallCount: row.model_call_count,
|
|
14067
14732
|
usage: {
|
|
14068
14733
|
reportedCallCount: row.reported_usage_call_count,
|
|
14734
|
+
completeCallCount: row.complete_usage_call_count,
|
|
14069
14735
|
inputTokens: meterFragment(row.input_tokens_count, row.input_tokens_sum),
|
|
14070
14736
|
outputTokens: meterFragment(row.output_tokens_count, row.output_tokens_sum),
|
|
14071
14737
|
uncachedInputTokens: meterFragment(row.uncached_input_tokens_count, row.uncached_input_tokens_sum),
|
|
@@ -15048,8 +15714,134 @@ function toStorageRow(row) {
|
|
|
15048
15714
|
};
|
|
15049
15715
|
}
|
|
15050
15716
|
|
|
15717
|
+
// src/pg-file-upload-session-storage.ts
|
|
15718
|
+
import {
|
|
15719
|
+
DurableFileUploadSessions,
|
|
15720
|
+
fileUploadSessionReapAt,
|
|
15721
|
+
parseFileUploadSessionRow
|
|
15722
|
+
} from "@sixb/core/internal/file-upload-session-storage-provider";
|
|
15723
|
+
class PgFileUploadSessionStorage extends DurableFileUploadSessions {
|
|
15724
|
+
constructor(sql) {
|
|
15725
|
+
super(new PgFileUploadSessionBackend(sql));
|
|
15726
|
+
}
|
|
15727
|
+
}
|
|
15728
|
+
|
|
15729
|
+
class PgFileUploadSessionBackend {
|
|
15730
|
+
sql;
|
|
15731
|
+
constructor(sql) {
|
|
15732
|
+
this.sql = sql;
|
|
15733
|
+
}
|
|
15734
|
+
read(run) {
|
|
15735
|
+
return run(new PgFileUploadSessionPersistence(this.sql, false));
|
|
15736
|
+
}
|
|
15737
|
+
transaction(run) {
|
|
15738
|
+
return runPgTransaction(this.sql, (tx) => run(new PgFileUploadSessionPersistence(tx, true)));
|
|
15739
|
+
}
|
|
15740
|
+
}
|
|
15741
|
+
|
|
15742
|
+
class PgFileUploadSessionPersistence {
|
|
15743
|
+
sql;
|
|
15744
|
+
locking;
|
|
15745
|
+
constructor(sql, locking) {
|
|
15746
|
+
this.sql = sql;
|
|
15747
|
+
this.locking = locking;
|
|
15748
|
+
}
|
|
15749
|
+
async now() {
|
|
15750
|
+
const [row] = await this.sql`SELECT clock_timestamp() AS now`;
|
|
15751
|
+
if (!row)
|
|
15752
|
+
throw new Error("[SixbPg] Database clock returned no row.");
|
|
15753
|
+
return new Date(row.now);
|
|
15754
|
+
}
|
|
15755
|
+
async insert(session) {
|
|
15756
|
+
const rows = await this.sql`
|
|
15757
|
+
INSERT INTO file_upload_sessions (
|
|
15758
|
+
id, project_id, owner_principal_type, owner_principal_id, strategy, status, file_name,
|
|
15759
|
+
media_type, logical_path, expected_size_bytes, expected_digest, provider_upload,
|
|
15760
|
+
signed_parts, file_ref, created_at, expires_at, completed_at, aborted_at, reap_at
|
|
15761
|
+
) VALUES (
|
|
15762
|
+
${session.id}, ${session.projectId}, ${session.principal.type}, ${session.principal.id},
|
|
15763
|
+
${session.strategy}, ${session.status}, ${session.fileName ?? null}, ${session.mediaType ?? null},
|
|
15764
|
+
${session.logicalPath ?? null}, ${session.expectedSizeBytes ?? null},
|
|
15765
|
+
${session.expectedDigest ?? null}, ${jsonText(session.providerUpload)}::text::jsonb,
|
|
15766
|
+
${JSON.stringify(session.signedParts)}::text::jsonb, ${jsonText(session.fileRef)}::text::jsonb,
|
|
15767
|
+
${session.createdAt}, ${session.expiresAt}, ${session.completedAt ?? null},
|
|
15768
|
+
${session.abortedAt ?? null}, ${fileUploadSessionReapAt(session)}
|
|
15769
|
+
)
|
|
15770
|
+
ON CONFLICT (id) DO NOTHING
|
|
15771
|
+
RETURNING id
|
|
15772
|
+
`;
|
|
15773
|
+
return rows.length === 1;
|
|
15774
|
+
}
|
|
15775
|
+
async get(uploadId) {
|
|
15776
|
+
const [row] = this.locking ? await this.sql`
|
|
15777
|
+
SELECT * FROM file_upload_sessions WHERE id = ${uploadId} FOR UPDATE
|
|
15778
|
+
` : await this.sql`
|
|
15779
|
+
SELECT * FROM file_upload_sessions WHERE id = ${uploadId}
|
|
15780
|
+
`;
|
|
15781
|
+
return row ? sessionFromRow(row) : null;
|
|
15782
|
+
}
|
|
15783
|
+
async update(session) {
|
|
15784
|
+
await this.sql`
|
|
15785
|
+
UPDATE file_upload_sessions
|
|
15786
|
+
SET status = ${session.status},
|
|
15787
|
+
provider_upload = ${jsonText(session.providerUpload)}::text::jsonb,
|
|
15788
|
+
signed_parts = ${JSON.stringify(session.signedParts)}::text::jsonb,
|
|
15789
|
+
file_ref = ${jsonText(session.fileRef)}::text::jsonb,
|
|
15790
|
+
created_at = ${session.createdAt},
|
|
15791
|
+
expires_at = ${session.expiresAt},
|
|
15792
|
+
completed_at = ${session.completedAt ?? null},
|
|
15793
|
+
aborted_at = ${session.abortedAt ?? null},
|
|
15794
|
+
reap_at = ${fileUploadSessionReapAt(session)}
|
|
15795
|
+
WHERE id = ${session.id}
|
|
15796
|
+
`;
|
|
15797
|
+
}
|
|
15798
|
+
async listAbandoned(input) {
|
|
15799
|
+
const rows = await this.sql`
|
|
15800
|
+
SELECT * FROM file_upload_sessions
|
|
15801
|
+
WHERE project_id = ${input.projectId} AND status = 'pending'
|
|
15802
|
+
AND provider_upload IS NOT NULL AND expires_at <= ${input.now}
|
|
15803
|
+
ORDER BY expires_at, id COLLATE "C"
|
|
15804
|
+
LIMIT ${input.limit}
|
|
15805
|
+
`;
|
|
15806
|
+
return rows.map(sessionFromRow);
|
|
15807
|
+
}
|
|
15808
|
+
async deleteReapable(now) {
|
|
15809
|
+
const rows = await this.sql`
|
|
15810
|
+
DELETE FROM file_upload_sessions
|
|
15811
|
+
WHERE reap_at IS NOT NULL AND reap_at <= ${now}
|
|
15812
|
+
RETURNING id
|
|
15813
|
+
`;
|
|
15814
|
+
return rows.length;
|
|
15815
|
+
}
|
|
15816
|
+
}
|
|
15817
|
+
function sessionFromRow(row) {
|
|
15818
|
+
return parseFileUploadSessionRow({
|
|
15819
|
+
id: row.id,
|
|
15820
|
+
projectId: row.project_id,
|
|
15821
|
+
ownerPrincipalType: row.owner_principal_type,
|
|
15822
|
+
ownerPrincipalId: row.owner_principal_id,
|
|
15823
|
+
strategy: row.strategy,
|
|
15824
|
+
status: row.status,
|
|
15825
|
+
fileName: row.file_name,
|
|
15826
|
+
mediaType: row.media_type,
|
|
15827
|
+
logicalPath: row.logical_path,
|
|
15828
|
+
expectedSizeBytes: row.expected_size_bytes,
|
|
15829
|
+
expectedDigest: row.expected_digest,
|
|
15830
|
+
providerUpload: row.provider_upload,
|
|
15831
|
+
signedParts: row.signed_parts,
|
|
15832
|
+
fileRef: row.file_ref,
|
|
15833
|
+
createdAt: row.created_at,
|
|
15834
|
+
expiresAt: row.expires_at,
|
|
15835
|
+
completedAt: row.completed_at,
|
|
15836
|
+
abortedAt: row.aborted_at
|
|
15837
|
+
});
|
|
15838
|
+
}
|
|
15839
|
+
function jsonText(value) {
|
|
15840
|
+
return value === undefined ? null : JSON.stringify(value);
|
|
15841
|
+
}
|
|
15842
|
+
|
|
15051
15843
|
// src/pg-pipeline-run-storage.ts
|
|
15052
|
-
import { parseSixbFailure as
|
|
15844
|
+
import { parseSixbFailure as parseSixbFailure4, serializeSixbFailure as serializeSixbFailure3 } from "@sixb/core/internal/errors";
|
|
15053
15845
|
import { assertPipelineRunExecution } from "@sixb/core/internal/pipeline-run-storage-provider";
|
|
15054
15846
|
import { canRequeuePipelineRunAfterEnqueueFailure } from "@sixb/core/internal/storage";
|
|
15055
15847
|
import { PIPELINE_RUN_FAILURE_CODES, PipelineRunError } from "@sixb/core/storage";
|
|
@@ -15403,7 +16195,7 @@ function rowToPipelineRunRecord(row) {
|
|
|
15403
16195
|
datasetId: row.output_dataset_id,
|
|
15404
16196
|
versionId: row.output_version_id
|
|
15405
16197
|
} : undefined,
|
|
15406
|
-
error: row.error === null ? undefined :
|
|
16198
|
+
error: row.error === null ? undefined : parseSixbFailure4(row.error, PIPELINE_RUN_FAILURE_CODES)
|
|
15407
16199
|
};
|
|
15408
16200
|
}
|
|
15409
16201
|
function rowToPipelineStepRunRecord(row) {
|
|
@@ -15424,7 +16216,7 @@ function rowToPipelineStepRunRecord(row) {
|
|
|
15424
16216
|
versionId: row.output_version_id
|
|
15425
16217
|
} : undefined,
|
|
15426
16218
|
rowsWritten: row.rows_written != null ? Number(row.rows_written) : undefined,
|
|
15427
|
-
error: row.error === null ? undefined :
|
|
16219
|
+
error: row.error === null ? undefined : parseSixbFailure4(row.error, PIPELINE_RUN_FAILURE_CODES)
|
|
15428
16220
|
};
|
|
15429
16221
|
}
|
|
15430
16222
|
function parseDatasetVersionRefs(value) {
|
|
@@ -16150,7 +16942,7 @@ function toIsoString3(value) {
|
|
|
16150
16942
|
}
|
|
16151
16943
|
|
|
16152
16944
|
// src/pg-sync-run-storage.ts
|
|
16153
|
-
import { parseSixbFailure as
|
|
16945
|
+
import { parseSixbFailure as parseSixbFailure5, serializeSixbFailure as serializeSixbFailure5 } from "@sixb/core/internal/errors";
|
|
16154
16946
|
import { canRequeueSyncRunAfterEnqueueFailure } from "@sixb/core/internal/storage";
|
|
16155
16947
|
import { assertSyncRunExecution } from "@sixb/core/internal/sync-run-storage-provider";
|
|
16156
16948
|
import { SYNC_RUN_FAILURE_CODES, SyncRunError } from "@sixb/core/storage";
|
|
@@ -16376,7 +17168,7 @@ function rowToSyncRunRecord(row) {
|
|
|
16376
17168
|
} : undefined,
|
|
16377
17169
|
expectedLatestVersionId: row.expected_latest_version_id ?? undefined,
|
|
16378
17170
|
commitMessage: row.commit_message ?? undefined,
|
|
16379
|
-
error: row.error === null ? undefined :
|
|
17171
|
+
error: row.error === null ? undefined : parseSixbFailure5(row.error, SYNC_RUN_FAILURE_CODES),
|
|
16380
17172
|
checkpoint: hasCheckpoint(row) ? row.checkpoint : undefined
|
|
16381
17173
|
};
|
|
16382
17174
|
}
|
|
@@ -16501,7 +17293,7 @@ function rowToPoint(row) {
|
|
|
16501
17293
|
}
|
|
16502
17294
|
|
|
16503
17295
|
// src/pg-webhook-run-storage.ts
|
|
16504
|
-
import { parseSixbFailure as
|
|
17296
|
+
import { parseSixbFailure as parseSixbFailure6, serializeSixbFailure as serializeSixbFailure6 } from "@sixb/core/internal/errors";
|
|
16505
17297
|
import { assertWebhookRunExecution } from "@sixb/core/internal/webhook-run-storage-provider";
|
|
16506
17298
|
import { canRetryWebhookRun, WEBHOOK_RUN_FAILURE_CODES, WebhookRunError } from "@sixb/core/storage";
|
|
16507
17299
|
class PgWebhookRunStorage {
|
|
@@ -16655,7 +17447,7 @@ function rowToWebhookRunRecord(row) {
|
|
|
16655
17447
|
requestBodySha256: row.request_body_sha256,
|
|
16656
17448
|
responseStatus: row.response_status != null ? Number(row.response_status) : undefined,
|
|
16657
17449
|
idempotencyKey: row.idempotency_key ?? undefined,
|
|
16658
|
-
error: row.error === null ? undefined :
|
|
17450
|
+
error: row.error === null ? undefined : parseSixbFailure6(row.error, WEBHOOK_RUN_FAILURE_CODES)
|
|
16659
17451
|
};
|
|
16660
17452
|
}
|
|
16661
17453
|
|
|
@@ -16719,7 +17511,7 @@ class PgWorkflowInterventionStorage {
|
|
|
16719
17511
|
SET
|
|
16720
17512
|
status = ${"submitted"},
|
|
16721
17513
|
submitted_at = ${input.submittedAt ?? new Date},
|
|
16722
|
-
submitted_by = ${
|
|
17514
|
+
submitted_by = ${serializePrincipal(input.submittedBy)}::text::jsonb,
|
|
16723
17515
|
response = ${serializeRecord(input.response)}::text::jsonb
|
|
16724
17516
|
WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
16725
17517
|
RETURNING *
|
|
@@ -16735,7 +17527,7 @@ class PgWorkflowInterventionStorage {
|
|
|
16735
17527
|
SET
|
|
16736
17528
|
status = ${"cancelled"},
|
|
16737
17529
|
cancelled_at = ${input.cancelledAt ?? new Date},
|
|
16738
|
-
cancelled_by = ${
|
|
17530
|
+
cancelled_by = ${serializePrincipal(input.cancelledBy)}::text::jsonb
|
|
16739
17531
|
WHERE project_id = ${input.projectId} AND id = ${input.id}
|
|
16740
17532
|
RETURNING *
|
|
16741
17533
|
`;
|
|
@@ -16862,10 +17654,10 @@ function serializeRecord(value) {
|
|
|
16862
17654
|
function parseRecord(value) {
|
|
16863
17655
|
return typeof value === "string" ? JSON.parse(value) : value;
|
|
16864
17656
|
}
|
|
16865
|
-
function
|
|
16866
|
-
return
|
|
17657
|
+
function serializePrincipal(principal) {
|
|
17658
|
+
return principal ? JSON.stringify(principal) : null;
|
|
16867
17659
|
}
|
|
16868
|
-
function
|
|
17660
|
+
function parsePrincipal(value) {
|
|
16869
17661
|
return typeof value === "string" ? JSON.parse(value) : value ?? undefined;
|
|
16870
17662
|
}
|
|
16871
17663
|
function rowToWorkflowInterventionRecord(row) {
|
|
@@ -16885,10 +17677,10 @@ function rowToWorkflowInterventionRecord(row) {
|
|
|
16885
17677
|
requestedAt: new Date(row.requested_at),
|
|
16886
17678
|
expiresAt: row.expires_at ? new Date(row.expires_at) : undefined,
|
|
16887
17679
|
submittedAt: row.submitted_at ? new Date(row.submitted_at) : undefined,
|
|
16888
|
-
submittedBy:
|
|
17680
|
+
submittedBy: parsePrincipal(row.submitted_by),
|
|
16889
17681
|
response: row.response ? parseRecord(row.response) : undefined,
|
|
16890
17682
|
cancelledAt: row.cancelled_at ? new Date(row.cancelled_at) : undefined,
|
|
16891
|
-
cancelledBy:
|
|
17683
|
+
cancelledBy: parsePrincipal(row.cancelled_by),
|
|
16892
17684
|
expiredAt: row.expired_at ? new Date(row.expired_at) : undefined
|
|
16893
17685
|
};
|
|
16894
17686
|
}
|
|
@@ -16899,7 +17691,7 @@ function assertNonNegativeInteger(value, fieldName) {
|
|
|
16899
17691
|
}
|
|
16900
17692
|
|
|
16901
17693
|
// src/pg-workflow-run-storage.ts
|
|
16902
|
-
import { parseSixbFailure as
|
|
17694
|
+
import { parseSixbFailure as parseSixbFailure7, serializeSixbFailure as serializeSixbFailure7 } from "@sixb/core/internal/errors";
|
|
16903
17695
|
import {
|
|
16904
17696
|
assertWorkflowAgentNodeRunExecution,
|
|
16905
17697
|
assertWorkflowRunExecution
|
|
@@ -17541,7 +18333,7 @@ function rowToWorkflowRunRecord(row) {
|
|
|
17541
18333
|
queuedAt: row.queued_at ? new Date(row.queued_at) : undefined,
|
|
17542
18334
|
startedAt: new Date(row.started_at),
|
|
17543
18335
|
finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
|
|
17544
|
-
error: row.error === null ? undefined :
|
|
18336
|
+
error: row.error === null ? undefined : parseSixbFailure7(row.error, WORKFLOW_RUN_FAILURE_CODES),
|
|
17545
18337
|
attempt: Number(row.attempt),
|
|
17546
18338
|
...row.execution_token && row.execution_queue_lease_expires_at ? {
|
|
17547
18339
|
execution: {
|
|
@@ -17566,7 +18358,7 @@ function rowToWorkflowNodeRunRecord(row) {
|
|
|
17566
18358
|
startedAt: new Date(row.started_at),
|
|
17567
18359
|
finishedAt: row.finished_at ? new Date(row.finished_at) : undefined,
|
|
17568
18360
|
output: row.output ? parseRecord2(row.output) : undefined,
|
|
17569
|
-
error: row.error === null ? undefined :
|
|
18361
|
+
error: row.error === null ? undefined : parseSixbFailure7(row.error, WORKFLOW_RUN_FAILURE_CODES)
|
|
17570
18362
|
};
|
|
17571
18363
|
}
|
|
17572
18364
|
function assertNonNegativeInteger2(value, fieldName) {
|
|
@@ -17608,7 +18400,7 @@ function rowToWorkflowAgentNodeRunRecord(row) {
|
|
|
17608
18400
|
...row.finish_reason ? { finishReason: row.finish_reason } : {},
|
|
17609
18401
|
...row.trace ? { trace: parseJson(row.trace) } : {},
|
|
17610
18402
|
...row.diagnostics ? { diagnostics: parseJson(row.diagnostics) } : {},
|
|
17611
|
-
...row.error ? { error:
|
|
18403
|
+
...row.error ? { error: parseSixbFailure7(row.error, AGENT_RUN_FAILURE_CODES3) } : {},
|
|
17612
18404
|
attempt: Number(row.attempt),
|
|
17613
18405
|
...row.execution_token && row.execution_queue_lease_expires_at ? {
|
|
17614
18406
|
execution: {
|
|
@@ -17956,6 +18748,7 @@ class PostgresStorage {
|
|
|
17956
18748
|
connectorConnections;
|
|
17957
18749
|
shareGrants;
|
|
17958
18750
|
shareSessions;
|
|
18751
|
+
fileUploadSessions;
|
|
17959
18752
|
migrators;
|
|
17960
18753
|
sql;
|
|
17961
18754
|
schemaName;
|
|
@@ -18009,6 +18802,7 @@ class PostgresStorage {
|
|
|
18009
18802
|
this.connectorConnections = createOperationScopedFacade(stores.connectorConnections, scope);
|
|
18010
18803
|
this.shareGrants = createOperationScopedFacade(stores.shareGrants, scope);
|
|
18011
18804
|
this.shareSessions = createOperationScopedFacade(stores.shareSessions, scope);
|
|
18805
|
+
this.fileUploadSessions = createOperationScopedFacade(stores.fileUploadSessions, scope);
|
|
18012
18806
|
registerPostgresStorageTestingAdapter(this, (durationMs) => stores.connectorConnections.advanceTimeForTesting(durationMs));
|
|
18013
18807
|
}
|
|
18014
18808
|
async ping() {
|
|
@@ -18103,7 +18897,8 @@ function createPostgresStores(sql, options) {
|
|
|
18103
18897
|
rules: new PgRulesStorage(sql),
|
|
18104
18898
|
connectorConnections: new PgConnectorConnectionStorage(sql),
|
|
18105
18899
|
shareGrants,
|
|
18106
|
-
shareSessions
|
|
18900
|
+
shareSessions,
|
|
18901
|
+
fileUploadSessions: new PgFileUploadSessionStorage(sql)
|
|
18107
18902
|
};
|
|
18108
18903
|
}
|
|
18109
18904
|
function resolveTimeoutMillis(value, label) {
|
|
@@ -18120,4 +18915,4 @@ export {
|
|
|
18120
18915
|
migratePostgresStorage
|
|
18121
18916
|
};
|
|
18122
18917
|
|
|
18123
|
-
//# debugId=
|
|
18918
|
+
//# debugId=F4D8409142F8F3AF64756E2164756E21
|