toiljs 0.0.63 → 0.0.65
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/CHANGELOG.md +15 -0
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/routing/mount.js +3 -0
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/index.js +53 -1
- package/build/compiler/toil-docs.generated.js +4 -1
- package/build/devserver/.tsbuildinfo +1 -1
- package/build/devserver/db/catalog.js +1 -1
- package/build/devserver/runtime/module.d.ts +3 -0
- package/build/devserver/runtime/module.js +5 -7
- package/docs/daemon.md +123 -0
- package/docs/index.md +5 -1
- package/docs/streams.md +147 -0
- package/docs/tiers.md +127 -0
- package/package.json +2 -2
- package/scripts/gen-toil-docs.mjs +3 -0
- package/src/client/routing/mount.tsx +7 -0
- package/src/compiler/index.ts +68 -1
- package/src/compiler/toil-docs.generated.ts +4 -1
- package/src/devserver/db/catalog.ts +1 -1
- package/src/devserver/runtime/module.ts +12 -14
- package/test/devserver-database.test.ts +38 -2
|
@@ -51,6 +51,15 @@ function dbKindForHttpMethod(method: string): DbFunctionKind {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export function dbFunctionKindForRequest(
|
|
55
|
+
routes: readonly RouteKindEntry[],
|
|
56
|
+
method: string,
|
|
57
|
+
path: string,
|
|
58
|
+
): DbFunctionKind {
|
|
59
|
+
const routeKind = routeKindForRequest(routes, method, path);
|
|
60
|
+
return routeKind === DbFunctionKind.Query ? DbFunctionKind.Query : dbKindForHttpMethod(method);
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
/** The shaped outcome of one guest dispatch. */
|
|
55
64
|
export interface WasmDispatchResult {
|
|
56
65
|
readonly status: number;
|
|
@@ -186,20 +195,9 @@ export class WasmServerModule {
|
|
|
186
195
|
const ref: MemoryRef = { memory: null };
|
|
187
196
|
const state = freshDispatchState();
|
|
188
197
|
state.clientIp = req.clientIp ?? '';
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
// inferring a kind from the HTTP method and enforcing it would wrongly
|
|
193
|
-
// reject legitimate bounded reads (e.g. a GET that reads `events.latest`,
|
|
194
|
-
// a scan-class op denied in `Query`). With no declarations we keep the
|
|
195
|
-
// unenforced default (`Job`, see `freshDbState`).
|
|
196
|
-
const routeKind = routeKindForRequest(this.routeKinds, req.method, req.path);
|
|
197
|
-
state.db.functionKind =
|
|
198
|
-
this.routeKinds.length === 0
|
|
199
|
-
? DbFunctionKind.Job
|
|
200
|
-
: routeKind === DbFunctionKind.Query
|
|
201
|
-
? DbFunctionKind.Query
|
|
202
|
-
: dbKindForHttpMethod(req.method);
|
|
198
|
+
// Match the edge DB gate: the HTTP method is the baseline authority,
|
|
199
|
+
// and `toildb.route_kinds` can only tighten a mutating route to query.
|
|
200
|
+
state.db.functionKind = dbFunctionKindForRequest(this.routeKinds, req.method, req.path);
|
|
203
201
|
const instance = new WebAssembly.Instance(this.module, buildHostImports(ref, state));
|
|
204
202
|
const exports = instance.exports as unknown as HandleExports;
|
|
205
203
|
ref.memory = exports.memory;
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
setDbCatalog,
|
|
17
17
|
} from '../src/devserver/db/index.js';
|
|
18
18
|
import { parseRouteKinds, routeKindForRequest } from '../src/devserver/db/routeKinds.js';
|
|
19
|
+
import { dbFunctionKindForRequest } from '../src/devserver/runtime/module.js';
|
|
19
20
|
import type { MemoryRef } from '../src/devserver/runtime/host.js';
|
|
20
21
|
|
|
21
22
|
const DEFAULT_CATALOG = {
|
|
@@ -91,7 +92,7 @@ function routeKindsSection(routes: readonly (readonly [number, number, string])[
|
|
|
91
92
|
return Buffer.concat(chunks);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
function catalogSectionV2(fillMaxWaitMs: number, fillAllowStale: number): Buffer {
|
|
95
|
+
function catalogSectionV2(fillMaxWaitMs: number, fillAllowStale: number, replication = 5): Buffer {
|
|
95
96
|
const chunks: Buffer[] = [];
|
|
96
97
|
const u8 = (v: number) => chunks.push(Buffer.from([v & 0xff]));
|
|
97
98
|
const u16 = (v: number) => {
|
|
@@ -121,7 +122,7 @@ function catalogSectionV2(fillMaxWaitMs: number, fillAllowStale: number): Buffer
|
|
|
121
122
|
u32(0xaaaa);
|
|
122
123
|
u32(0x1234);
|
|
123
124
|
u32(0); // generation
|
|
124
|
-
u8(
|
|
125
|
+
u8(replication); // replication
|
|
125
126
|
u8(0); // placement = hashKey
|
|
126
127
|
u32(fillMaxWaitMs);
|
|
127
128
|
u8(fillAllowStale);
|
|
@@ -151,6 +152,31 @@ describe('toildb dev emulator (record family)', () => {
|
|
|
151
152
|
expect(routeKindForRequest(routes, 'POST', '/api/items')).toBeNull();
|
|
152
153
|
});
|
|
153
154
|
|
|
155
|
+
it('matches the edge method clamp when route-kind metadata is absent', () => {
|
|
156
|
+
expect(dbFunctionKindForRequest([], 'GET', '/api/users')).toBe(DbFunctionKind.Query);
|
|
157
|
+
expect(dbFunctionKindForRequest([], 'HEAD', '/api/users')).toBe(DbFunctionKind.Query);
|
|
158
|
+
expect(dbFunctionKindForRequest([], 'OPTIONS', '/api/users')).toBe(DbFunctionKind.Query);
|
|
159
|
+
expect(dbFunctionKindForRequest([], 'POST', '/api/users')).toBe(DbFunctionKind.Action);
|
|
160
|
+
expect(dbFunctionKindForRequest([], 'PUT', '/api/users')).toBe(DbFunctionKind.Action);
|
|
161
|
+
expect(dbFunctionKindForRequest([], 'PATCH', '/api/users')).toBe(DbFunctionKind.Action);
|
|
162
|
+
expect(dbFunctionKindForRequest([], 'DELETE', '/api/users')).toBe(DbFunctionKind.Action);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('uses route-kind metadata only to tighten mutating routes to query', () => {
|
|
166
|
+
const wasm = wasmWithSection(
|
|
167
|
+
'toildb.route_kinds',
|
|
168
|
+
routeKindsSection([
|
|
169
|
+
[1, 0, '/api/search'],
|
|
170
|
+
[0, 1, '/api/users'],
|
|
171
|
+
]),
|
|
172
|
+
);
|
|
173
|
+
const routes = parseRouteKinds(wasm);
|
|
174
|
+
|
|
175
|
+
expect(dbFunctionKindForRequest(routes, 'POST', '/api/search')).toBe(DbFunctionKind.Query);
|
|
176
|
+
expect(dbFunctionKindForRequest(routes, 'POST', '/api/write')).toBe(DbFunctionKind.Action);
|
|
177
|
+
expect(dbFunctionKindForRequest(routes, 'GET', '/api/users')).toBe(DbFunctionKind.Query);
|
|
178
|
+
});
|
|
179
|
+
|
|
154
180
|
it('ignores malformed route-kind metadata like the edge method clamp fallback', () => {
|
|
155
181
|
expect(
|
|
156
182
|
parseRouteKinds(wasmWithSection('toildb.route_kinds', Buffer.from([1, 0, 1, 0, 1]))),
|
|
@@ -205,6 +231,16 @@ describe('toildb dev emulator (record family)', () => {
|
|
|
205
231
|
});
|
|
206
232
|
});
|
|
207
233
|
|
|
234
|
+
it('rejects replication policies that require catalog v3 metadata', () => {
|
|
235
|
+
for (const replication of [3, 4]) {
|
|
236
|
+
setDbCatalog(wasmWithSection('toildb.catalog', catalogSectionV2(7, 0, replication)));
|
|
237
|
+
const { imports, buf } = setupRaw();
|
|
238
|
+
const [p, l] = put(buf, 0, 'App/users');
|
|
239
|
+
|
|
240
|
+
expect(imports['data.resolve_collection'](p, l, 16)).toBe(-1070);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
208
244
|
it('rejects malformed catalog v2 fill policy', () => {
|
|
209
245
|
setDbCatalog(wasmWithSection('toildb.catalog', catalogSectionV2(7, 2)));
|
|
210
246
|
const { imports, buf } = setupRaw();
|