@gencow/core 0.1.23 → 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 (77) hide show
  1. package/dist/crud.d.ts +2 -2
  2. package/dist/crud.js +225 -208
  3. package/dist/index.d.ts +7 -3
  4. package/dist/index.js +4 -1
  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-types.d.ts +81 -0
  16. package/dist/workflow-types.js +12 -0
  17. package/dist/workflow.d.ts +30 -0
  18. package/dist/workflow.js +150 -0
  19. package/dist/workflows-api.d.ts +13 -0
  20. package/dist/workflows-api.js +321 -0
  21. package/package.json +46 -42
  22. package/src/__tests__/auth.test.ts +90 -86
  23. package/src/__tests__/crons.test.ts +69 -67
  24. package/src/__tests__/crud-codegen-integration.test.ts +164 -170
  25. package/src/__tests__/crud-owner-rls.test.ts +308 -301
  26. package/src/__tests__/crud.test.ts +694 -711
  27. package/src/__tests__/dist-exports.test.ts +120 -114
  28. package/src/__tests__/fixtures/basic/auth.ts +16 -16
  29. package/src/__tests__/fixtures/basic/drizzle.config.ts +1 -4
  30. package/src/__tests__/fixtures/basic/index.ts +1 -1
  31. package/src/__tests__/fixtures/basic/schema.ts +1 -1
  32. package/src/__tests__/fixtures/basic/tasks.ts +4 -4
  33. package/src/__tests__/fixtures/common/auth-schema.ts +38 -34
  34. package/src/__tests__/helpers/basic-rls-fixture.ts +80 -78
  35. package/src/__tests__/helpers/pglite-migrations.ts +2 -5
  36. package/src/__tests__/helpers/pglite-rls-session.ts +13 -16
  37. package/src/__tests__/helpers/seed-like-fill.ts +50 -44
  38. package/src/__tests__/helpers/test-gencow-ctx-rls.ts +4 -7
  39. package/src/__tests__/httpaction.test.ts +91 -91
  40. package/src/__tests__/image-optimization.test.ts +570 -574
  41. package/src/__tests__/load.test.ts +321 -308
  42. package/src/__tests__/network-sim.test.ts +238 -215
  43. package/src/__tests__/reactive.test.ts +380 -358
  44. package/src/__tests__/retry.test.ts +99 -84
  45. package/src/__tests__/rls-crud-basic.test.ts +172 -245
  46. package/src/__tests__/rls-crud-no-owner-rls-pglite.test.ts +81 -81
  47. package/src/__tests__/rls-custom-mutation-handlers.test.ts +47 -94
  48. package/src/__tests__/rls-custom-query-handlers.test.ts +92 -92
  49. package/src/__tests__/rls-db-leased-connection.test.ts +2 -6
  50. package/src/__tests__/rls-session-and-policies.test.ts +181 -199
  51. package/src/__tests__/scheduler-durable-v2.test.ts +199 -181
  52. package/src/__tests__/scheduler-durable.test.ts +117 -117
  53. package/src/__tests__/scheduler-exec.test.ts +258 -246
  54. package/src/__tests__/scheduler.test.ts +129 -111
  55. package/src/__tests__/storage.test.ts +282 -269
  56. package/src/__tests__/tsconfig.json +6 -6
  57. package/src/__tests__/validator.test.ts +236 -232
  58. package/src/__tests__/workflow.test.ts +606 -0
  59. package/src/__tests__/ws-integration.test.ts +223 -218
  60. package/src/__tests__/ws-scale.test.ts +168 -159
  61. package/src/auth-config.ts +18 -18
  62. package/src/auth.ts +106 -106
  63. package/src/crons.ts +77 -77
  64. package/src/crud.ts +523 -479
  65. package/src/index.ts +71 -6
  66. package/src/reactive.ts +357 -331
  67. package/src/retry.ts +51 -54
  68. package/src/rls-db.ts +195 -205
  69. package/src/rls.ts +33 -36
  70. package/src/scheduler.ts +237 -211
  71. package/src/server.ts +0 -1
  72. package/src/storage.ts +632 -593
  73. package/src/v.ts +119 -114
  74. package/src/workflow-types.ts +108 -0
  75. package/src/workflow.ts +188 -0
  76. package/src/workflows-api.ts +415 -0
  77. 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
  });