cooper-stack 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai.d.ts +60 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +66 -0
- package/dist/ai.js.map +1 -0
- package/dist/api.d.ts +31 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +40 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +13 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +16 -0
- package/dist/auth.js.map +1 -0
- package/dist/bridge.d.ts +15 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +217 -0
- package/dist/bridge.js.map +1 -0
- package/dist/cache.d.ts +27 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +69 -0
- package/dist/cache.js.map +1 -0
- package/dist/cron.d.ts +22 -0
- package/dist/cron.d.ts.map +1 -0
- package/dist/cron.js +26 -0
- package/dist/cron.js.map +1 -0
- package/dist/db.d.ts +30 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +75 -0
- package/dist/db.js.map +1 -0
- package/dist/error.d.ts +16 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +28 -0
- package/dist/error.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/islands.d.ts +16 -0
- package/dist/islands.d.ts.map +1 -0
- package/dist/islands.js +23 -0
- package/dist/islands.js.map +1 -0
- package/dist/middleware.d.ts +20 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +26 -0
- package/dist/middleware.js.map +1 -0
- package/dist/pubsub.d.ts +24 -0
- package/dist/pubsub.d.ts.map +1 -0
- package/dist/pubsub.js +48 -0
- package/dist/pubsub.js.map +1 -0
- package/dist/queue.d.ts +36 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +100 -0
- package/dist/queue.js.map +1 -0
- package/dist/registry.d.ts +75 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +41 -0
- package/dist/registry.js.map +1 -0
- package/dist/secrets.d.ts +10 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +35 -0
- package/dist/secrets.js.map +1 -0
- package/dist/ssr.d.ts +53 -0
- package/dist/ssr.d.ts.map +1 -0
- package/dist/ssr.js +39 -0
- package/dist/ssr.js.map +1 -0
- package/dist/storage.d.ts +28 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +61 -0
- package/dist/storage.js.map +1 -0
- package/package.json +38 -0
- package/src/ai.ts +99 -0
- package/src/api.ts +56 -0
- package/src/auth.ts +16 -0
- package/src/bridge.ts +267 -0
- package/src/cache.ts +86 -0
- package/src/cron.ts +32 -0
- package/src/db.ts +109 -0
- package/src/error.ts +42 -0
- package/src/index.ts +15 -0
- package/src/islands.ts +28 -0
- package/src/middleware.ts +27 -0
- package/src/pubsub.ts +69 -0
- package/src/queue.ts +133 -0
- package/src/registry.ts +98 -0
- package/src/secrets.ts +40 -0
- package/src/ssr.ts +58 -0
- package/src/storage.ts +79 -0
- package/tsconfig.json +17 -0
package/dist/cron.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { registry } from "./registry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Declare a cron job.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* export const cleanup = cron("cleanup", {
|
|
7
|
+
* schedule: "every 1 hour",
|
|
8
|
+
* handler: async () => {
|
|
9
|
+
* await db.query("DELETE FROM sessions WHERE expires_at < NOW()");
|
|
10
|
+
* },
|
|
11
|
+
* });
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export function cron(name, config) {
|
|
15
|
+
registry.registerCron(name, {
|
|
16
|
+
name,
|
|
17
|
+
schedule: config.schedule,
|
|
18
|
+
handler: config.handler,
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
_cooper_type: "cron",
|
|
22
|
+
name,
|
|
23
|
+
schedule: config.schedule,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=cron.js.map
|
package/dist/cron.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.js","sourceRoot":"","sources":["../src/cron.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAOzC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,MAAkB;IACnD,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE;QAC1B,IAAI;QACJ,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;IAEH,OAAO;QACL,YAAY,EAAE,MAAe;QAC7B,IAAI;QACJ,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC;AACJ,CAAC"}
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface DatabaseConfig {
|
|
2
|
+
engine?: "postgres" | "mysql" | "mongodb" | "dynamodb";
|
|
3
|
+
migrations?: string;
|
|
4
|
+
partitionKey?: string;
|
|
5
|
+
sortKey?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DatabaseClient {
|
|
8
|
+
/** Run a query returning multiple rows */
|
|
9
|
+
query<T = any>(sql: string, params?: any[]): Promise<T[]>;
|
|
10
|
+
/** Run a query returning a single row or null */
|
|
11
|
+
queryRow<T = any>(sql: string, params?: any[]): Promise<T | null>;
|
|
12
|
+
/** Run a query returning affected row count */
|
|
13
|
+
exec(sql: string, params?: any[]): Promise<{
|
|
14
|
+
rowCount: number;
|
|
15
|
+
}>;
|
|
16
|
+
/** Insert and return the inserted row */
|
|
17
|
+
insert<T = any>(table: string, data: Record<string, any>): Promise<T>;
|
|
18
|
+
/** Access the underlying connection pool (for ORMs like Drizzle) */
|
|
19
|
+
pool: any;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Declare a database.
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* export const db = database("main", { migrations: "./migrations" });
|
|
26
|
+
* const user = await db.queryRow<User>("SELECT * FROM users WHERE id = $1", [id]);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function database(name: string, config?: DatabaseConfig): DatabaseClient;
|
|
30
|
+
//# sourceMappingURL=db.d.ts.map
|
package/dist/db.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAC1D,iDAAiD;IACjD,QAAQ,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAClE,+CAA+C;IAC/C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,yCAAyC;IACzC,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtE,oEAAoE;IACpE,IAAI,EAAE,GAAG,CAAC;CACX;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,cAAc,CA8E9E"}
|
package/dist/db.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { registry } from "./registry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Declare a database.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* export const db = database("main", { migrations: "./migrations" });
|
|
7
|
+
* const user = await db.queryRow<User>("SELECT * FROM users WHERE id = $1", [id]);
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export function database(name, config) {
|
|
11
|
+
const engine = config?.engine ?? "postgres";
|
|
12
|
+
// Connection details injected by the Rust runtime via env vars
|
|
13
|
+
const connStr = process.env[`COOPER_DB_${name.toUpperCase()}_URL`]
|
|
14
|
+
?? `postgres://cooper:cooper@localhost:5432/cooper_${name}`;
|
|
15
|
+
let pool = null;
|
|
16
|
+
const ensurePool = async () => {
|
|
17
|
+
if (pool)
|
|
18
|
+
return pool;
|
|
19
|
+
if (engine === "postgres") {
|
|
20
|
+
const pg = await import("pg");
|
|
21
|
+
pool = new pg.default.Pool({ connectionString: connStr });
|
|
22
|
+
return pool;
|
|
23
|
+
}
|
|
24
|
+
if (engine === "mysql") {
|
|
25
|
+
const mysql = await import("mysql2/promise");
|
|
26
|
+
pool = await mysql.createPool(connStr);
|
|
27
|
+
return pool;
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`Database engine "${engine}" not yet supported in JS runtime`);
|
|
30
|
+
};
|
|
31
|
+
const client = {
|
|
32
|
+
async query(sql, params) {
|
|
33
|
+
const p = await ensurePool();
|
|
34
|
+
if (engine === "postgres") {
|
|
35
|
+
const res = await p.query(sql, params);
|
|
36
|
+
return res.rows;
|
|
37
|
+
}
|
|
38
|
+
if (engine === "mysql") {
|
|
39
|
+
const [rows] = await p.execute(sql, params);
|
|
40
|
+
return rows;
|
|
41
|
+
}
|
|
42
|
+
return [];
|
|
43
|
+
},
|
|
44
|
+
async queryRow(sql, params) {
|
|
45
|
+
const rows = await client.query(sql, params);
|
|
46
|
+
return rows[0] ?? null;
|
|
47
|
+
},
|
|
48
|
+
async exec(sql, params) {
|
|
49
|
+
const p = await ensurePool();
|
|
50
|
+
if (engine === "postgres") {
|
|
51
|
+
const res = await p.query(sql, params);
|
|
52
|
+
return { rowCount: res.rowCount ?? 0 };
|
|
53
|
+
}
|
|
54
|
+
if (engine === "mysql") {
|
|
55
|
+
const [result] = await p.execute(sql, params);
|
|
56
|
+
return { rowCount: result.affectedRows ?? 0 };
|
|
57
|
+
}
|
|
58
|
+
return { rowCount: 0 };
|
|
59
|
+
},
|
|
60
|
+
async insert(table, data) {
|
|
61
|
+
const keys = Object.keys(data);
|
|
62
|
+
const values = Object.values(data);
|
|
63
|
+
const placeholders = keys.map((_, i) => engine === "postgres" ? `$${i + 1}` : "?");
|
|
64
|
+
const sql = `INSERT INTO ${table} (${keys.join(", ")}) VALUES (${placeholders.join(", ")}) RETURNING *`;
|
|
65
|
+
const row = await client.queryRow(sql, values);
|
|
66
|
+
return row;
|
|
67
|
+
},
|
|
68
|
+
get pool() {
|
|
69
|
+
return pool;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
registry.registerDatabase(name, { name, engine, pool: client });
|
|
73
|
+
return client;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=db.js.map
|
package/dist/db.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error codes with automatic HTTP status mapping.
|
|
3
|
+
*/
|
|
4
|
+
export type ErrorCode = "NOT_FOUND" | "UNAUTHORIZED" | "PERMISSION_DENIED" | "RATE_LIMITED" | "INVALID_ARGUMENT" | "VALIDATION_FAILED" | "INTERNAL";
|
|
5
|
+
export declare class CooperError extends Error {
|
|
6
|
+
readonly code: ErrorCode;
|
|
7
|
+
readonly statusCode: number;
|
|
8
|
+
constructor(code: ErrorCode, message: string);
|
|
9
|
+
toJSON(): {
|
|
10
|
+
error: {
|
|
11
|
+
code: ErrorCode;
|
|
12
|
+
message: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB,WAAW,GACX,cAAc,GACd,mBAAmB,GACnB,cAAc,GACd,kBAAkB,GAClB,mBAAmB,GACnB,UAAU,CAAC;AAYf,qBAAa,WAAY,SAAQ,KAAK;IACpC,SAAgB,IAAI,EAAE,SAAS,CAAC;IAChC,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM;IAO5C,MAAM;;;;;;CAQP"}
|
package/dist/error.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const STATUS_MAP = {
|
|
2
|
+
NOT_FOUND: 404,
|
|
3
|
+
UNAUTHORIZED: 401,
|
|
4
|
+
PERMISSION_DENIED: 403,
|
|
5
|
+
RATE_LIMITED: 429,
|
|
6
|
+
INVALID_ARGUMENT: 400,
|
|
7
|
+
VALIDATION_FAILED: 422,
|
|
8
|
+
INTERNAL: 500,
|
|
9
|
+
};
|
|
10
|
+
export class CooperError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
statusCode;
|
|
13
|
+
constructor(code, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "CooperError";
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.statusCode = STATUS_MAP[code] ?? 500;
|
|
18
|
+
}
|
|
19
|
+
toJSON() {
|
|
20
|
+
return {
|
|
21
|
+
error: {
|
|
22
|
+
code: this.code,
|
|
23
|
+
message: this.message,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,GAA8B;IAC5C,SAAS,EAAE,GAAG;IACd,YAAY,EAAE,GAAG;IACjB,iBAAiB,EAAE,GAAG;IACtB,YAAY,EAAE,GAAG;IACjB,gBAAgB,EAAE,GAAG;IACrB,iBAAiB,EAAE,GAAG;IACtB,QAAQ,EAAE,GAAG;CACd,CAAC;AAEF,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpB,IAAI,CAAY;IAChB,UAAU,CAAS;IAEnC,YAAY,IAAe,EAAE,OAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;IAC5C,CAAC;IAED,MAAM;QACJ,OAAO;YACL,KAAK,EAAE;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB;SACF,CAAC;IACJ,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { api } from "./api.js";
|
|
2
|
+
export { CooperError, type ErrorCode } from "./error.js";
|
|
3
|
+
export { database, type DatabaseClient } from "./db.js";
|
|
4
|
+
export { middleware, cooper } from "./middleware.js";
|
|
5
|
+
export { authHandler } from "./auth.js";
|
|
6
|
+
export { topic, type Topic } from "./pubsub.js";
|
|
7
|
+
export { cron } from "./cron.js";
|
|
8
|
+
export { cache, type CacheClient } from "./cache.js";
|
|
9
|
+
export { bucket, type BucketClient } from "./storage.js";
|
|
10
|
+
export { secret } from "./secrets.js";
|
|
11
|
+
export { queue, type QueueClient } from "./queue.js";
|
|
12
|
+
export { page, layout, pageLoader, Suspense } from "./ssr.js";
|
|
13
|
+
export { island } from "./islands.js";
|
|
14
|
+
export { vectorStore, llmGateway } from "./ai.js";
|
|
15
|
+
export { registry } from "./registry.js";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { api } from "./api.js";
|
|
2
|
+
export { CooperError } from "./error.js";
|
|
3
|
+
export { database } from "./db.js";
|
|
4
|
+
export { middleware, cooper } from "./middleware.js";
|
|
5
|
+
export { authHandler } from "./auth.js";
|
|
6
|
+
export { topic } from "./pubsub.js";
|
|
7
|
+
export { cron } from "./cron.js";
|
|
8
|
+
export { cache } from "./cache.js";
|
|
9
|
+
export { bucket } from "./storage.js";
|
|
10
|
+
export { secret } from "./secrets.js";
|
|
11
|
+
export { queue } from "./queue.js";
|
|
12
|
+
export { page, layout, pageLoader, Suspense } from "./ssr.js";
|
|
13
|
+
export { island } from "./islands.js";
|
|
14
|
+
export { vectorStore, llmGateway } from "./ai.js";
|
|
15
|
+
export { registry } from "./registry.js";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAuB,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,KAAK,EAAc,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAoB,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,MAAM,EAAqB,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,KAAK,EAAoB,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type HydrationStrategy = "load" | "visible" | "idle" | "interaction" | "none";
|
|
2
|
+
/**
|
|
3
|
+
* Mark a component as an island — it will be hydrated on the client.
|
|
4
|
+
*
|
|
5
|
+
* ```tsx
|
|
6
|
+
* // islands/LikeButton.island.tsx
|
|
7
|
+
* export default island(function LikeButton({ userId, initialCount }) {
|
|
8
|
+
* const [count, setCount] = useState(initialCount);
|
|
9
|
+
* return <button onClick={...}>Like ({count})</button>;
|
|
10
|
+
* });
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function island<P = any>(component: (props: P) => any): (props: P & {
|
|
14
|
+
hydrate?: HydrationStrategy;
|
|
15
|
+
}) => any;
|
|
16
|
+
//# sourceMappingURL=islands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"islands.d.ts","sourceRoot":"","sources":["../src/islands.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;AAErF;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,CAAC,GAAG,GAAG,EAC5B,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,GAAG,GAC3B,CAAC,KAAK,EAAE,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAAE,KAAK,GAAG,CAYrD"}
|
package/dist/islands.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mark a component as an island — it will be hydrated on the client.
|
|
3
|
+
*
|
|
4
|
+
* ```tsx
|
|
5
|
+
* // islands/LikeButton.island.tsx
|
|
6
|
+
* export default island(function LikeButton({ userId, initialCount }) {
|
|
7
|
+
* const [count, setCount] = useState(initialCount);
|
|
8
|
+
* return <button onClick={...}>Like ({count})</button>;
|
|
9
|
+
* });
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export function island(component) {
|
|
13
|
+
// Mark the component for the bundler
|
|
14
|
+
const wrapper = (props) => {
|
|
15
|
+
// Server-side: render the component to HTML
|
|
16
|
+
// Client-side: hydrate based on strategy
|
|
17
|
+
return component(props);
|
|
18
|
+
};
|
|
19
|
+
wrapper._cooper_island = true;
|
|
20
|
+
wrapper._cooper_hydrate = "load"; // default strategy
|
|
21
|
+
return wrapper;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=islands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"islands.js","sourceRoot":"","sources":["../src/islands.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,MAAM,CACpB,SAA4B;IAE5B,qCAAqC;IACrC,MAAM,OAAO,GAAG,CAAC,KAA0C,EAAE,EAAE;QAC7D,4CAA4C;QAC5C,yCAAyC;QACzC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC;IAED,OAAe,CAAC,cAAc,GAAG,IAAI,CAAC;IACtC,OAAe,CAAC,eAAe,GAAG,MAAM,CAAC,CAAC,mBAAmB;IAE9D,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type MiddlewareFn } from "./registry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Define a middleware function.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* const rateLimiter = middleware(async (req, next) => {
|
|
7
|
+
* const count = await userCache.increment(`rate:${req.ip}`, { ttl: "1m" });
|
|
8
|
+
* if (count > 100) throw new CooperError("RATE_LIMITED");
|
|
9
|
+
* return next(req);
|
|
10
|
+
* });
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function middleware(fn: MiddlewareFn): MiddlewareFn;
|
|
14
|
+
/**
|
|
15
|
+
* Cooper instance for global middleware registration.
|
|
16
|
+
*/
|
|
17
|
+
export declare const cooper: {
|
|
18
|
+
use(...middlewares: MiddlewareFn[]): void;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,YAAY,GAAG,YAAY,CAEzD;AAED;;GAEG;AACH,eAAO,MAAM,MAAM;wBACG,YAAY,EAAE;CAKnC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { registry } from "./registry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Define a middleware function.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* const rateLimiter = middleware(async (req, next) => {
|
|
7
|
+
* const count = await userCache.increment(`rate:${req.ip}`, { ttl: "1m" });
|
|
8
|
+
* if (count > 100) throw new CooperError("RATE_LIMITED");
|
|
9
|
+
* return next(req);
|
|
10
|
+
* });
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function middleware(fn) {
|
|
14
|
+
return fn;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Cooper instance for global middleware registration.
|
|
18
|
+
*/
|
|
19
|
+
export const cooper = {
|
|
20
|
+
use(...middlewares) {
|
|
21
|
+
for (const mw of middlewares) {
|
|
22
|
+
registry.addGlobalMiddleware(mw);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAqB,MAAM,eAAe,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CAAC,EAAgB;IACzC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,GAAG,CAAC,GAAG,WAA2B;QAChC,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;YAC7B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;CACF,CAAC"}
|
package/dist/pubsub.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface TopicConfig {
|
|
2
|
+
deliveryGuarantee?: "at-least-once" | "exactly-once";
|
|
3
|
+
orderBy?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SubscribeConfig {
|
|
6
|
+
concurrency?: number;
|
|
7
|
+
handler: (data: any) => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export interface Topic<T> {
|
|
10
|
+
publish(data: T): Promise<void>;
|
|
11
|
+
subscribe(name: string, config: SubscribeConfig): any;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Declare a typed Pub/Sub topic.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* export const UserSignedUp = topic<{ userId: string; email: string }>(
|
|
18
|
+
* "user-signed-up",
|
|
19
|
+
* { deliveryGuarantee: "at-least-once" }
|
|
20
|
+
* );
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function topic<T = any>(name: string, config?: TopicConfig): Topic<T>;
|
|
24
|
+
//# sourceMappingURL=pubsub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pubsub.d.ts","sourceRoot":"","sources":["../src/pubsub.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,iBAAiB,CAAC,EAAE,eAAe,GAAG,cAAc,CAAC;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,GAAG,CAAC;CACvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAyC3E"}
|
package/dist/pubsub.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { registry } from "./registry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Declare a typed Pub/Sub topic.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* export const UserSignedUp = topic<{ userId: string; email: string }>(
|
|
7
|
+
* "user-signed-up",
|
|
8
|
+
* { deliveryGuarantee: "at-least-once" }
|
|
9
|
+
* );
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export function topic(name, config) {
|
|
13
|
+
const subscribers = new Map();
|
|
14
|
+
const t = {
|
|
15
|
+
async publish(data) {
|
|
16
|
+
// In local dev, deliver directly to subscribers
|
|
17
|
+
// In production, publish to NATS/SNS/Pub/Sub
|
|
18
|
+
const natsUrl = process.env.COOPER_NATS_URL ?? "nats://localhost:4222";
|
|
19
|
+
// Direct local delivery for development
|
|
20
|
+
for (const [subName, sub] of subscribers) {
|
|
21
|
+
try {
|
|
22
|
+
await sub.handler(data);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
console.error(`[cooper] Subscriber "${subName}" failed:`, err);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
subscribe(subName, subConfig) {
|
|
30
|
+
subscribers.set(subName, {
|
|
31
|
+
handler: subConfig.handler,
|
|
32
|
+
options: subConfig,
|
|
33
|
+
});
|
|
34
|
+
registry.registerTopic(name, {
|
|
35
|
+
name,
|
|
36
|
+
subscribers,
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
_cooper_type: "subscription",
|
|
40
|
+
topic: name,
|
|
41
|
+
name: subName,
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
registry.registerTopic(name, { name, subscribers });
|
|
46
|
+
return t;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=pubsub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pubsub.js","sourceRoot":"","sources":["../src/pubsub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAiBzC;;;;;;;;;GASG;AACH,MAAM,UAAU,KAAK,CAAU,IAAY,EAAE,MAAoB;IAC/D,MAAM,WAAW,GAAG,IAAI,GAAG,EAA+C,CAAC;IAE3E,MAAM,CAAC,GAAa;QAClB,KAAK,CAAC,OAAO,CAAC,IAAO;YACnB,gDAAgD;YAChD,6CAA6C;YAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC;YAEvE,wCAAwC;YACxC,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,WAAW,EAAE,CAAC;gBACzC,IAAI,CAAC;oBACH,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,wBAAwB,OAAO,WAAW,EAAE,GAAG,CAAC,CAAC;gBACjE,CAAC;YACH,CAAC;QACH,CAAC;QAED,SAAS,CAAC,OAAe,EAAE,SAA0B;YACnD,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE;gBACvB,OAAO,EAAE,SAAS,CAAC,OAAO;gBAC1B,OAAO,EAAE,SAAS;aACnB,CAAC,CAAC;YAEH,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE;gBAC3B,IAAI;gBACJ,WAAW;aACZ,CAAC,CAAC;YAEH,OAAO;gBACL,YAAY,EAAE,cAAc;gBAC5B,KAAK,EAAE,IAAI;gBACX,IAAI,EAAE,OAAO;aACd,CAAC;QACJ,CAAC;KACF,CAAC;IAEF,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAEpD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
package/dist/queue.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface QueueConfig {
|
|
2
|
+
concurrency?: number;
|
|
3
|
+
retries?: number;
|
|
4
|
+
retryDelay?: "fixed" | "exponential";
|
|
5
|
+
timeout?: string;
|
|
6
|
+
deadLetter?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface EnqueueOptions {
|
|
9
|
+
delay?: string;
|
|
10
|
+
priority?: "low" | "normal" | "high";
|
|
11
|
+
dedupeKey?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface QueueClient<T> {
|
|
14
|
+
enqueue(data: T, opts?: EnqueueOptions): Promise<void>;
|
|
15
|
+
worker(name: string, config: {
|
|
16
|
+
handler: (data: T) => Promise<void>;
|
|
17
|
+
onFailure?: (data: T, error: Error) => Promise<void>;
|
|
18
|
+
}): any;
|
|
19
|
+
list(): Promise<{
|
|
20
|
+
id: string;
|
|
21
|
+
data: T;
|
|
22
|
+
}[]>;
|
|
23
|
+
delete(id: string): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Declare a job queue.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* export const EmailQueue = queue<{ to: string; subject: string; body: string }>(
|
|
30
|
+
* "email-queue",
|
|
31
|
+
* { concurrency: 10, retries: 3, retryDelay: "exponential", timeout: "30s", deadLetter: "email-dlq" }
|
|
32
|
+
* );
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function queue<T = any>(name: string, config?: QueueConfig): QueueClient<T>;
|
|
36
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE;QAAE,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GAAG,GAAG,CAAC;IACjI,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAED;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAmGjF"}
|
package/dist/queue.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { registry } from "./registry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Declare a job queue.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* export const EmailQueue = queue<{ to: string; subject: string; body: string }>(
|
|
7
|
+
* "email-queue",
|
|
8
|
+
* { concurrency: 10, retries: 3, retryDelay: "exponential", timeout: "30s", deadLetter: "email-dlq" }
|
|
9
|
+
* );
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export function queue(name, config) {
|
|
13
|
+
// In-memory queue for local dev — backed by NATS JetStream
|
|
14
|
+
// In production: SQS, Cloud Tasks, Azure Storage Queues, or QStash
|
|
15
|
+
const jobs = [];
|
|
16
|
+
let processing = false;
|
|
17
|
+
let workerHandler = null;
|
|
18
|
+
let failureHandler = null;
|
|
19
|
+
const concurrency = config?.concurrency ?? 1;
|
|
20
|
+
const maxRetries = config?.retries ?? 0;
|
|
21
|
+
const parseDuration = (dur) => {
|
|
22
|
+
const m = dur.match(/^(\d+)(s|m|h|d)$/);
|
|
23
|
+
if (!m)
|
|
24
|
+
return 0;
|
|
25
|
+
const mult = { s: 1000, m: 60000, h: 3600000, d: 86400000 };
|
|
26
|
+
return parseInt(m[1]) * (mult[m[2]] ?? 1000);
|
|
27
|
+
};
|
|
28
|
+
const processQueue = async () => {
|
|
29
|
+
if (processing || !workerHandler)
|
|
30
|
+
return;
|
|
31
|
+
processing = true;
|
|
32
|
+
while (jobs.length > 0) {
|
|
33
|
+
const batch = jobs.splice(0, concurrency);
|
|
34
|
+
await Promise.allSettled(batch.map(async (job) => {
|
|
35
|
+
if (job.scheduledAt > Date.now()) {
|
|
36
|
+
jobs.push(job); // not ready yet
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
await workerHandler(job.data);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
job.attempts++;
|
|
44
|
+
if (job.attempts <= maxRetries) {
|
|
45
|
+
const delay = config?.retryDelay === "exponential"
|
|
46
|
+
? Math.pow(2, job.attempts - 1) * 1000
|
|
47
|
+
: 1000;
|
|
48
|
+
job.scheduledAt = Date.now() + delay;
|
|
49
|
+
jobs.push(job);
|
|
50
|
+
}
|
|
51
|
+
else if (failureHandler) {
|
|
52
|
+
await failureHandler(job.data, err);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
processing = false;
|
|
58
|
+
};
|
|
59
|
+
const client = {
|
|
60
|
+
async enqueue(data, opts) {
|
|
61
|
+
const id = crypto.randomUUID();
|
|
62
|
+
const delay = opts?.delay ? parseDuration(opts.delay) : 0;
|
|
63
|
+
jobs.push({
|
|
64
|
+
id,
|
|
65
|
+
data,
|
|
66
|
+
attempts: 0,
|
|
67
|
+
priority: opts?.priority ?? "normal",
|
|
68
|
+
scheduledAt: Date.now() + delay,
|
|
69
|
+
});
|
|
70
|
+
// Sort by priority
|
|
71
|
+
const priorityOrder = { high: 0, normal: 1, low: 2 };
|
|
72
|
+
jobs.sort((a, b) => (priorityOrder[a.priority] ?? 1) - (priorityOrder[b.priority] ?? 1));
|
|
73
|
+
// Trigger processing
|
|
74
|
+
setImmediate(() => processQueue());
|
|
75
|
+
},
|
|
76
|
+
worker(workerName, workerConfig) {
|
|
77
|
+
workerHandler = workerConfig.handler;
|
|
78
|
+
failureHandler = workerConfig.onFailure ?? null;
|
|
79
|
+
registry.registerQueue(name, {
|
|
80
|
+
name,
|
|
81
|
+
options: config ?? {},
|
|
82
|
+
worker: { name: workerName, handler: workerConfig.handler, onFailure: workerConfig.onFailure },
|
|
83
|
+
});
|
|
84
|
+
// Start processing any already-queued jobs
|
|
85
|
+
setImmediate(() => processQueue());
|
|
86
|
+
return { _cooper_type: "queue_worker", queue: name, name: workerName };
|
|
87
|
+
},
|
|
88
|
+
async list() {
|
|
89
|
+
return jobs.map((j) => ({ id: j.id, data: j.data }));
|
|
90
|
+
},
|
|
91
|
+
async delete(id) {
|
|
92
|
+
const idx = jobs.findIndex((j) => j.id === id);
|
|
93
|
+
if (idx >= 0)
|
|
94
|
+
jobs.splice(idx, 1);
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
registry.registerQueue(name, { name, options: config ?? {} });
|
|
98
|
+
return client;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAuBzC;;;;;;;;;GASG;AACH,MAAM,UAAU,KAAK,CAAU,IAAY,EAAE,MAAoB;IAC/D,2DAA2D;IAC3D,mEAAmE;IACnE,MAAM,IAAI,GAAuF,EAAE,CAAC;IACpG,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,aAAa,GAAwC,IAAI,CAAC;IAC9D,IAAI,cAAc,GAAsD,IAAI,CAAC;IAC7E,MAAM,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,MAAM,EAAE,OAAO,IAAI,CAAC,CAAC;IAExC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAU,EAAE;QAC5C,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACxC,IAAI,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;QACjB,MAAM,IAAI,GAA2B,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;QACpF,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IAC/C,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE;QAC9B,IAAI,UAAU,IAAI,CAAC,aAAa;YAAE,OAAO;QACzC,UAAU,GAAG,IAAI,CAAC;QAElB,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;YAC1C,MAAM,OAAO,CAAC,UAAU,CACtB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACtB,IAAI,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;oBACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB;oBAChC,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC;oBACH,MAAM,aAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACjC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,GAAG,CAAC,QAAQ,EAAE,CAAC;oBACf,IAAI,GAAG,CAAC,QAAQ,IAAI,UAAU,EAAE,CAAC;wBAC/B,MAAM,KAAK,GAAG,MAAM,EAAE,UAAU,KAAK,aAAa;4BAChD,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,IAAI;4BACtC,CAAC,CAAC,IAAI,CAAC;wBACT,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;wBACrC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBACjB,CAAC;yBAAM,IAAI,cAAc,EAAE,CAAC;wBAC1B,MAAM,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,GAAY,CAAC,CAAC;oBAC/C,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CACH,CAAC;QACJ,CAAC;QAED,UAAU,GAAG,KAAK,CAAC;IACrB,CAAC,CAAC;IAEF,MAAM,MAAM,GAAmB;QAC7B,KAAK,CAAC,OAAO,CAAC,IAAO,EAAE,IAAqB;YAC1C,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAC,IAAI,CAAC;gBACR,EAAE;gBACF,IAAI;gBACJ,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,QAAQ;gBACpC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;aAChC,CAAC,CAAC;YAEH,mBAAmB;YACnB,MAAM,aAAa,GAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;YAC7E,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAEzF,qBAAqB;YACrB,YAAY,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;QACrC,CAAC;QAED,MAAM,CAAC,UAAkB,EAAE,YAAY;YACrC,aAAa,GAAG,YAAY,CAAC,OAAO,CAAC;YACrC,cAAc,GAAG,YAAY,CAAC,SAAS,IAAI,IAAI,CAAC;YAEhD,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE;gBAC3B,IAAI;gBACJ,OAAO,EAAE,MAAM,IAAI,EAAE;gBACrB,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,EAAE;aAC/F,CAAC,CAAC;YAEH,2CAA2C;YAC3C,YAAY,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;YAEnC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QACzE,CAAC;QAED,KAAK,CAAC,IAAI;YACR,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,EAAU;YACrB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YAC/C,IAAI,GAAG,IAAI,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC;KACF,CAAC;IAEF,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;IAE9D,OAAO,MAAM,CAAC;AAChB,CAAC"}
|