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