@absurd-sqlite/bun-worker 0.2.2-alpha.2 → 0.3.0-alpha.1

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/dist/sqlite.d.ts CHANGED
@@ -1,15 +1,7 @@
1
1
  import { Database } from "bun:sqlite";
2
- import type { Queryable } from "@absurd-sqlite/sdk";
3
- import type { SQLiteRestBindParams } from "@absurd-sqlite/sdk";
4
- export declare class BunSqliteConnection implements Queryable {
5
- private readonly db;
6
- private readonly maxRetries;
7
- private readonly baseRetryDelayMs;
8
- constructor(db: Database);
9
- query<R extends object = Record<string, any>>(sql: string, params?: SQLiteRestBindParams): Promise<{
10
- rows: R[];
11
- }>;
12
- exec(sql: string, params?: SQLiteRestBindParams): Promise<void>;
13
- private runWithRetry;
2
+ import type { SQLiteConnectionOptions } from "@absurd-sqlite/sdk";
3
+ import { SQLiteConnection } from "@absurd-sqlite/sdk";
4
+ export declare class BunSqliteConnection extends SQLiteConnection {
5
+ constructor(db: Database, options?: SQLiteConnectionOptions);
14
6
  }
15
7
  //# sourceMappingURL=sqlite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAGV,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAE5B,qBAAa,mBAAoB,YAAW,SAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAK;IAChC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAM;gBAE3B,EAAE,EAAE,QAAQ;IAIlB,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAChD,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,oBAAoB,GAC5B,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC;IAiBnB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;YAWvD,YAAY;CAc3B"}
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,KAAK,EAGV,uBAAuB,EAIxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAY,MAAM,oBAAoB,CAAC;AAEhE,qBAAa,mBAAoB,SAAQ,gBAAgB;gBAC3C,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAE,uBAA4B;CAIhE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absurd-sqlite/bun-worker",
3
- "version": "0.2.2-alpha.2",
3
+ "version": "0.3.0-alpha.1",
4
4
  "description": "Bun worker utilities for Absurd-SQLite",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -39,14 +39,14 @@
39
39
  "homepage": "https://github.com/b4fun/absurd-sqlite#readme",
40
40
  "dependencies": {
41
41
  "@absurd-sqlite/sdk": "next",
42
- "absurd-sdk": "https://github.com/bcho/absurd/releases/download/sdks%2Ftypescript%2Fv0.0.7/typescript-sdk-v0.0.7.tgz",
43
- "cac": "^6.7.14"
42
+ "cac": "^6.7.14",
43
+ "temporal-polyfill": "^0.3.0"
44
44
  },
45
45
  "devDependencies": {
46
- "bun-types": "^1.3.5",
46
+ "bun-types": "^1.3.6",
47
47
  "typescript": "^5.9.3"
48
48
  },
49
49
  "engines": {
50
50
  "bun": ">=1.1.0"
51
51
  }
52
- }
52
+ }
package/src/index.ts CHANGED
@@ -1,16 +1,20 @@
1
- import { Absurd, type WorkerOptions } from "absurd-sdk";
2
1
  import { Database } from "bun:sqlite";
3
- import type { AbsurdClient } from "@absurd-sqlite/sdk";
2
+ import {
3
+ Absurd,
4
+ type AbsurdClient,
5
+ type WorkerOptions,
6
+ } from "@absurd-sqlite/sdk";
4
7
  import { cac } from "cac";
5
8
 
6
9
  import { BunSqliteConnection } from "./sqlite";
7
10
 
8
11
  export type { AbsurdClient } from "@absurd-sqlite/sdk";
9
- export type { WorkerOptions } from "absurd-sdk";
12
+ export type { WorkerOptions } from "@absurd-sqlite/sdk";
10
13
 
11
14
  export {
12
15
  downloadExtension,
13
16
  type DownloadExtensionOptions,
17
+ Temporal,
14
18
  } from "@absurd-sqlite/sdk";
15
19
 
16
20
  /**
@@ -101,12 +105,10 @@ export default async function run(setupFunction: SetupFunction): Promise<void> {
101
105
  }
102
106
 
103
107
  const db = new Database(dbPath);
104
- (db as unknown as { loadExtension(path: string): void }).loadExtension(
105
- extensionPath
106
- );
108
+ db.loadExtension(extensionPath);
107
109
 
108
110
  const conn = new BunSqliteConnection(db);
109
- const absurd = new Absurd({ db: conn });
111
+ const absurd = new Absurd(conn);
110
112
 
111
113
  await setupFunction(absurd);
112
114
 
package/src/sqlite.ts CHANGED
@@ -1,126 +1,166 @@
1
1
  import { Database } from "bun:sqlite";
2
2
 
3
- import type { Queryable } from "@absurd-sqlite/sdk";
4
3
  import type {
5
- SQLiteBindParams,
6
4
  SQLiteBindValue,
7
- SQLiteRestBindParams,
5
+ SQLiteColumnDefinition,
6
+ SQLiteConnectionOptions,
7
+ SQLiteDatabase,
8
+ SQLiteStatement,
9
+ SQLiteValueCodec,
8
10
  } from "@absurd-sqlite/sdk";
11
+ import { SQLiteConnection, Temporal } from "@absurd-sqlite/sdk";
9
12
 
10
- export class BunSqliteConnection implements Queryable {
11
- private readonly db: Database;
12
- private readonly maxRetries = 5;
13
- private readonly baseRetryDelayMs = 50;
13
+ export class BunSqliteConnection extends SQLiteConnection {
14
+ constructor(db: Database, options: SQLiteConnectionOptions = {}) {
15
+ const valueCodec = buildValueCodec(options.valueCodec);
16
+ super(new BunSqliteDatabase(db), { ...options, valueCodec });
17
+ }
18
+ }
19
+
20
+ class BunSqliteDatabase implements SQLiteDatabase {
21
+ constructor(private readonly db: Database) {}
14
22
 
15
- constructor(db: Database) {
16
- this.db = db;
23
+ prepare<Result extends object = Record<string, any>>(
24
+ sql: string
25
+ ): SQLiteStatement<Result> {
26
+ const statement = this.db.prepare(sql);
27
+ return new BunSqliteStatement(statement, isReadonlyQuery(sql));
17
28
  }
18
29
 
19
- async query<R extends object = Record<string, any>>(
20
- sql: string,
21
- params?: SQLiteRestBindParams
22
- ): Promise<{ rows: R[] }> {
23
- const { sql: sqliteQuery, paramOrder } = rewritePostgresQuery(sql);
24
- const sqliteParams = rewritePostgresParams(
25
- normalizeParams(params),
26
- paramOrder
27
- );
30
+ close(): void {
31
+ this.db.close();
32
+ }
28
33
 
29
- const statement = this.db.query(sqliteQuery);
30
- const rows = await this.runWithRetry(() =>
31
- statement.all(...sqliteParams).map((row) =>
32
- decodeRowValues(row as Record<string, unknown>)
33
- )
34
+ loadExtension(path: string): void {
35
+ (this.db as unknown as { loadExtension(path: string): void }).loadExtension(
36
+ path
34
37
  );
38
+ }
39
+ }
40
+
41
+ class BunSqliteStatement<Result extends object = Record<string, any>>
42
+ implements SQLiteStatement<Result>
43
+ {
44
+ readonly readonly: boolean;
35
45
 
36
- return { rows: rows as R[] };
46
+ constructor(
47
+ private readonly stmt: ReturnType<Database["prepare"]>,
48
+ readonlyFlag: boolean
49
+ ) {
50
+ this.readonly = readonlyFlag;
37
51
  }
38
52
 
39
- async exec(sql: string, params?: SQLiteRestBindParams): Promise<void> {
40
- const { sql: sqliteQuery, paramOrder } = rewritePostgresQuery(sql);
41
- const sqliteParams = rewritePostgresParams(
42
- normalizeParams(params),
43
- paramOrder
44
- );
53
+ columns(): SQLiteColumnDefinition[] {
54
+ const columnNames = this.stmt.columnNames ?? [];
55
+ const declaredTypes = this.stmt.declaredTypes ?? [];
56
+ return columnNames.map((name, index) => ({
57
+ name,
58
+ column: null,
59
+ table: null,
60
+ database: null,
61
+ type: normalizeColumnType(declaredTypes[index] ?? null),
62
+ }));
63
+ }
45
64
 
46
- const statement = this.db.query(sqliteQuery);
47
- await this.runWithRetry(() => statement.run(...sqliteParams));
48
- }
49
-
50
- private async runWithRetry<T>(operation: () => T): Promise<T> {
51
- let attempt = 0;
52
- while (true) {
53
- try {
54
- return operation();
55
- } catch (err) {
56
- if (!isRetryableSQLiteError(err) || attempt >= this.maxRetries) {
57
- throw err;
58
- }
59
- attempt++;
60
- await delay(this.baseRetryDelayMs * attempt);
61
- }
62
- }
65
+ all(...args: any[]): Result[] {
66
+ const normalizedArgs = normalizeStatementArgs(args);
67
+ return this.stmt.all(...normalizedArgs) as Result[];
68
+ }
69
+
70
+ run(...args: any[]): unknown {
71
+ const normalizedArgs = normalizeStatementArgs(args);
72
+ return this.stmt.run(...normalizedArgs);
63
73
  }
64
74
  }
65
75
 
66
- function rewritePostgresQuery(text: string): {
67
- sql: string;
68
- paramOrder: number[];
69
- } {
70
- const paramOrder: number[] = [];
71
- const sql = text
72
- .replace(/\$(\d+)/g, (_, index) => {
73
- paramOrder.push(Number(index));
74
- return "?";
75
- })
76
- .replace(/absurd\.(\w+)/g, "absurd_$1");
77
-
78
- return { sql, paramOrder };
76
+ function buildValueCodec(
77
+ overrides?: SQLiteValueCodec
78
+ ): SQLiteValueCodec {
79
+ return {
80
+ encodeParam: overrides?.encodeParam ?? encodeColumnValue,
81
+ decodeColumn: overrides?.decodeColumn ?? decodeColumnValue,
82
+ decodeRow: overrides?.decodeRow ?? decodeRowValues,
83
+ };
79
84
  }
80
85
 
81
- function rewritePostgresParams<I = any>(
82
- params: SQLiteBindValue[],
83
- paramOrder: number[]
84
- ): I[] {
85
- if (paramOrder.length === 0) {
86
- return params.map((value) => encodeColumnValue(value)) as I[];
86
+ function normalizeStatementArgs(args: any[]): any[] {
87
+ if (args.length !== 1) {
88
+ return args;
89
+ }
90
+ const params = args[0];
91
+ if (!params || typeof params !== "object" || Array.isArray(params)) {
92
+ return args;
93
+ }
94
+ const normalized: Record<string, unknown> = {};
95
+ for (const [key, value] of Object.entries(params)) {
96
+ normalized[normalizeParamKey(key)] = value;
87
97
  }
98
+ return [normalized];
99
+ }
88
100
 
89
- return paramOrder.map((index) => {
90
- const value = params[index - 1];
91
- return encodeColumnValue(value) as I;
92
- });
101
+ function normalizeParamKey(key: string): string {
102
+ if (key.startsWith("$") || key.startsWith(":") || key.startsWith("@")) {
103
+ return key;
104
+ }
105
+ return `:${key}`;
93
106
  }
94
107
 
95
- function decodeRowValues<R extends object = any>(
96
- row: Record<string, unknown>
97
- ): R {
108
+ function decodeRowValues<R extends object = any>(args: {
109
+ row: Record<string, unknown>;
110
+ columns?: SQLiteColumnDefinition[];
111
+ decodeColumn?: (args: {
112
+ value: unknown;
113
+ columnName: string;
114
+ columnType: string | null;
115
+ }) => unknown;
116
+ }): R {
98
117
  const decodedRow: any = {};
99
- for (const [columnName, rawValue] of Object.entries(row)) {
100
- decodedRow[columnName] = decodeColumnValue(rawValue, columnName);
118
+ if (args.columns && args.decodeColumn) {
119
+ for (const column of args.columns) {
120
+ const columnName = column.name;
121
+ const rawValue = args.row[columnName];
122
+ decodedRow[columnName] = args.decodeColumn({
123
+ value: rawValue,
124
+ columnName,
125
+ columnType: column.type,
126
+ });
127
+ }
128
+ return decodedRow as R;
129
+ }
130
+
131
+ for (const [columnName, rawValue] of Object.entries(args.row)) {
132
+ decodedRow[columnName] = decodeColumnValue({
133
+ value: rawValue,
134
+ columnName,
135
+ columnType: null,
136
+ });
101
137
  }
102
138
 
103
139
  return decodedRow as R;
104
140
  }
105
141
 
106
- function decodeColumnValue<V = any>(
107
- value: unknown | V,
108
- columnName: string
109
- ): V | null {
142
+ function decodeColumnValue<V = any>(args: {
143
+ value: unknown | V;
144
+ columnName: string;
145
+ columnType: string | null;
146
+ verbose?: (...args: any[]) => void;
147
+ }): V | null {
148
+ const { value, columnName, columnType } = args;
110
149
  if (value === null || value === undefined) {
111
150
  return null;
112
151
  }
113
152
 
114
- if (isTimestampColumn(columnName)) {
115
- if (typeof value === "number") {
116
- return new Date(value) as V;
117
- }
153
+ const isDateTime = columnType === "datetime" || isTimestampColumn(columnName);
154
+ if (isDateTime) {
118
155
  if (typeof value === "string") {
119
- const parsed = Date.parse(value);
120
- if (!Number.isNaN(parsed)) {
121
- return new Date(parsed) as V;
122
- }
156
+ return Temporal.Instant.from(value) as V;
157
+ }
158
+ if (typeof value === "number") {
159
+ return Temporal.Instant.fromEpochMilliseconds(value) as V;
123
160
  }
161
+ throw new Error(
162
+ `Expected datetime column ${columnName} to be a string or number, got ${typeof value}`
163
+ );
124
164
  }
125
165
 
126
166
  if (typeof value === "string") {
@@ -128,8 +168,7 @@ function decodeColumnValue<V = any>(
128
168
  }
129
169
 
130
170
  if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
131
- const bytes =
132
- value instanceof Uint8Array ? value : new Uint8Array(value);
171
+ const bytes = value instanceof Uint8Array ? value : new Uint8Array(value);
133
172
  const decoded = new TextDecoder().decode(bytes);
134
173
  return tryDecodeJson(decoded) ?? (value as V);
135
174
  }
@@ -145,7 +184,13 @@ function tryDecodeJson<V = any>(value: string): V | null {
145
184
  }
146
185
  }
147
186
 
148
- function encodeColumnValue(value: any): any {
187
+ function encodeColumnValue(value: SQLiteBindValue): SQLiteBindValue {
188
+ if (value instanceof Temporal.Instant) {
189
+ return value.toString();
190
+ }
191
+ if (value instanceof Temporal.Duration) {
192
+ return value.toString();
193
+ }
149
194
  if (value instanceof Date) {
150
195
  return value.toISOString();
151
196
  }
@@ -159,60 +204,23 @@ function isTimestampColumn(columnName: string): boolean {
159
204
  return columnName.endsWith("_at");
160
205
  }
161
206
 
162
- function normalizeParams(
163
- params?: SQLiteRestBindParams
164
- ): SQLiteBindValue[] {
165
- if (!params) {
166
- return [];
167
- }
168
-
169
- if (params.length === 1 && isBindParams(params[0])) {
170
- const inner = params[0];
171
- if (Array.isArray(inner)) {
172
- return inner;
173
- }
174
- return Object.values(inner);
175
- }
176
-
177
- return params as SQLiteBindValue[];
178
- }
179
-
180
- function isBindParams(value: unknown): value is SQLiteBindParams {
181
- if (Array.isArray(value)) {
182
- return true;
183
- }
184
- if (!value || typeof value !== "object") {
185
- return false;
186
- }
187
- const tag = Object.prototype.toString.call(value);
188
- return tag === "[object Object]";
207
+ function isReadonlyQuery(sql: string): boolean {
208
+ const trimmed = sql.trim().toLowerCase();
209
+ return (
210
+ trimmed.startsWith("select") ||
211
+ trimmed.startsWith("with") ||
212
+ trimmed.startsWith("pragma") ||
213
+ trimmed.startsWith("explain")
214
+ );
189
215
  }
190
216
 
191
- const sqliteRetryableErrorCodes = new Set(["SQLITE_BUSY", "SQLITE_LOCKED"]);
192
- const sqliteRetryableErrnos = new Set([5, 6]);
193
-
194
- function isRetryableSQLiteError(err: unknown): boolean {
195
- if (!err || typeof err !== "object") {
196
- return false;
197
- }
198
-
199
- const code = (err as any).code;
200
- if (typeof code === "string") {
201
- for (const retryableCode of sqliteRetryableErrorCodes) {
202
- if (code.startsWith(retryableCode)) {
203
- return true;
204
- }
205
- }
217
+ function normalizeColumnType(value: string | null): string | null {
218
+ if (!value) {
219
+ return null;
206
220
  }
207
-
208
- const errno = (err as any).errno;
209
- if (typeof errno === "number" && sqliteRetryableErrnos.has(errno)) {
210
- return true;
221
+ const lowered = value.toLowerCase();
222
+ if (lowered === "null") {
223
+ return null;
211
224
  }
212
-
213
- return false;
214
- }
215
-
216
- function delay(ms: number): Promise<void> {
217
- return new Promise((resolve) => setTimeout(resolve, ms));
225
+ return lowered;
218
226
  }
@@ -7,7 +7,7 @@ import {
7
7
  jest,
8
8
  } from "bun:test";
9
9
  import assert from "node:assert/strict";
10
- import type { Absurd } from "absurd-sdk";
10
+ import { Temporal, type Absurd } from "@absurd-sqlite/sdk";
11
11
  import { createTestAbsurd, randomName, type TestContext } from "./setup";
12
12
  import { EventEmitter, once } from "events";
13
13
  import { waitFor } from "./wait-for";
@@ -171,7 +171,7 @@ describe("Basic SDK Operations", () => {
171
171
  const scheduledRun = await ctx.getRun(runID);
172
172
  expect(scheduledRun).toMatchObject({
173
173
  state: "sleeping",
174
- available_at: wakeAt,
174
+ available_at: Temporal.Instant.fromEpochMilliseconds(wakeAt.getTime()),
175
175
  wake_event: null,
176
176
  });
177
177
 
@@ -189,7 +189,7 @@ describe("Basic SDK Operations", () => {
189
189
  const resumedRun = await ctx.getRun(runID);
190
190
  expect(resumedRun).toMatchObject({
191
191
  state: "running",
192
- started_at: wakeAt,
192
+ started_at: Temporal.Instant.fromEpochMilliseconds(wakeAt.getTime()),
193
193
  });
194
194
  });
195
195
 
@@ -216,7 +216,9 @@ describe("Basic SDK Operations", () => {
216
216
  expect(running).toMatchObject({
217
217
  state: "running",
218
218
  claimed_by: "worker-a",
219
- claim_expires_at: new Date(baseTime.getTime() + 30 * 1000),
219
+ claim_expires_at: Temporal.Instant.fromEpochMilliseconds(
220
+ baseTime.getTime() + 30 * 1000,
221
+ ),
220
222
  });
221
223
 
222
224
  await ctx.setFakeNow(new Date(baseTime.getTime() + 5 * 60 * 1000));
@@ -275,7 +277,9 @@ describe("Basic SDK Operations", () => {
275
277
  const runRow = await ctx.getRun(runID);
276
278
  expect(runRow).toMatchObject({
277
279
  claimed_by: "worker-clean",
278
- claim_expires_at: new Date(base.getTime() + 60 * 1000),
280
+ claim_expires_at: Temporal.Instant.fromEpochMilliseconds(
281
+ base.getTime() + 60 * 1000,
282
+ ),
279
283
  });
280
284
 
281
285
  const beforeTTL = new Date(finishTime.getTime() + 30 * 60 * 1000);
@@ -482,7 +486,9 @@ describe("Basic SDK Operations", () => {
482
486
 
483
487
  const getExpiresAt = async (runID: string) => {
484
488
  const run = await ctx.getRun(runID);
485
- return run?.claim_expires_at ? run.claim_expires_at.getTime() : 0;
489
+ return run?.claim_expires_at
490
+ ? run.claim_expires_at.epochMilliseconds
491
+ : 0;
486
492
  };
487
493
 
488
494
  absurd.workBatch("test-worker", claimTimeout);
@@ -1,7 +1,7 @@
1
1
  import { describe, test, expect, beforeAll, afterEach } from "bun:test";
2
- import type { Absurd } from "absurd-sdk";
2
+ import { Temporal, type Absurd } from "@absurd-sqlite/sdk";
3
3
  import { createTestAbsurd, randomName, type TestContext } from "./setup";
4
- import { TimeoutError } from "absurd-sdk";
4
+ import { TimeoutError } from "@absurd-sqlite/sdk";
5
5
 
6
6
  describe("Event system", () => {
7
7
  let ctx: TestContext;
@@ -21,7 +21,9 @@ describe("Event system", () => {
21
21
  const eventName = randomName("test_event");
22
22
 
23
23
  absurd.registerTask({ name: "waiter" }, async (params, ctx) => {
24
- const payload = await ctx.awaitEvent(eventName, { timeout: 60 });
24
+ const payload = await ctx.awaitEvent(eventName, {
25
+ timeout: Temporal.Duration.from({ seconds: 60 }),
26
+ });
25
27
  return { received: payload };
26
28
  });
27
29
 
@@ -86,7 +88,7 @@ describe("Event system", () => {
86
88
  absurd.registerTask({ name: "timeout-waiter" }, async (_params, ctx) => {
87
89
  try {
88
90
  const payload = await ctx.awaitEvent(eventName, {
89
- timeout: timeoutSeconds,
91
+ timeout: Temporal.Duration.from({ seconds: timeoutSeconds }),
90
92
  });
91
93
  return { timedOut: false, result: payload };
92
94
  } catch (err) {
@@ -109,7 +111,9 @@ describe("Event system", () => {
109
111
  wake_event: eventName,
110
112
  });
111
113
  const expectedWake = new Date(baseTime.getTime() + timeoutSeconds * 1000);
112
- expect(sleepingRun?.available_at?.getTime()).toBe(expectedWake.getTime());
114
+ expect(sleepingRun?.available_at?.epochMilliseconds).toBe(
115
+ expectedWake.getTime(),
116
+ );
113
117
 
114
118
  await ctx.setFakeNow(new Date(expectedWake.getTime() + 1000));
115
119
  await absurd.workBatch("worker1", 120, 1);
@@ -170,13 +174,16 @@ describe("Event system", () => {
170
174
 
171
175
  absurd.registerTask({ name: "timeout-no-loop" }, async (_params, ctx) => {
172
176
  try {
173
- await ctx.awaitEvent(eventName, { stepName: "wait", timeout: 10 });
177
+ await ctx.awaitEvent(eventName, {
178
+ stepName: "wait",
179
+ timeout: Temporal.Duration.from({ seconds: 10 }),
180
+ });
174
181
  return { stage: "unexpected" };
175
182
  } catch (err) {
176
183
  if (err instanceof TimeoutError) {
177
184
  const payload = await ctx.awaitEvent(eventName, {
178
185
  stepName: "wait",
179
- timeout: 10,
186
+ timeout: Temporal.Duration.from({ seconds: 10 }),
180
187
  });
181
188
  return { stage: "resumed", payload };
182
189
  }
@@ -1,6 +1,6 @@
1
1
  import { describe, test, expect, beforeAll, afterEach } from "bun:test";
2
2
  import { AsyncLocalStorage } from "node:async_hooks";
3
- import type { Absurd, SpawnOptions } from "absurd-sdk";
3
+ import type { Absurd, SpawnOptions } from "@absurd-sqlite/sdk";
4
4
  import { createTestAbsurd, randomName, type TestContext } from "./setup";
5
5
 
6
6
  describe("Hooks", () => {
@@ -1,5 +1,5 @@
1
1
  import { describe, test, expect, beforeAll, afterEach } from "bun:test";
2
- import type { Absurd } from "absurd-sdk";
2
+ import type { Absurd } from "@absurd-sqlite/sdk";
3
3
  import { createTestAbsurd, randomName, type TestContext } from "./setup";
4
4
 
5
5
  describe("Idempotent Task Spawning", () => {
@@ -3,7 +3,7 @@ import { mkdtempSync, rmSync } from "node:fs";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { afterEach, describe, expect, it } from "bun:test";
6
- import { Absurd } from "absurd-sdk";
6
+ import { Absurd } from "@absurd-sqlite/sdk";
7
7
 
8
8
  import { BunSqliteConnection } from "../src/sqlite";
9
9
  import { loadExtension } from "./setup";
@@ -29,7 +29,7 @@ describe("Absurd", () => {
29
29
  it("creates and lists queues using the sqlite extension", async () => {
30
30
  const db = createDatabaseWithMigrations();
31
31
  const conn = new BunSqliteConnection(db);
32
- const absurd = new Absurd({ db: conn });
32
+ const absurd = new Absurd(conn);
33
33
 
34
34
  await absurd.createQueue("alpha");
35
35
  await absurd.createQueue("beta");
@@ -52,7 +52,7 @@ describe("Absurd", () => {
52
52
  it("closes workers without affecting the sqlite database", async () => {
53
53
  const db = createDatabaseWithMigrations();
54
54
  const conn = new BunSqliteConnection(db);
55
- const absurd = new Absurd({ db: conn });
55
+ const absurd = new Absurd(conn);
56
56
 
57
57
  await absurd.close();
58
58
 
@@ -1,5 +1,5 @@
1
1
  import { describe, test, expect, beforeAll, afterEach } from "bun:test";
2
- import type { Absurd } from "absurd-sdk";
2
+ import { Temporal, type Absurd } from "@absurd-sqlite/sdk";
3
3
  import { createTestAbsurd, randomName, type TestContext } from "./setup";
4
4
 
5
5
  describe("Retry and cancellation", () => {
@@ -159,7 +159,7 @@ describe("Retry and cancellation", () => {
159
159
  const { taskID } = await absurd.spawn("duration-cancel", undefined, {
160
160
  maxAttempts: 4,
161
161
  retryStrategy: { kind: "fixed", baseSeconds: 30 },
162
- cancellation: { maxDuration: 90 },
162
+ cancellation: { maxDuration: Temporal.Duration.from({ seconds: 90 }) },
163
163
  });
164
164
 
165
165
  await absurd.workBatch("worker1", 60, 1);
@@ -185,7 +185,7 @@ describe("Retry and cancellation", () => {
185
185
  });
186
186
 
187
187
  const { taskID } = await absurd.spawn("delay-cancel", undefined, {
188
- cancellation: { maxDelay: 60 },
188
+ cancellation: { maxDelay: Temporal.Duration.from({ seconds: 60 }) },
189
189
  });
190
190
 
191
191
  await ctx.setFakeNow(new Date(baseTime.getTime() + 61 * 1000));
@@ -312,8 +312,8 @@ describe("Retry and cancellation", () => {
312
312
 
313
313
  await absurd.cancelTask(taskID);
314
314
  const second = await ctx.getTask(taskID);
315
- expect(second?.cancelled_at?.getTime()).toBe(
316
- first?.cancelled_at?.getTime(),
315
+ expect(second?.cancelled_at?.epochMilliseconds).toBe(
316
+ first?.cancelled_at?.epochMilliseconds,
317
317
  );
318
318
  });
319
319