@haverstack/server 0.8.0 → 0.9.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.
Files changed (197) hide show
  1. package/dist/app.d.ts +8 -0
  2. package/dist/app.d.ts.map +1 -0
  3. package/dist/app.js +70 -0
  4. package/dist/app.js.map +1 -0
  5. package/dist/config.d.ts +21 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +115 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/index.d.ts +16 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +12 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/lib/changeStreams.d.ts +17 -0
  14. package/dist/lib/changeStreams.d.ts.map +1 -0
  15. package/{src/lib/changeStreams.ts → dist/lib/changeStreams.js} +12 -12
  16. package/dist/lib/changeStreams.js.map +1 -0
  17. package/dist/lib/frameGate.d.ts +26 -0
  18. package/dist/lib/frameGate.d.ts.map +1 -0
  19. package/dist/lib/frameGate.js +44 -0
  20. package/dist/lib/frameGate.js.map +1 -0
  21. package/dist/lib/json.d.ts +10 -0
  22. package/dist/lib/json.d.ts.map +1 -0
  23. package/dist/lib/json.js +27 -0
  24. package/dist/lib/json.js.map +1 -0
  25. package/dist/lib/nonceStore.d.ts +50 -0
  26. package/dist/lib/nonceStore.d.ts.map +1 -0
  27. package/dist/lib/nonceStore.js +96 -0
  28. package/dist/lib/nonceStore.js.map +1 -0
  29. package/dist/lib/queryLimit.d.ts +4 -0
  30. package/dist/lib/queryLimit.d.ts.map +1 -0
  31. package/{src/lib/queryLimit.ts → dist/lib/queryLimit.js} +5 -6
  32. package/dist/lib/queryLimit.js.map +1 -0
  33. package/dist/lib/queryWorker/pool.d.ts +60 -0
  34. package/dist/lib/queryWorker/pool.d.ts.map +1 -0
  35. package/dist/lib/queryWorker/pool.js +278 -0
  36. package/dist/lib/queryWorker/pool.js.map +1 -0
  37. package/{src/lib/queryWorker/protocol.ts → dist/lib/queryWorker/protocol.d.ts} +21 -18
  38. package/dist/lib/queryWorker/protocol.d.ts.map +1 -0
  39. package/dist/lib/queryWorker/protocol.js +2 -0
  40. package/dist/lib/queryWorker/protocol.js.map +1 -0
  41. package/dist/lib/queryWorker/worker.d.ts +2 -0
  42. package/dist/lib/queryWorker/worker.d.ts.map +1 -0
  43. package/{src/lib/queryWorker/worker.ts → dist/lib/queryWorker/worker.js} +19 -22
  44. package/dist/lib/queryWorker/worker.js.map +1 -0
  45. package/dist/lib/resumeBuffer.d.ts +143 -0
  46. package/dist/lib/resumeBuffer.d.ts.map +1 -0
  47. package/dist/lib/resumeBuffer.js +216 -0
  48. package/dist/lib/resumeBuffer.js.map +1 -0
  49. package/dist/lib/resumeCursor.d.ts +16 -0
  50. package/dist/lib/resumeCursor.d.ts.map +1 -0
  51. package/{src/lib/resumeCursor.ts → dist/lib/resumeCursor.js} +22 -24
  52. package/dist/lib/resumeCursor.js.map +1 -0
  53. package/dist/lib/tokenSweep.d.ts +17 -0
  54. package/dist/lib/tokenSweep.d.ts.map +1 -0
  55. package/dist/lib/tokenSweep.js +40 -0
  56. package/dist/lib/tokenSweep.js.map +1 -0
  57. package/dist/main.d.ts +2 -0
  58. package/dist/main.d.ts.map +1 -0
  59. package/dist/main.js +46 -0
  60. package/dist/main.js.map +1 -0
  61. package/dist/middleware/auth.d.ts +25 -0
  62. package/dist/middleware/auth.d.ts.map +1 -0
  63. package/dist/middleware/auth.js +74 -0
  64. package/dist/middleware/auth.js.map +1 -0
  65. package/dist/middleware/errors.d.ts +17 -0
  66. package/dist/middleware/errors.d.ts.map +1 -0
  67. package/dist/middleware/errors.js +64 -0
  68. package/dist/middleware/errors.js.map +1 -0
  69. package/dist/routes/attachments.d.ts +5 -0
  70. package/dist/routes/attachments.d.ts.map +1 -0
  71. package/dist/routes/attachments.js +108 -0
  72. package/dist/routes/attachments.js.map +1 -0
  73. package/dist/routes/auth.d.ts +6 -0
  74. package/dist/routes/auth.d.ts.map +1 -0
  75. package/dist/routes/auth.js +110 -0
  76. package/dist/routes/auth.js.map +1 -0
  77. package/dist/routes/changes.d.ts +22 -0
  78. package/dist/routes/changes.d.ts.map +1 -0
  79. package/dist/routes/changes.js +233 -0
  80. package/dist/routes/changes.js.map +1 -0
  81. package/dist/routes/entity.d.ts +5 -0
  82. package/dist/routes/entity.d.ts.map +1 -0
  83. package/dist/routes/entity.js +30 -0
  84. package/dist/routes/entity.js.map +1 -0
  85. package/dist/routes/health.d.ts +4 -0
  86. package/dist/routes/health.d.ts.map +1 -0
  87. package/dist/routes/health.js +7 -0
  88. package/dist/routes/health.js.map +1 -0
  89. package/dist/routes/records.d.ts +5 -0
  90. package/dist/routes/records.d.ts.map +1 -0
  91. package/dist/routes/records.js +231 -0
  92. package/dist/routes/records.js.map +1 -0
  93. package/dist/routes/tokens.d.ts +5 -0
  94. package/dist/routes/tokens.d.ts.map +1 -0
  95. package/dist/routes/tokens.js +65 -0
  96. package/dist/routes/tokens.js.map +1 -0
  97. package/dist/routes/types.d.ts +5 -0
  98. package/dist/routes/types.d.ts.map +1 -0
  99. package/dist/routes/types.js +46 -0
  100. package/dist/routes/types.js.map +1 -0
  101. package/dist/routes/wellknown.d.ts +6 -0
  102. package/dist/routes/wellknown.d.ts.map +1 -0
  103. package/dist/routes/wellknown.js +45 -0
  104. package/dist/routes/wellknown.js.map +1 -0
  105. package/dist/shutdown.d.ts +23 -0
  106. package/dist/shutdown.d.ts.map +1 -0
  107. package/dist/shutdown.js +32 -0
  108. package/dist/shutdown.js.map +1 -0
  109. package/dist/stack.d.ts +20 -0
  110. package/dist/stack.d.ts.map +1 -0
  111. package/dist/stack.js +50 -0
  112. package/dist/stack.js.map +1 -0
  113. package/dist/testing.d.ts +49 -0
  114. package/dist/testing.d.ts.map +1 -0
  115. package/dist/testing.js +130 -0
  116. package/dist/testing.js.map +1 -0
  117. package/{src/types.ts → dist/types.d.ts} +5 -5
  118. package/dist/types.d.ts.map +1 -0
  119. package/dist/types.js +2 -0
  120. package/dist/types.js.map +1 -0
  121. package/{src/wireError.ts → dist/wireError.d.ts} +2 -9
  122. package/dist/wireError.d.ts.map +1 -0
  123. package/dist/wireError.js +13 -0
  124. package/dist/wireError.js.map +1 -0
  125. package/package.json +42 -17
  126. package/.claude/settings.local.json +0 -22
  127. package/.dockerignore +0 -10
  128. package/.env.example +0 -90
  129. package/.github/pull_request_template.md +0 -23
  130. package/.github/workflows/ci.yml +0 -55
  131. package/.github/workflows/release.yml +0 -99
  132. package/.prettierignore +0 -3
  133. package/.prettierrc +0 -7
  134. package/AGENTS.md +0 -91
  135. package/CONTRIBUTING.md +0 -234
  136. package/Dockerfile +0 -30
  137. package/SECURITY.md +0 -54
  138. package/docs/api.md +0 -277
  139. package/docs/deployment.md +0 -212
  140. package/eslint.config.mjs +0 -18
  141. package/pnpm-workspace.yaml +0 -13
  142. package/src/app.ts +0 -86
  143. package/src/config.ts +0 -176
  144. package/src/index.ts +0 -54
  145. package/src/lib/frameGate.ts +0 -42
  146. package/src/lib/json.ts +0 -27
  147. package/src/lib/nonceStore.ts +0 -103
  148. package/src/lib/queryWorker/pool.ts +0 -324
  149. package/src/lib/resumeBuffer.ts +0 -268
  150. package/src/lib/tokenSweep.ts +0 -43
  151. package/src/middleware/auth.ts +0 -77
  152. package/src/middleware/errors.ts +0 -73
  153. package/src/routes/attachments.ts +0 -126
  154. package/src/routes/auth.ts +0 -137
  155. package/src/routes/changes.ts +0 -279
  156. package/src/routes/entity.ts +0 -33
  157. package/src/routes/health.ts +0 -8
  158. package/src/routes/records.ts +0 -259
  159. package/src/routes/tokens.ts +0 -85
  160. package/src/routes/types.ts +0 -57
  161. package/src/routes/wellknown.ts +0 -55
  162. package/src/shutdown.ts +0 -56
  163. package/src/stack.ts +0 -96
  164. package/tests/app.test.ts +0 -86
  165. package/tests/changeFeedClient.ts +0 -156
  166. package/tests/config.test.ts +0 -112
  167. package/tests/conformance.test.ts +0 -2322
  168. package/tests/fixtures/blockingWorker.ts +0 -27
  169. package/tests/fixtures/brokenWorker.ts +0 -7
  170. package/tests/lib/changeFeedClient.test.ts +0 -126
  171. package/tests/lib/frameGate.test.ts +0 -93
  172. package/tests/lib/queryLimit.test.ts +0 -33
  173. package/tests/lib/queryWorker.test.ts +0 -60
  174. package/tests/lib/queryWorkerPool.test.ts +0 -129
  175. package/tests/lib/resumeBuffer.test.ts +0 -341
  176. package/tests/lib/resumeCursor.test.ts +0 -46
  177. package/tests/middleware/errors.test.ts +0 -176
  178. package/tests/routes/associations.test.ts +0 -170
  179. package/tests/routes/attachments.test.ts +0 -621
  180. package/tests/routes/auth.test.ts +0 -448
  181. package/tests/routes/changes.test.ts +0 -567
  182. package/tests/routes/contentQuery.test.ts +0 -68
  183. package/tests/routes/entity.test.ts +0 -170
  184. package/tests/routes/groups.test.ts +0 -69
  185. package/tests/routes/records.test.ts +0 -1965
  186. package/tests/routes/relatedToQuery.test.ts +0 -182
  187. package/tests/routes/tokens.test.ts +0 -157
  188. package/tests/routes/tombstones.test.ts +0 -93
  189. package/tests/routes/types.test.ts +0 -129
  190. package/tests/routes/versions.test.ts +0 -177
  191. package/tests/routes/wellknown.test.ts +0 -71
  192. package/tests/setup.ts +0 -154
  193. package/tests/shutdown.test.ts +0 -121
  194. package/tests/stack.test.ts +0 -198
  195. package/tsconfig.build.json +0 -9
  196. package/tsconfig.json +0 -19
  197. package/vitest.config.ts +0 -12
@@ -1,198 +0,0 @@
1
- import { describe, it, expect, vi, afterEach } from 'vitest';
2
- import { writeFileSync } from 'node:fs';
3
- import { rm } from 'node:fs/promises';
4
- import { dirname } from 'node:path';
5
- import type { Logger } from 'pino';
6
- import { initStack } from '../src/stack.js';
7
- import { testConfig, tempDbPath, logger, OTHER_ENTITY_ID } from './setup.js';
8
-
9
- // A minimal stub, so the mock can't silently miss calls to unmocked
10
- // methods that a full pino instance's prototype methods wouldn't survive a
11
- // spread of. initStack() itself only calls logger.warn(), but the context
12
- // it returns owns a QueryWorkerPool that logs errors on its own schedule —
13
- // and an unstubbed method there surfaces as an uncaught TypeError from
14
- // inside a worker event handler, not as a failed assertion.
15
- function spyLogger(): Logger & { warn: ReturnType<typeof vi.fn> } {
16
- return { warn: vi.fn(), error: vi.fn() } as unknown as Logger & {
17
- warn: ReturnType<typeof vi.fn>;
18
- };
19
- }
20
-
21
- // A second server process against the same DB_PATH must fail loudly at
22
- // startup rather than corrupt or silently share the database — the native
23
- // SQLite adapter's own storage-ownership lock (record-adapter-sqlite) is
24
- // what enforces this; this test pins that the failure surfaces cleanly
25
- // through initStack() rather than getting swallowed.
26
- describe('initStack double-open protection', () => {
27
- let dbPath: string | undefined;
28
- afterEach(async () => {
29
- if (dbPath) await rm(dirname(dbPath), { recursive: true, force: true }).catch(() => {});
30
- });
31
-
32
- it('fails with an operator-legible message when the lock is held by another live process', async () => {
33
- dbPath = tempDbPath();
34
- const config = testConfig(dbPath);
35
-
36
- const ctx = await initStack(config, logger);
37
- await ctx.queryWorker.close();
38
- await ctx.stack.close();
39
-
40
- // Simulate another still-running process holding the lock: process.ppid
41
- // is guaranteed alive (it's this test runner's own parent) and is never
42
- // this process's own pid, so the lock check's same-pid bypass can't mask
43
- // the scenario being tested.
44
- writeFileSync(`${dbPath}.lock`, JSON.stringify({ pid: process.ppid }));
45
-
46
- // Second call finds the db already exists (openOrInitialize's open path)
47
- // and hits the same lock check LocalAdapter.open() always enforced.
48
- await expect(initStack(config, logger)).rejects.toThrow(/in use by another process/);
49
- });
50
- });
51
-
52
- describe('initStack bootstrap', () => {
53
- let dbPath: string | undefined;
54
- afterEach(async () => {
55
- if (dbPath) await rm(dirname(dbPath), { recursive: true, force: true }).catch(() => {});
56
- });
57
-
58
- it('fails clearly when initializing a new database without ENTITY_ID', async () => {
59
- dbPath = tempDbPath();
60
- const config = { ...testConfig(dbPath), entityId: null };
61
-
62
- await expect(initStack(config, logger)).rejects.toThrow(
63
- /ENTITY_ID is required when initializing a new database/,
64
- );
65
- });
66
-
67
- it('opens an existing database fine without ENTITY_ID set', async () => {
68
- dbPath = tempDbPath();
69
- const config = testConfig(dbPath);
70
-
71
- const ctx = await initStack(config, logger);
72
- await ctx.queryWorker.close();
73
- await ctx.stack.close();
74
- await ctx.tokens.close();
75
- ctx.nonces.close();
76
-
77
- const reopened = await initStack({ ...config, entityId: null }, logger);
78
- expect(reopened.stack.ownerEntityId).toBe(config.entityId);
79
- await reopened.queryWorker.close();
80
- await reopened.stack.close();
81
- await reopened.tokens.close();
82
- reopened.nonces.close();
83
- });
84
-
85
- it('warns but does not fail when ENTITY_ID no longer matches the stored owner', async () => {
86
- dbPath = tempDbPath();
87
- const config = testConfig(dbPath);
88
-
89
- const ctx = await initStack(config, logger);
90
- await ctx.queryWorker.close();
91
- await ctx.stack.close();
92
- await ctx.tokens.close();
93
- ctx.nonces.close();
94
-
95
- const warn = spyLogger();
96
- const mismatched = await initStack({ ...config, entityId: OTHER_ENTITY_ID }, warn);
97
- expect(mismatched.stack.ownerEntityId).toBe(config.entityId);
98
- expect(warn.warn).toHaveBeenCalledWith(
99
- expect.objectContaining({
100
- configuredEntityId: OTHER_ENTITY_ID,
101
- storedOwnerEntityId: config.entityId,
102
- }),
103
- expect.stringMatching(/does not match/),
104
- );
105
- await mismatched.queryWorker.close();
106
- await mismatched.stack.close();
107
- await mismatched.tokens.close();
108
- mismatched.nonces.close();
109
- });
110
-
111
- it('does not register commons types when SEED_COMMONS_TYPES is unset', async () => {
112
- dbPath = tempDbPath();
113
- const config = testConfig(dbPath);
114
-
115
- const ctx = await initStack(config, logger);
116
- const types = await ctx.adapter.listTypes();
117
- expect(types.some((t) => t.id.startsWith('org.haverstack/'))).toBe(false);
118
- await ctx.queryWorker.close();
119
- await ctx.stack.close();
120
- await ctx.tokens.close();
121
- ctx.nonces.close();
122
- });
123
-
124
- it('registers all eight commons types when SEED_COMMONS_TYPES is set', async () => {
125
- dbPath = tempDbPath();
126
- const config = { ...testConfig(dbPath), seedCommonsTypes: true };
127
-
128
- const ctx = await initStack(config, logger);
129
- const types = await ctx.adapter.listTypes();
130
- const commonsIds = types.filter((t) => t.id.startsWith('org.haverstack/')).map((t) => t.id);
131
- expect(commonsIds.sort()).toEqual(
132
- [
133
- 'org.haverstack/article@1',
134
- 'org.haverstack/bookmark@1',
135
- 'org.haverstack/contact@1',
136
- 'org.haverstack/note@1',
137
- 'org.haverstack/page@1',
138
- 'org.haverstack/photo@1',
139
- 'org.haverstack/place@1',
140
- 'org.haverstack/task@1',
141
- ].sort(),
142
- );
143
- await ctx.queryWorker.close();
144
- await ctx.stack.close();
145
- await ctx.tokens.close();
146
- ctx.nonces.close();
147
- });
148
-
149
- it('re-seeding commons types on a later boot causes no createdAt churn', async () => {
150
- dbPath = tempDbPath();
151
- const config = { ...testConfig(dbPath), seedCommonsTypes: true };
152
-
153
- const first = await initStack(config, logger);
154
- const firstType = await first.adapter.getType('org.haverstack/note@1');
155
- await first.queryWorker.close();
156
- await first.stack.close();
157
- await first.tokens.close();
158
- first.nonces.close();
159
-
160
- const second = await initStack({ ...config, entityId: null }, logger);
161
- const secondType = await second.adapter.getType('org.haverstack/note@1');
162
- expect(secondType?.createdAt).toEqual(firstType?.createdAt);
163
- await second.queryWorker.close();
164
- await second.stack.close();
165
- await second.tokens.close();
166
- second.nonces.close();
167
- });
168
-
169
- it('creates the owner _entity record when OWNER_NAME is configured', async () => {
170
- dbPath = tempDbPath();
171
- const config = { ...testConfig(dbPath), ownerName: 'Jane Owner', ownerHandle: '@jane' };
172
-
173
- const ctx = await initStack(config, logger);
174
- const { records } = await ctx.stack.query({
175
- filter: { typeId: '_entity@1', content: { did: ctx.stack.ownerEntityId } },
176
- });
177
- expect(records[0]?.content).toMatchObject({ name: 'Jane Owner', handle: '@jane' });
178
- await ctx.queryWorker.close();
179
- await ctx.stack.close();
180
- await ctx.tokens.close();
181
- ctx.nonces.close();
182
- });
183
-
184
- it('creates no owner _entity record when OWNER_NAME is unset', async () => {
185
- dbPath = tempDbPath();
186
- const config = testConfig(dbPath);
187
-
188
- const ctx = await initStack(config, logger);
189
- const { records } = await ctx.stack.query({
190
- filter: { typeId: '_entity@1', content: { did: ctx.stack.ownerEntityId } },
191
- });
192
- expect(records).toHaveLength(0);
193
- await ctx.queryWorker.close();
194
- await ctx.stack.close();
195
- await ctx.tokens.close();
196
- ctx.nonces.close();
197
- });
198
- });
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist"
6
- },
7
- "include": ["src"],
8
- "exclude": ["node_modules", "dist", "tests"]
9
- }
package/tsconfig.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2022"],
7
- "outDir": "./dist",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "declaration": true,
12
- "declarationMap": true,
13
- "sourceMap": true,
14
- "forceConsistentCasingInFileNames": true,
15
- "resolveJsonModule": true
16
- },
17
- "include": ["src", "tests"],
18
- "exclude": ["node_modules", "dist"]
19
- }
package/vitest.config.ts DELETED
@@ -1,12 +0,0 @@
1
- import { defineConfig } from 'vitest/config';
2
-
3
- export default defineConfig({
4
- test: {
5
- globals: true,
6
- environment: 'node',
7
- coverage: {
8
- provider: 'v8',
9
- reporter: ['text', 'lcov'],
10
- },
11
- },
12
- });