or3-provider-sqlite 0.0.8 → 0.0.10
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 +24 -5
- package/dist/module.json +1 -1
- package/dist/runtime/server/background-jobs/sqlite-provider.d.ts +27 -0
- package/dist/runtime/server/background-jobs/sqlite-provider.js +536 -0
- package/dist/runtime/server/db/migrate.js +13 -2
- package/dist/runtime/server/db/migrations/017_background_jobs.d.ts +4 -0
- package/dist/runtime/server/db/migrations/017_background_jobs.js +42 -0
- package/dist/runtime/server/db/migrations/018_background_admission_cancels.d.ts +7 -0
- package/dist/runtime/server/db/migrations/018_background_admission_cancels.js +18 -0
- package/dist/runtime/server/db/migrations/019_background_generation_history.d.ts +7 -0
- package/dist/runtime/server/db/migrations/019_background_generation_history.js +25 -0
- package/dist/runtime/server/db/migrations/020_background_generation_receipts.d.ts +4 -0
- package/dist/runtime/server/db/migrations/020_background_generation_receipts.js +19 -0
- package/dist/runtime/server/db/schema.d.ts +38 -0
- package/dist/runtime/server/plugins/register.js +8 -1
- package/dist/runtime/server/sync/history-gc-policy.d.ts +8 -0
- package/dist/runtime/server/sync/history-gc-policy.js +7 -0
- package/dist/runtime/server/sync/sqlite-sync-gateway-adapter.d.ts +13 -1
- package/dist/runtime/server/sync/sqlite-sync-gateway-adapter.js +669 -96
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { sql } from "kysely";
|
|
2
|
+
export async function up(db) {
|
|
3
|
+
await sql`
|
|
4
|
+
CREATE TABLE IF NOT EXISTS background_jobs (
|
|
5
|
+
id TEXT PRIMARY KEY,
|
|
6
|
+
user_id TEXT NOT NULL,
|
|
7
|
+
thread_id TEXT NOT NULL,
|
|
8
|
+
message_id TEXT NOT NULL,
|
|
9
|
+
model TEXT NOT NULL,
|
|
10
|
+
kind TEXT,
|
|
11
|
+
status TEXT NOT NULL,
|
|
12
|
+
content TEXT NOT NULL DEFAULT '',
|
|
13
|
+
chunks_received INTEGER NOT NULL DEFAULT 0,
|
|
14
|
+
started_at INTEGER NOT NULL,
|
|
15
|
+
last_activity_at INTEGER NOT NULL,
|
|
16
|
+
completed_at INTEGER,
|
|
17
|
+
error TEXT,
|
|
18
|
+
tool_calls_json TEXT,
|
|
19
|
+
workflow_state_json TEXT,
|
|
20
|
+
execution_json TEXT,
|
|
21
|
+
idempotency_key TEXT UNIQUE,
|
|
22
|
+
lease_owner TEXT,
|
|
23
|
+
lease_expires_at INTEGER,
|
|
24
|
+
attempts INTEGER NOT NULL DEFAULT 0
|
|
25
|
+
)
|
|
26
|
+
`.execute(db);
|
|
27
|
+
await sql`
|
|
28
|
+
CREATE INDEX IF NOT EXISTS background_jobs_active
|
|
29
|
+
ON background_jobs(status, last_activity_at)
|
|
30
|
+
`.execute(db);
|
|
31
|
+
await sql`
|
|
32
|
+
CREATE INDEX IF NOT EXISTS background_jobs_user_active
|
|
33
|
+
ON background_jobs(user_id, status)
|
|
34
|
+
`.execute(db);
|
|
35
|
+
await sql`
|
|
36
|
+
CREATE INDEX IF NOT EXISTS background_jobs_claim
|
|
37
|
+
ON background_jobs(status, lease_expires_at, started_at)
|
|
38
|
+
`.execute(db);
|
|
39
|
+
}
|
|
40
|
+
export async function down(db) {
|
|
41
|
+
await sql`DROP TABLE IF EXISTS background_jobs`.execute(db);
|
|
42
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Durable admission cancellations. Creation and cancellation both check this
|
|
4
|
+
* table so a Stop that arrives before the job row commits cannot launch work.
|
|
5
|
+
*/
|
|
6
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
7
|
+
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { sql } from "kysely";
|
|
2
|
+
export async function up(db) {
|
|
3
|
+
await sql`
|
|
4
|
+
CREATE TABLE IF NOT EXISTS background_admission_cancels (
|
|
5
|
+
user_id TEXT NOT NULL,
|
|
6
|
+
admission_id TEXT NOT NULL,
|
|
7
|
+
expires_at INTEGER NOT NULL,
|
|
8
|
+
PRIMARY KEY (user_id, admission_id)
|
|
9
|
+
)
|
|
10
|
+
`.execute(db);
|
|
11
|
+
await sql`
|
|
12
|
+
CREATE INDEX IF NOT EXISTS background_admission_cancels_expiry
|
|
13
|
+
ON background_admission_cancels(expires_at)
|
|
14
|
+
`.execute(db);
|
|
15
|
+
}
|
|
16
|
+
export async function down(db) {
|
|
17
|
+
await sql`DROP TABLE IF EXISTS background_admission_cancels`.execute(db);
|
|
18
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Generation identity, durable history phase, and accumulated reasoning on
|
|
4
|
+
* background jobs. Reasoning is kept distinct from request reasoning config.
|
|
5
|
+
*/
|
|
6
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
7
|
+
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { sql } from "kysely";
|
|
2
|
+
export async function up(db) {
|
|
3
|
+
await sql`
|
|
4
|
+
ALTER TABLE background_jobs
|
|
5
|
+
ADD COLUMN reasoning TEXT NOT NULL DEFAULT ''
|
|
6
|
+
`.execute(db);
|
|
7
|
+
await sql`
|
|
8
|
+
ALTER TABLE background_jobs
|
|
9
|
+
ADD COLUMN generation_id TEXT
|
|
10
|
+
`.execute(db);
|
|
11
|
+
await sql`
|
|
12
|
+
ALTER TABLE background_jobs
|
|
13
|
+
ADD COLUMN history_phase TEXT
|
|
14
|
+
`.execute(db);
|
|
15
|
+
await sql`
|
|
16
|
+
ALTER TABLE background_jobs
|
|
17
|
+
ADD COLUMN sync_provider_id TEXT
|
|
18
|
+
`.execute(db);
|
|
19
|
+
}
|
|
20
|
+
export async function down(db) {
|
|
21
|
+
await sql`ALTER TABLE background_jobs DROP COLUMN sync_provider_id`.execute(db);
|
|
22
|
+
await sql`ALTER TABLE background_jobs DROP COLUMN history_phase`.execute(db);
|
|
23
|
+
await sql`ALTER TABLE background_jobs DROP COLUMN generation_id`.execute(db);
|
|
24
|
+
await sql`ALTER TABLE background_jobs DROP COLUMN reasoning`.execute(db);
|
|
25
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { sql } from "kysely";
|
|
2
|
+
export async function up(db) {
|
|
3
|
+
await sql`
|
|
4
|
+
CREATE TABLE background_generation_receipts (
|
|
5
|
+
id TEXT PRIMARY KEY,
|
|
6
|
+
workspace_id TEXT NOT NULL,
|
|
7
|
+
generation_id TEXT NOT NULL,
|
|
8
|
+
stage TEXT NOT NULL CHECK(stage IN ('admission', 'finalization')),
|
|
9
|
+
fingerprint TEXT NOT NULL,
|
|
10
|
+
outcome TEXT NOT NULL,
|
|
11
|
+
server_version INTEGER,
|
|
12
|
+
created_at INTEGER NOT NULL,
|
|
13
|
+
UNIQUE(workspace_id, generation_id, stage)
|
|
14
|
+
)
|
|
15
|
+
`.execute(db);
|
|
16
|
+
}
|
|
17
|
+
export async function down(db) {
|
|
18
|
+
await sql`DROP TABLE IF EXISTS background_generation_receipts`.execute(db);
|
|
19
|
+
}
|
|
@@ -188,6 +188,42 @@ export interface RateLimitsTable {
|
|
|
188
188
|
window_started_at: number;
|
|
189
189
|
expires_at: number;
|
|
190
190
|
}
|
|
191
|
+
export interface BackgroundJobsTable {
|
|
192
|
+
id: string;
|
|
193
|
+
user_id: string;
|
|
194
|
+
thread_id: string;
|
|
195
|
+
message_id: string;
|
|
196
|
+
model: string;
|
|
197
|
+
kind: string | null;
|
|
198
|
+
status: 'streaming' | 'complete' | 'error' | 'aborted';
|
|
199
|
+
content: string;
|
|
200
|
+
reasoning: string;
|
|
201
|
+
generation_id: string | null;
|
|
202
|
+
history_phase: string | null;
|
|
203
|
+
sync_provider_id: string | null;
|
|
204
|
+
chunks_received: number;
|
|
205
|
+
started_at: number;
|
|
206
|
+
last_activity_at: number;
|
|
207
|
+
completed_at: number | null;
|
|
208
|
+
error: string | null;
|
|
209
|
+
tool_calls_json: string | null;
|
|
210
|
+
workflow_state_json: string | null;
|
|
211
|
+
execution_json: string | null;
|
|
212
|
+
idempotency_key: string | null;
|
|
213
|
+
lease_owner: string | null;
|
|
214
|
+
lease_expires_at: number | null;
|
|
215
|
+
attempts: number;
|
|
216
|
+
}
|
|
217
|
+
export interface BackgroundGenerationReceiptsTable {
|
|
218
|
+
id: string;
|
|
219
|
+
workspace_id: string;
|
|
220
|
+
generation_id: string;
|
|
221
|
+
stage: 'admission' | 'finalization';
|
|
222
|
+
fingerprint: string;
|
|
223
|
+
outcome: string;
|
|
224
|
+
server_version: number | null;
|
|
225
|
+
created_at: number;
|
|
226
|
+
}
|
|
191
227
|
export interface AdminUsersTable {
|
|
192
228
|
user_id: string;
|
|
193
229
|
created_at: number;
|
|
@@ -216,6 +252,8 @@ export interface Or3SqliteDb {
|
|
|
216
252
|
connect_device_authorizations: ConnectDeviceAuthorizationsTable;
|
|
217
253
|
connect_environments: ConnectEnvironmentsTable;
|
|
218
254
|
rate_limits: RateLimitsTable;
|
|
255
|
+
background_jobs: BackgroundJobsTable;
|
|
256
|
+
background_generation_receipts: BackgroundGenerationReceiptsTable;
|
|
219
257
|
s_threads: SyncedEntityTable;
|
|
220
258
|
s_messages: SyncedEntityTable;
|
|
221
259
|
s_projects: SyncedEntityTable;
|
|
@@ -6,6 +6,7 @@ import { registerSyncGatewayAdapter } from "~~/server/sync/gateway/registry";
|
|
|
6
6
|
import { registerWebhookStore } from "~~/server/utils/webhooks/store/registry";
|
|
7
7
|
import { registerConnectStore } from "~~/server/connect/store/registry";
|
|
8
8
|
import { registerRateLimitProvider } from "~~/server/utils/rate-limit/registry";
|
|
9
|
+
import { registerBackgroundJobProvider } from "~~/server/utils/background-jobs/registry";
|
|
9
10
|
import { createSqliteAuthWorkspaceStore } from "../auth/sqlite-auth-workspace-store.js";
|
|
10
11
|
import { createSqliteSyncGatewayAdapter } from "../sync/sqlite-sync-gateway-adapter.js";
|
|
11
12
|
import { createSqliteWebhookStore } from "../webhooks/sqlite-webhook-store.js";
|
|
@@ -19,6 +20,7 @@ import { createSqliteConnectStore } from "../connect/sqlite-connect-store.js";
|
|
|
19
20
|
import { getSqliteDriver, initializeSqliteDb } from "../db/kysely.js";
|
|
20
21
|
import { runMigrations } from "../db/migrate.js";
|
|
21
22
|
import { sqliteRateLimitProvider } from "../rate-limit/sqlite-provider.js";
|
|
23
|
+
import { sqliteBackgroundJobProvider } from "../background-jobs/sqlite-provider.js";
|
|
22
24
|
import { useRuntimeConfig } from "#imports";
|
|
23
25
|
const SQLITE_PROVIDER_ID = "sqlite";
|
|
24
26
|
let d1RuntimeInitialization;
|
|
@@ -27,7 +29,8 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
27
29
|
if (!config.auth?.enabled) return;
|
|
28
30
|
const syncSelected = config.sync?.enabled === true && config.sync?.provider === SQLITE_PROVIDER_ID;
|
|
29
31
|
const connectSelected = config.connect?.enabled === true && config.connect?.provider === SQLITE_PROVIDER_ID;
|
|
30
|
-
|
|
32
|
+
const backgroundJobsSelected = config.backgroundJobs?.enabled === true && config.backgroundJobs?.storageProvider === SQLITE_PROVIDER_ID;
|
|
33
|
+
if (!syncSelected && !connectSelected && !backgroundJobsSelected) return;
|
|
31
34
|
const driver = getSqliteDriver();
|
|
32
35
|
if (driver === "d1" && connectSelected) {
|
|
33
36
|
throw new Error(
|
|
@@ -40,6 +43,10 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
40
43
|
create: createSqliteAuthWorkspaceStore
|
|
41
44
|
});
|
|
42
45
|
registerRateLimitProvider(SQLITE_PROVIDER_ID, sqliteRateLimitProvider);
|
|
46
|
+
registerBackgroundJobProvider(
|
|
47
|
+
SQLITE_PROVIDER_ID,
|
|
48
|
+
sqliteBackgroundJobProvider
|
|
49
|
+
);
|
|
43
50
|
if (syncSelected) {
|
|
44
51
|
registerSyncGatewayAdapter({
|
|
45
52
|
id: SQLITE_PROVIDER_ID,
|
|
@@ -11,3 +11,11 @@ export declare const SYNC_HISTORY_GC_POLICY: Readonly<{
|
|
|
11
11
|
reason: "SQLite history GC is guarded by the verified snapshot-v1 retention contract.";
|
|
12
12
|
}>;
|
|
13
13
|
export declare function canRunSyncHistoryGc(): boolean;
|
|
14
|
+
export declare function computePullRetention(input: {
|
|
15
|
+
cursor: number;
|
|
16
|
+
oldestLogVersion: number | null;
|
|
17
|
+
highWatermark: number;
|
|
18
|
+
}): {
|
|
19
|
+
oldestRetainedVersion: number;
|
|
20
|
+
requiresSnapshot: boolean;
|
|
21
|
+
};
|
|
@@ -6,3 +6,10 @@ export const SYNC_HISTORY_GC_POLICY = Object.freeze({
|
|
|
6
6
|
export function canRunSyncHistoryGc() {
|
|
7
7
|
return SYNC_HISTORY_GC_POLICY.enabled && SYNC_HISTORY_GC_POLICY.snapshotBootstrapVerified;
|
|
8
8
|
}
|
|
9
|
+
export function computePullRetention(input) {
|
|
10
|
+
const oldestRetainedVersion = input.oldestLogVersion ?? Math.max(0, input.highWatermark) + 1;
|
|
11
|
+
return {
|
|
12
|
+
oldestRetainedVersion,
|
|
13
|
+
requiresSnapshot: oldestRetainedVersion > 0 && input.cursor < Math.max(0, oldestRetainedVersion - 1)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -7,14 +7,26 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { H3Event } from 'h3';
|
|
9
9
|
import type { CanonicalStorageQueryRequest, CanonicalStorageQueryResponse, SyncGatewayAdapter, SyncMaintenanceState, UploadIntentConsumptionRequest, UploadIntentReservationRequest } from '~~/server/sync/gateway/types';
|
|
10
|
+
import type { AdmitChatGenerationResult, CanonicalGenerationSnapshot, CanonicalHistoryActor, ChatGenerationAdmissionEnvelope, FinalizeChatGenerationResult } from '~~/shared/chat/background-history';
|
|
10
11
|
import type { PullRequest, PullResponse, PushBatch, PushResult, SnapshotRequest, SnapshotResponse } from '~~/shared/sync/types';
|
|
11
12
|
export declare class SqliteSyncGatewayAdapter implements SyncGatewayAdapter {
|
|
12
13
|
id: string;
|
|
13
|
-
|
|
14
|
+
get capabilities(): {
|
|
14
15
|
readonly snapshotBootstrap: "snapshot-v1";
|
|
15
16
|
readonly historyRetention: "snapshot-v1";
|
|
17
|
+
readonly backgroundGenerationHistory?: undefined;
|
|
18
|
+
} | {
|
|
19
|
+
readonly snapshotBootstrap: "snapshot-v1";
|
|
20
|
+
readonly historyRetention: "snapshot-v1";
|
|
21
|
+
readonly backgroundGenerationHistory: "v1";
|
|
16
22
|
};
|
|
17
23
|
private get db();
|
|
24
|
+
private assertCanonicalActor;
|
|
25
|
+
admitChatGeneration(actor: CanonicalHistoryActor, input: ChatGenerationAdmissionEnvelope): Promise<AdmitChatGenerationResult>;
|
|
26
|
+
finalizeChatGeneration(actor: CanonicalHistoryActor, input: {
|
|
27
|
+
admission: ChatGenerationAdmissionEnvelope;
|
|
28
|
+
snapshot: CanonicalGenerationSnapshot;
|
|
29
|
+
}): Promise<FinalizeChatGenerationResult>;
|
|
18
30
|
reserveUploadIntent(event: H3Event, input: UploadIntentReservationRequest): Promise<void>;
|
|
19
31
|
consumeUploadIntent(event: H3Event, input: UploadIntentConsumptionRequest): Promise<void>;
|
|
20
32
|
cancelUploadIntent(event: H3Event, input: {
|