@gencow/core 0.1.24 → 0.1.25
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/crud.d.ts +2 -2
- package/dist/crud.js +225 -208
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/reactive.js +10 -3
- package/dist/retry.js +1 -1
- package/dist/rls-db.d.ts +2 -2
- package/dist/rls-db.js +1 -5
- package/dist/scheduler.d.ts +2 -0
- package/dist/scheduler.js +16 -6
- package/dist/server.d.ts +0 -1
- package/dist/server.js +0 -1
- package/dist/storage.js +29 -22
- package/dist/v.d.ts +2 -2
- package/dist/workflow.js +4 -11
- package/dist/workflows-api.js +5 -12
- package/package.json +46 -42
- package/src/__tests__/auth.test.ts +90 -86
- package/src/__tests__/crons.test.ts +69 -67
- package/src/__tests__/crud-codegen-integration.test.ts +164 -170
- package/src/__tests__/crud-owner-rls.test.ts +308 -301
- package/src/__tests__/crud.test.ts +694 -711
- package/src/__tests__/dist-exports.test.ts +120 -120
- package/src/__tests__/fixtures/basic/auth.ts +16 -16
- package/src/__tests__/fixtures/basic/drizzle.config.ts +1 -4
- package/src/__tests__/fixtures/basic/index.ts +1 -1
- package/src/__tests__/fixtures/basic/schema.ts +1 -1
- package/src/__tests__/fixtures/basic/tasks.ts +4 -4
- package/src/__tests__/fixtures/common/auth-schema.ts +38 -34
- package/src/__tests__/helpers/basic-rls-fixture.ts +80 -78
- package/src/__tests__/helpers/pglite-migrations.ts +2 -5
- package/src/__tests__/helpers/pglite-rls-session.ts +13 -16
- package/src/__tests__/helpers/seed-like-fill.ts +50 -44
- package/src/__tests__/helpers/test-gencow-ctx-rls.ts +4 -7
- package/src/__tests__/httpaction.test.ts +91 -91
- package/src/__tests__/image-optimization.test.ts +570 -574
- package/src/__tests__/load.test.ts +321 -308
- package/src/__tests__/network-sim.test.ts +238 -215
- package/src/__tests__/reactive.test.ts +380 -358
- package/src/__tests__/retry.test.ts +99 -84
- package/src/__tests__/rls-crud-basic.test.ts +172 -245
- package/src/__tests__/rls-crud-no-owner-rls-pglite.test.ts +81 -81
- package/src/__tests__/rls-custom-mutation-handlers.test.ts +47 -94
- package/src/__tests__/rls-custom-query-handlers.test.ts +92 -92
- package/src/__tests__/rls-db-leased-connection.test.ts +2 -6
- package/src/__tests__/rls-session-and-policies.test.ts +181 -199
- package/src/__tests__/scheduler-durable-v2.test.ts +199 -181
- package/src/__tests__/scheduler-durable.test.ts +117 -117
- package/src/__tests__/scheduler-exec.test.ts +258 -246
- package/src/__tests__/scheduler.test.ts +129 -111
- package/src/__tests__/storage.test.ts +282 -269
- package/src/__tests__/tsconfig.json +6 -6
- package/src/__tests__/validator.test.ts +236 -232
- package/src/__tests__/workflow.test.ts +309 -286
- package/src/__tests__/ws-integration.test.ts +223 -218
- package/src/__tests__/ws-scale.test.ts +168 -159
- package/src/auth-config.ts +18 -18
- package/src/auth.ts +106 -106
- package/src/crons.ts +77 -77
- package/src/crud.ts +523 -479
- package/src/index.ts +69 -5
- package/src/reactive.ts +357 -331
- package/src/retry.ts +51 -54
- package/src/rls-db.ts +195 -205
- package/src/rls.ts +33 -36
- package/src/scheduler.ts +237 -211
- package/src/server.ts +0 -1
- package/src/storage.ts +632 -593
- package/src/v.ts +119 -114
- package/src/workflow-types.ts +67 -70
- package/src/workflow.ts +99 -116
- package/src/workflows-api.ts +231 -241
- package/src/db.ts +0 -18
|
@@ -9,165 +9,165 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { describe, it, expect } from "bun:test";
|
|
12
|
-
import { createScheduler } from "../scheduler";
|
|
13
|
-
import type { ScheduledJobRecord } from "../scheduler";
|
|
12
|
+
import { createScheduler } from "../scheduler.js";
|
|
13
|
+
import type { ScheduledJobRecord } from "../scheduler.js";
|
|
14
14
|
|
|
15
15
|
describe("Scheduler Durable Mode — persistJob/removeJob", () => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
scheduler.registerAction("test.durable", async () => {});
|
|
27
|
-
const id = scheduler.runAfter(5000, "test.durable", { key: "value" });
|
|
28
|
-
|
|
29
|
-
// persistJob은 비동기이므로 약간 대기
|
|
30
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
31
|
-
|
|
32
|
-
expect(persisted.length).toBe(1);
|
|
33
|
-
expect(persisted[0].id).toBe(id);
|
|
34
|
-
expect(persisted[0].action).toBe("test.durable");
|
|
35
|
-
expect(persisted[0].args).toEqual({ key: "value" });
|
|
36
|
-
expect(persisted[0].runAt).toBeInstanceOf(Date);
|
|
37
|
-
expect(persisted[0].runAt.getTime()).toBeGreaterThan(Date.now() + 4000); // ~5초 후
|
|
16
|
+
it("durable mode에서 runAfter → persistJob 콜백 호출", async () => {
|
|
17
|
+
const persisted: ScheduledJobRecord[] = [];
|
|
18
|
+
|
|
19
|
+
const scheduler = createScheduler({
|
|
20
|
+
persistJob: async (job) => {
|
|
21
|
+
persisted.push(job);
|
|
22
|
+
},
|
|
23
|
+
removeJob: async () => true,
|
|
38
24
|
});
|
|
39
25
|
|
|
40
|
-
|
|
41
|
-
|
|
26
|
+
scheduler.registerAction("test.durable", async () => {});
|
|
27
|
+
const id = scheduler.runAfter(5000, "test.durable", { key: "value" });
|
|
42
28
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
removeJob: async () => true,
|
|
46
|
-
});
|
|
29
|
+
// persistJob은 비동기이므로 약간 대기
|
|
30
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
47
31
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
32
|
+
expect(persisted.length).toBe(1);
|
|
33
|
+
expect(persisted[0].id).toBe(id);
|
|
34
|
+
expect(persisted[0].action).toBe("test.durable");
|
|
35
|
+
expect(persisted[0].args).toEqual({ key: "value" });
|
|
36
|
+
expect(persisted[0].runAt).toBeInstanceOf(Date);
|
|
37
|
+
expect(persisted[0].runAt.getTime()).toBeGreaterThan(Date.now() + 4000); // ~5초 후
|
|
38
|
+
});
|
|
51
39
|
|
|
52
|
-
|
|
40
|
+
it("durable mode에서 runAfter → setTimeout 실행 안 함 (외부 폴러에 위임)", async () => {
|
|
41
|
+
let actionExecuted = false;
|
|
53
42
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
expect(actionExecuted).toBe(false);
|
|
43
|
+
const scheduler = createScheduler({
|
|
44
|
+
persistJob: async () => {},
|
|
45
|
+
removeJob: async () => true,
|
|
58
46
|
});
|
|
59
47
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const scheduler = createScheduler({
|
|
64
|
-
persistJob: async () => {},
|
|
65
|
-
removeJob: async (jobId) => {
|
|
66
|
-
removed.push(jobId);
|
|
67
|
-
return true;
|
|
68
|
-
},
|
|
69
|
-
});
|
|
48
|
+
scheduler.registerAction("no.exec", async () => {
|
|
49
|
+
actionExecuted = true;
|
|
50
|
+
});
|
|
70
51
|
|
|
71
|
-
|
|
72
|
-
const id = scheduler.runAfter(10000, "noop");
|
|
52
|
+
scheduler.runAfter(50, "no.exec");
|
|
73
53
|
|
|
74
|
-
|
|
75
|
-
|
|
54
|
+
// 100ms 대기 — durable mode에서는 action이 실행되지 않아야 함
|
|
55
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
76
56
|
|
|
77
|
-
|
|
57
|
+
expect(actionExecuted).toBe(false);
|
|
58
|
+
});
|
|
78
59
|
|
|
79
|
-
|
|
80
|
-
|
|
60
|
+
it("durable mode에서 cancel → removeJob 콜백 호출", async () => {
|
|
61
|
+
const removed: string[] = [];
|
|
81
62
|
|
|
82
|
-
|
|
83
|
-
|
|
63
|
+
const scheduler = createScheduler({
|
|
64
|
+
persistJob: async () => {},
|
|
65
|
+
removeJob: async (jobId) => {
|
|
66
|
+
removed.push(jobId);
|
|
67
|
+
return true;
|
|
68
|
+
},
|
|
84
69
|
});
|
|
85
70
|
|
|
86
|
-
|
|
87
|
-
|
|
71
|
+
scheduler.registerAction("noop", async () => {});
|
|
72
|
+
const id = scheduler.runAfter(10000, "noop");
|
|
88
73
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
persisted.push(job);
|
|
92
|
-
},
|
|
93
|
-
removeJob: async () => true,
|
|
94
|
-
});
|
|
74
|
+
// persistJob 완료 대기
|
|
75
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
95
76
|
|
|
96
|
-
|
|
97
|
-
scheduler.registerAction("onFail", async () => {});
|
|
77
|
+
scheduler.cancel(id);
|
|
98
78
|
|
|
99
|
-
|
|
79
|
+
// removeJob은 비동기이므로 대기
|
|
80
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
100
81
|
|
|
101
|
-
|
|
82
|
+
expect(removed.length).toBeGreaterThanOrEqual(1);
|
|
83
|
+
expect(removed).toContain(id);
|
|
84
|
+
});
|
|
102
85
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
86
|
+
it("durable mode에서 onError action 이름이 persistJob에 전달", async () => {
|
|
87
|
+
const persisted: ScheduledJobRecord[] = [];
|
|
106
88
|
|
|
107
|
-
|
|
108
|
-
|
|
89
|
+
const scheduler = createScheduler({
|
|
90
|
+
persistJob: async (job) => {
|
|
91
|
+
persisted.push(job);
|
|
92
|
+
},
|
|
93
|
+
removeJob: async () => true,
|
|
94
|
+
});
|
|
109
95
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
throw new Error("DB connection failed");
|
|
113
|
-
},
|
|
114
|
-
removeJob: async () => true,
|
|
115
|
-
});
|
|
96
|
+
scheduler.registerAction("step1", async () => {});
|
|
97
|
+
scheduler.registerAction("onFail", async () => {});
|
|
116
98
|
|
|
117
|
-
|
|
118
|
-
actionExecuted = true;
|
|
119
|
-
});
|
|
99
|
+
scheduler.runAfter(1000, "step1", {}, { onError: "onFail" });
|
|
120
100
|
|
|
121
|
-
|
|
122
|
-
const origError = console.error;
|
|
123
|
-
console.error = () => {};
|
|
101
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
124
102
|
|
|
125
|
-
|
|
103
|
+
expect(persisted.length).toBe(1);
|
|
104
|
+
expect(persisted[0].onErrorAction).toBe("onFail");
|
|
105
|
+
});
|
|
126
106
|
|
|
127
|
-
|
|
128
|
-
|
|
107
|
+
it("persistJob 실패 시 인메모리 fallback으로 실행", async () => {
|
|
108
|
+
let actionExecuted = false;
|
|
129
109
|
|
|
130
|
-
|
|
110
|
+
const scheduler = createScheduler({
|
|
111
|
+
persistJob: async () => {
|
|
112
|
+
throw new Error("DB connection failed");
|
|
113
|
+
},
|
|
114
|
+
removeJob: async () => true,
|
|
115
|
+
});
|
|
131
116
|
|
|
132
|
-
|
|
117
|
+
scheduler.registerAction("fallback.test", async () => {
|
|
118
|
+
actionExecuted = true;
|
|
133
119
|
});
|
|
134
120
|
|
|
135
|
-
|
|
136
|
-
|
|
121
|
+
// suppress expected error log
|
|
122
|
+
const origError = console.error;
|
|
123
|
+
console.error = () => {};
|
|
137
124
|
|
|
138
|
-
|
|
125
|
+
scheduler.runAfter(50, "fallback.test");
|
|
139
126
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
});
|
|
127
|
+
// persistJob 실패 → fallback → setTimeout(50ms) → 실행
|
|
128
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
143
129
|
|
|
144
|
-
|
|
130
|
+
console.error = origError;
|
|
145
131
|
|
|
146
|
-
|
|
132
|
+
expect(actionExecuted).toBe(true);
|
|
133
|
+
});
|
|
147
134
|
|
|
148
|
-
|
|
149
|
-
|
|
135
|
+
it("콜백 미설정 시 기존 인메모리 mode 유지", async () => {
|
|
136
|
+
let executed = false;
|
|
150
137
|
|
|
151
|
-
|
|
152
|
-
const persisted: ScheduledJobRecord[] = [];
|
|
138
|
+
const scheduler = createScheduler(); // no options
|
|
153
139
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
});
|
|
140
|
+
scheduler.registerAction("mem.test", async () => {
|
|
141
|
+
executed = true;
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
scheduler.runAfter(50, "mem.test");
|
|
160
145
|
|
|
161
|
-
|
|
146
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
162
147
|
|
|
163
|
-
|
|
164
|
-
|
|
148
|
+
expect(executed).toBe(true);
|
|
149
|
+
});
|
|
165
150
|
|
|
166
|
-
|
|
151
|
+
it("runAt도 durable mode에서 persistJob 호출", async () => {
|
|
152
|
+
const persisted: ScheduledJobRecord[] = [];
|
|
167
153
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
154
|
+
const scheduler = createScheduler({
|
|
155
|
+
persistJob: async (job) => {
|
|
156
|
+
persisted.push(job);
|
|
157
|
+
},
|
|
158
|
+
removeJob: async () => true,
|
|
172
159
|
});
|
|
160
|
+
|
|
161
|
+
scheduler.registerAction("future.task", async () => {});
|
|
162
|
+
|
|
163
|
+
const futureTime = new Date(Date.now() + 60_000); // 1분 후
|
|
164
|
+
scheduler.runAt(futureTime, "future.task", { x: 1 });
|
|
165
|
+
|
|
166
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
167
|
+
|
|
168
|
+
expect(persisted.length).toBe(1);
|
|
169
|
+
expect(persisted[0].action).toBe("future.task");
|
|
170
|
+
// runAt → runAfter 변환이므로 runAt 시간과 근사해야 함
|
|
171
|
+
expect(Math.abs(persisted[0].runAt.getTime() - futureTime.getTime())).toBeLessThan(1000);
|
|
172
|
+
});
|
|
173
173
|
});
|