spacetimedb 2.3.0 → 2.4.0

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 (59) hide show
  1. package/LICENSE.txt +2 -2
  2. package/dist/index.browser.mjs +50 -4
  3. package/dist/index.browser.mjs.map +1 -1
  4. package/dist/index.cjs +50 -4
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.mjs +50 -4
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/lib/autogen/types.d.ts +674 -18
  9. package/dist/lib/autogen/types.d.ts.map +1 -1
  10. package/dist/lib/schema.d.ts.map +1 -1
  11. package/dist/min/index.browser.mjs +1 -1
  12. package/dist/min/index.browser.mjs.map +1 -1
  13. package/dist/min/sdk/index.browser.mjs +1 -1
  14. package/dist/min/sdk/index.browser.mjs.map +1 -1
  15. package/dist/sdk/decompress.d.ts.map +1 -1
  16. package/dist/sdk/index.browser.mjs +50 -4
  17. package/dist/sdk/index.browser.mjs.map +1 -1
  18. package/dist/sdk/index.cjs +50 -4
  19. package/dist/sdk/index.cjs.map +1 -1
  20. package/dist/sdk/index.mjs +50 -4
  21. package/dist/sdk/index.mjs.map +1 -1
  22. package/dist/server/http.d.ts +1 -2
  23. package/dist/server/http.d.ts.map +1 -1
  24. package/dist/server/http.test-d.d.ts +2 -0
  25. package/dist/server/http.test-d.d.ts.map +1 -0
  26. package/dist/server/http_handlers.d.ts +82 -0
  27. package/dist/server/http_handlers.d.ts.map +1 -0
  28. package/dist/server/http_internal.d.ts +1 -32
  29. package/dist/server/http_internal.d.ts.map +1 -1
  30. package/dist/server/http_shared.d.ts +44 -0
  31. package/dist/server/http_shared.d.ts.map +1 -0
  32. package/dist/server/index.d.ts +2 -0
  33. package/dist/server/index.d.ts.map +1 -1
  34. package/dist/server/index.mjs +582 -134
  35. package/dist/server/index.mjs.map +1 -1
  36. package/dist/server/runtime.d.ts +1 -0
  37. package/dist/server/runtime.d.ts.map +1 -1
  38. package/dist/server/schema.d.ts +16 -1
  39. package/dist/server/schema.d.ts.map +1 -1
  40. package/dist/server/views.d.ts.map +1 -1
  41. package/package.json +1 -1
  42. package/src/lib/autogen/types.ts +29 -0
  43. package/src/lib/schema.ts +14 -0
  44. package/src/sdk/decompress.ts +19 -4
  45. package/src/sdk/logger.ts +1 -1
  46. package/src/server/http.test-d.ts +80 -0
  47. package/src/server/http.ts +14 -2
  48. package/src/server/http_handlers.ts +413 -0
  49. package/src/server/http_internal.ts +15 -142
  50. package/src/server/http_shared.ts +186 -0
  51. package/src/server/index.ts +11 -0
  52. package/src/server/procedures.ts +8 -30
  53. package/src/server/runtime.ts +137 -1
  54. package/src/server/schema.ts +71 -2
  55. package/src/server/sys.d.ts +7 -0
  56. package/src/server/views.ts +1 -0
  57. package/dist/lib/http_types.d.ts +0 -2
  58. package/dist/lib/http_types.d.ts.map +0 -1
  59. package/src/lib/http_types.ts +0 -8
@@ -0,0 +1,186 @@
1
+ import { Headers, headersToList } from 'headers-polyfill';
2
+ import type {
3
+ HttpHeaders,
4
+ HttpMethod,
5
+ HttpVersion,
6
+ } from '../lib/autogen/types';
7
+
8
+ export { Headers };
9
+
10
+ export type BodyInit = ArrayBuffer | ArrayBufferView | string;
11
+ export type HeadersInit = [string, string][] | Record<string, string> | Headers;
12
+
13
+ export const textEncoder = new TextEncoder();
14
+ export const textDecoder = new TextDecoder('utf-8');
15
+
16
+ export function deserializeMethod(method: HttpMethod): string {
17
+ switch (method.tag) {
18
+ case 'Get':
19
+ return 'GET';
20
+ case 'Head':
21
+ return 'HEAD';
22
+ case 'Post':
23
+ return 'POST';
24
+ case 'Put':
25
+ return 'PUT';
26
+ case 'Delete':
27
+ return 'DELETE';
28
+ case 'Connect':
29
+ return 'CONNECT';
30
+ case 'Options':
31
+ return 'OPTIONS';
32
+ case 'Trace':
33
+ return 'TRACE';
34
+ case 'Patch':
35
+ return 'PATCH';
36
+ case 'Extension':
37
+ return method.value;
38
+ }
39
+ }
40
+
41
+ const methods = new Map<string, HttpMethod>([
42
+ ['GET', { tag: 'Get' }],
43
+ ['HEAD', { tag: 'Head' }],
44
+ ['POST', { tag: 'Post' }],
45
+ ['PUT', { tag: 'Put' }],
46
+ ['DELETE', { tag: 'Delete' }],
47
+ ['CONNECT', { tag: 'Connect' }],
48
+ ['OPTIONS', { tag: 'Options' }],
49
+ ['TRACE', { tag: 'Trace' }],
50
+ ['PATCH', { tag: 'Patch' }],
51
+ ]);
52
+
53
+ export function serializeMethod(method?: string): HttpMethod {
54
+ return (
55
+ methods.get(method?.toUpperCase() ?? 'GET') ?? {
56
+ tag: 'Extension',
57
+ value: method!,
58
+ }
59
+ );
60
+ }
61
+
62
+ export function serializeHeaders(headers: Headers): HttpHeaders {
63
+ return {
64
+ entries: headersToList(headers as any)
65
+ .flatMap(([k, v]) => (Array.isArray(v) ? v.map(v => [k, v]) : [[k, v]]))
66
+ .map(([name, value]) => ({ name, value: textEncoder.encode(value) })),
67
+ };
68
+ }
69
+
70
+ export function deserializeHeaders(headers: HttpHeaders): Headers {
71
+ return new Headers(
72
+ headers.entries.map(({ name, value }): [string, string] => [
73
+ name,
74
+ textDecoder.decode(value),
75
+ ])
76
+ );
77
+ }
78
+
79
+ export interface ResponseInit {
80
+ headers?: HeadersInit;
81
+ status?: number;
82
+ statusText?: string;
83
+ version?: HttpVersion;
84
+ }
85
+
86
+ export interface InnerResponse {
87
+ type: 'basic' | 'cors' | 'default' | 'error' | 'opaque' | 'opaqueredirect';
88
+ url: string | null;
89
+ status: number;
90
+ statusText: string;
91
+ headers: Headers;
92
+ aborted: boolean;
93
+ version: HttpVersion;
94
+ }
95
+
96
+ export const makeResponse = Symbol('makeResponse');
97
+
98
+ export class SyncResponse {
99
+ #body: string | ArrayBuffer | null;
100
+ #inner: InnerResponse;
101
+
102
+ constructor(body?: BodyInit | null, init?: ResponseInit) {
103
+ if (body == null) {
104
+ this.#body = null;
105
+ } else if (typeof body === 'string') {
106
+ this.#body = body;
107
+ } else {
108
+ // this call is fine, the typings are just weird
109
+ this.#body = new Uint8Array<ArrayBuffer>(body as any).buffer;
110
+ }
111
+
112
+ // there's a type mismatch - headers-polyfill's typing doesn't expect its
113
+ // own `Headers` type, even though the actual code handles it correctly.
114
+ this.#inner = {
115
+ headers: new Headers(init?.headers as any),
116
+ status: init?.status ?? 200,
117
+ statusText: init?.statusText ?? '',
118
+ type: 'default',
119
+ url: null,
120
+ aborted: false,
121
+ version: init?.version ?? { tag: 'Http11' },
122
+ };
123
+ }
124
+
125
+ static [makeResponse](body: BodyInit | null, inner: InnerResponse) {
126
+ const me = new SyncResponse(body);
127
+ me.#inner = inner;
128
+ return me;
129
+ }
130
+
131
+ get headers(): Headers {
132
+ return this.#inner.headers;
133
+ }
134
+
135
+ get status(): number {
136
+ return this.#inner.status;
137
+ }
138
+
139
+ get statusText() {
140
+ return this.#inner.statusText;
141
+ }
142
+
143
+ get ok(): boolean {
144
+ return 200 <= this.#inner.status && this.#inner.status <= 299;
145
+ }
146
+
147
+ get url(): string {
148
+ return this.#inner.url ?? '';
149
+ }
150
+
151
+ get type() {
152
+ return this.#inner.type;
153
+ }
154
+
155
+ get version(): HttpVersion {
156
+ return this.#inner.version;
157
+ }
158
+
159
+ arrayBuffer(): ArrayBuffer {
160
+ return this.bytes().buffer;
161
+ }
162
+
163
+ bytes(): Uint8Array<ArrayBuffer> {
164
+ if (this.#body == null) {
165
+ return new Uint8Array();
166
+ } else if (typeof this.#body === 'string') {
167
+ return textEncoder.encode(this.#body);
168
+ } else {
169
+ return new Uint8Array(this.#body);
170
+ }
171
+ }
172
+
173
+ json(): any {
174
+ return JSON.parse(this.text());
175
+ }
176
+
177
+ text(): string {
178
+ if (this.#body == null) {
179
+ return '';
180
+ } else if (typeof this.#body === 'string') {
181
+ return this.#body;
182
+ } else {
183
+ return textDecoder.decode(this.#body);
184
+ }
185
+ }
186
+ }
@@ -22,5 +22,16 @@ export type { Uuid } from '../lib/uuid';
22
22
  export type { Random } from './rng';
23
23
  export type { ViewExport, ViewCtx, AnonymousViewCtx } from './views';
24
24
  export { Range, type Bound } from './range';
25
+ export {
26
+ Headers,
27
+ Request,
28
+ SyncResponse,
29
+ Router,
30
+ type BodyInit,
31
+ type HeadersInit,
32
+ type RequestInit,
33
+ type ResponseInit,
34
+ } from './http';
35
+ export type { HandlerContext, HttpHandlerExport } from './http';
25
36
 
26
37
  import './polyfills'; // Ensure polyfills are loaded
@@ -22,7 +22,7 @@ import { Uuid } from '../lib/uuid';
22
22
  import { httpClient, type HttpClient } from './http_internal';
23
23
  import type { DbView } from './db_view';
24
24
  import { makeRandom, type Random } from './rng';
25
- import { callUserFunction, ReducerCtxImpl, sys } from './runtime';
25
+ import { callUserFunction, ReducerCtxImpl, runWithTx, sys } from './runtime';
26
26
  import {
27
27
  exportContext,
28
28
  registerExport,
@@ -214,38 +214,16 @@ const ProcedureCtxImpl = class ProcedureCtx<S extends UntypedSchemaDef>
214
214
  }
215
215
 
216
216
  withTx<T>(body: (ctx: TransactionCtx<S>) => T): T {
217
- const run = () => {
218
- const timestamp = sys.procedure_start_mut_tx();
219
-
220
- try {
221
- const ctx: TransactionCtx<S> = new TransactionCtxImpl(
217
+ return runWithTx(
218
+ timestamp =>
219
+ new TransactionCtxImpl(
222
220
  this.sender,
223
- new Timestamp(timestamp),
221
+ timestamp,
224
222
  this.connectionId,
225
223
  this.#dbView()
226
- );
227
- return body(ctx);
228
- } catch (e) {
229
- sys.procedure_abort_mut_tx();
230
- throw e;
231
- }
232
- };
233
-
234
- let res = run();
235
- try {
236
- sys.procedure_commit_mut_tx();
237
- return res;
238
- } catch {
239
- // ignore the commit error
240
- }
241
- console.warn('committing anonymous transaction failed');
242
- res = run();
243
- try {
244
- sys.procedure_commit_mut_tx();
245
- return res;
246
- } catch (e) {
247
- throw new Error('transaction retry failed again', { cause: e });
248
- }
224
+ ) as TransactionCtx<S>,
225
+ body
226
+ );
249
227
  }
250
228
 
251
229
  newUuidV4(): Uuid {
@@ -27,6 +27,18 @@ import {
27
27
  type UniqueIndex,
28
28
  } from '../lib/indexes';
29
29
  import { callProcedure } from './procedures';
30
+ import {
31
+ type HandlerContext,
32
+ Request,
33
+ SyncResponse,
34
+ makeRequest,
35
+ } from './http_handlers';
36
+ import { httpClient } from './http_internal';
37
+ import {
38
+ deserializeHeaders,
39
+ deserializeMethod,
40
+ serializeHeaders,
41
+ } from './http_shared';
30
42
  import {
31
43
  type AuthCtx,
32
44
  type JsonObject,
@@ -35,7 +47,7 @@ import {
35
47
  } from '../lib/reducers';
36
48
  import { type UntypedSchemaDef } from '../lib/schema';
37
49
  import { type RowType, type Table, type TableMethods } from '../lib/table';
38
- import { hasOwn } from '../lib/util';
50
+ import { bsatnBaseSize, hasOwn } from '../lib/util';
39
51
  import { type AnonymousViewCtx, type ViewCtx } from './views';
40
52
  import { isRowTypedQuery, makeQueryBuilder, toSql } from './query';
41
53
  import type { DbView } from './db_view';
@@ -43,11 +55,32 @@ import { getErrorConstructor, SenderError } from './errors';
43
55
  import { Range, type Bound } from './range';
44
56
  import { makeRandom, type Random } from './rng';
45
57
  import type { SchemaInner } from './schema';
58
+ import { HttpRequest, HttpResponse } from '../lib/autogen/types';
46
59
 
47
60
  const { freeze } = Object;
48
61
 
49
62
  export const sys = { ..._syscalls2_0, ..._syscalls2_1 };
50
63
 
64
+ function requestFromWire(request: HttpRequest, body: Uint8Array): Request {
65
+ return Request[makeRequest](body, {
66
+ headers: deserializeHeaders(request.headers),
67
+ method: deserializeMethod(request.method),
68
+ uri: request.uri,
69
+ version: request.version,
70
+ });
71
+ }
72
+
73
+ function responseIntoWire(response: SyncResponse): [HttpResponse, Uint8Array] {
74
+ return [
75
+ {
76
+ headers: serializeHeaders(response.headers),
77
+ version: response.version,
78
+ code: response.status,
79
+ },
80
+ response.bytes(),
81
+ ];
82
+ }
83
+
51
84
  export function parseJsonObject(json: string): JsonObject {
52
85
  let value: unknown;
53
86
 
@@ -272,6 +305,38 @@ export const callUserFunction = function __spacetimedb_end_short_backtrace<
272
305
  return fn(...args);
273
306
  };
274
307
 
308
+ export function runWithTx<T, Ctx>(
309
+ makeCtx: (timestamp: Timestamp) => Ctx,
310
+ body: (ctx: Ctx) => T
311
+ ): T {
312
+ const run = () => {
313
+ const timestamp = sys.procedure_start_mut_tx();
314
+
315
+ try {
316
+ return body(makeCtx(new Timestamp(timestamp)));
317
+ } catch (e) {
318
+ sys.procedure_abort_mut_tx();
319
+ throw e;
320
+ }
321
+ };
322
+
323
+ let res = run();
324
+ try {
325
+ sys.procedure_commit_mut_tx();
326
+ return res;
327
+ } catch {
328
+ // ignore the commit error
329
+ }
330
+ console.warn('committing anonymous transaction failed');
331
+ res = run();
332
+ try {
333
+ sys.procedure_commit_mut_tx();
334
+ return res;
335
+ } catch (e) {
336
+ throw new Error('transaction retry failed again', { cause: e });
337
+ }
338
+ }
339
+
275
340
  export const makeHooks = (schema: SchemaInner): ModuleHooks =>
276
341
  new ModuleHooksImpl(schema);
277
342
 
@@ -418,11 +483,82 @@ class ModuleHooksImpl implements ModuleHooks {
418
483
  () => this.#dbView
419
484
  );
420
485
  }
486
+
487
+ __call_http_handler__(
488
+ id: u32,
489
+ timestamp: bigint,
490
+ request: Uint8Array,
491
+ body: Uint8Array
492
+ ): [response: Uint8Array, body: Uint8Array] {
493
+ const moduleCtx = this.#schema;
494
+ const handler = moduleCtx.httpHandlers[id];
495
+ const ctx = new HandlerContextImpl(
496
+ new Timestamp(timestamp),
497
+ () => this.#dbView
498
+ );
499
+ const requestMetadata = HttpRequest.deserialize(new BinaryReader(request));
500
+ const response = callUserFunction(
501
+ handler,
502
+ ctx,
503
+ requestFromWire(requestMetadata, body)
504
+ );
505
+ const [responseMetadata, responseBody] = responseIntoWire(response);
506
+ const responseBuf = new BinaryWriter(
507
+ bsatnBaseSize(moduleCtx.typespace, HttpResponse.algebraicType)
508
+ );
509
+ HttpResponse.serialize(responseBuf, responseMetadata);
510
+ return [responseBuf.getBuffer(), responseBody];
511
+ }
421
512
  }
422
513
 
423
514
  const BINARY_WRITER = new BinaryWriter(0);
424
515
  const BINARY_READER = new BinaryReader(new Uint8Array());
425
516
 
517
+ class HandlerContextImpl<S extends UntypedSchemaDef = UntypedSchemaDef>
518
+ implements HandlerContext<S>
519
+ {
520
+ #identity: Identity | undefined;
521
+ #uuidCounter: { value: number } | undefined;
522
+ #random: Random | undefined;
523
+ #dbView: () => DbView<any>;
524
+
525
+ readonly http = httpClient;
526
+
527
+ constructor(
528
+ readonly timestamp: Timestamp,
529
+ dbView: () => DbView<any>
530
+ ) {
531
+ this.#dbView = dbView;
532
+ }
533
+
534
+ get identity() {
535
+ return (this.#identity ??= new Identity(sys.identity()));
536
+ }
537
+
538
+ get random() {
539
+ return (this.#random ??= makeRandom(this.timestamp));
540
+ }
541
+
542
+ withTx<T>(body: (ctx: any) => T): T {
543
+ return runWithTx(
544
+ timestamp =>
545
+ new ReducerCtxImpl(Identity.zero(), timestamp, null, this.#dbView()),
546
+ body
547
+ );
548
+ }
549
+
550
+ newUuidV4(): Uuid {
551
+ const bytes = this.random.fill(new Uint8Array(16));
552
+ return Uuid.fromRandomBytesV4(bytes);
553
+ }
554
+
555
+ newUuidV7(): Uuid {
556
+ const bytes = this.random.fill(new Uint8Array(4));
557
+ const counter = (this.#uuidCounter ??= { value: 0 });
558
+ return Uuid.fromCounterV7(counter, this.timestamp, bytes);
559
+ }
560
+ }
561
+
426
562
  function makeTableView(
427
563
  typespace: Typespace,
428
564
  table: RawTableDefV10
@@ -1,5 +1,9 @@
1
1
  import { moduleHooks, type ModuleDefaultExport } from 'spacetime:sys@2.0';
2
- import { CaseConversionPolicy, Lifecycle } from '../lib/autogen/types';
2
+ import {
3
+ CaseConversionPolicy,
4
+ Lifecycle,
5
+ type MethodOrAny,
6
+ } from '../lib/autogen/types';
3
7
  import {
4
8
  type ParamsAsObject,
5
9
  type ParamsObj,
@@ -14,6 +18,14 @@ import {
14
18
  } from '../lib/schema';
15
19
  import type { UntypedTableSchema } from '../lib/table_schema';
16
20
  import { ColumnBuilder, TypeBuilder } from '../lib/type_builders';
21
+ import {
22
+ Router,
23
+ type HandlerFn,
24
+ type HttpHandlerExport,
25
+ type HttpHandlerOpts,
26
+ makeHttpHandlerExport,
27
+ makeHttpRouterExport,
28
+ } from './http_handlers';
17
29
  import {
18
30
  makeProcedureExport,
19
31
  type ProcedureExport,
@@ -47,10 +59,12 @@ export class SchemaInner<
47
59
  > extends ModuleContext {
48
60
  schemaType: S;
49
61
  existingFunctions = new Set<string>();
62
+ existingHttpHandlers = new Set<string>();
50
63
  reducers: Reducers = [];
51
64
  procedures: Procedures = [];
52
65
  views: Views = [];
53
66
  anonViews: AnonViews = [];
67
+ httpHandlers: HandlerFn[] = [];
54
68
  /**
55
69
  * Maps ReducerExport objects to the name of the reducer.
56
70
  * Used for resolving the reducers of scheduled tables.
@@ -60,7 +74,10 @@ export class SchemaInner<
60
74
  | ProcedureExport<UntypedSchemaDef, any, any>,
61
75
  string
62
76
  > = new Map();
77
+ httpHandlerExports: Map<HttpHandlerExport<UntypedSchemaDef>, string> =
78
+ new Map();
63
79
  pendingSchedules: PendingSchedule[] = [];
80
+ pendingHttpRoutes: PendingHttpRoute[] = [];
64
81
 
65
82
  constructor(getSchemaType: (ctx: SchemaInner<S>) => S) {
66
83
  super();
@@ -70,12 +87,21 @@ export class SchemaInner<
70
87
  defineFunction(name: string) {
71
88
  if (this.existingFunctions.has(name)) {
72
89
  throw new TypeError(
73
- `There is already a reducer or procedure with the name '${name}'`
90
+ `There is already a reducer, procedure, or view with the name '${name}'`
74
91
  );
75
92
  }
76
93
  this.existingFunctions.add(name);
77
94
  }
78
95
 
96
+ defineHttpHandler(name: string) {
97
+ if (this.existingHttpHandlers.has(name)) {
98
+ throw new TypeError(
99
+ `There is already an HTTP handler with the name '${name}'`
100
+ );
101
+ }
102
+ this.existingHttpHandlers.add(name);
103
+ }
104
+
79
105
  resolveSchedules() {
80
106
  for (const { reducer, scheduleAtCol, tableName } of this.pendingSchedules) {
81
107
  const functionName = this.functionExports.get(reducer());
@@ -91,9 +117,30 @@ export class SchemaInner<
91
117
  });
92
118
  }
93
119
  }
120
+
121
+ resolveHttpRoutes() {
122
+ for (const route of this.pendingHttpRoutes) {
123
+ const handlerFunction = this.httpHandlerExports.get(route.handler);
124
+ if (handlerFunction === undefined) {
125
+ throw new TypeError(
126
+ `HTTP route for path '${route.path}' refers to a handler that was not exported.`
127
+ );
128
+ }
129
+ this.moduleDef.httpRoutes.push({
130
+ handlerFunction,
131
+ method: route.method,
132
+ path: route.path,
133
+ });
134
+ }
135
+ }
94
136
  }
95
137
 
96
138
  type PendingSchedule = UntypedTableSchema['schedule'] & { tableName: string };
139
+ type PendingHttpRoute = {
140
+ handler: HttpHandlerExport<UntypedSchemaDef>;
141
+ method: MethodOrAny;
142
+ path: string;
143
+ };
97
144
 
98
145
  /**
99
146
  * The Schema class represents the database schema for a SpacetimeDB application.
@@ -153,6 +200,7 @@ export class Schema<S extends UntypedSchemaDef> implements ModuleDefaultExport {
153
200
  moduleExport[registerExport](registeredSchema, name);
154
201
  }
155
202
  registeredSchema.resolveSchedules();
203
+ registeredSchema.resolveHttpRoutes();
156
204
  return makeHooks(registeredSchema);
157
205
  }
158
206
 
@@ -458,6 +506,27 @@ export class Schema<S extends UntypedSchemaDef> implements ModuleDefaultExport {
458
506
  return makeProcedureExport(this.#ctx, opts, params, ret, fn);
459
507
  }
460
508
 
509
+ httpHandler(fn: HandlerFn<S>): HttpHandlerExport<S>;
510
+ httpHandler(opts: HttpHandlerOpts, fn: HandlerFn<S>): HttpHandlerExport<S>;
511
+ httpHandler(
512
+ ...args: [HandlerFn<S>] | [HttpHandlerOpts, HandlerFn<S>]
513
+ ): HttpHandlerExport<S> {
514
+ let opts: HttpHandlerOpts | undefined, fn: HandlerFn<S>;
515
+ switch (args.length) {
516
+ case 1:
517
+ [fn] = args;
518
+ break;
519
+ case 2:
520
+ [opts, fn] = args;
521
+ break;
522
+ }
523
+ return makeHttpHandlerExport(this.#ctx, opts, fn);
524
+ }
525
+
526
+ httpRouter(router: Router): ModuleExport {
527
+ return makeHttpRouterExport(this.#ctx, router);
528
+ }
529
+
461
530
  /**
462
531
  * Bundle multiple reducers, procedures, etc into one value to export.
463
532
  * The name they will be exported with is their corresponding key in the `exports` argument.
@@ -37,6 +37,13 @@ declare module 'spacetime:sys@2.0' {
37
37
  timestamp: bigint,
38
38
  args: Uint8Array
39
39
  ): Uint8Array;
40
+
41
+ __call_http_handler__(
42
+ id: u32,
43
+ timestamp: bigint,
44
+ request: Uint8Array,
45
+ body: Uint8Array
46
+ ): [response: Uint8Array, body: Uint8Array];
40
47
  }
41
48
 
42
49
  export function register_hooks(hooks: ModuleHooks);
@@ -143,6 +143,7 @@ export function registerView<
143
143
  ? AnonymousViewFn<S, Params, Ret>
144
144
  : ViewFn<S, Params, Ret>
145
145
  ) {
146
+ ctx.defineFunction(exportName);
146
147
  const paramsBuilder = new RowBuilder(params, toPascalCase(exportName));
147
148
 
148
149
  // Register return types if they are product types
@@ -1,2 +0,0 @@
1
- export { HttpHeaderPair, HttpHeaders, HttpMethod, HttpRequest, HttpResponse, HttpVersion, } from './autogen/types';
2
- //# sourceMappingURL=http_types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http_types.d.ts","sourceRoot":"","sources":["../../src/lib/http_types.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,WAAW,EACX,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,MAAM,iBAAiB,CAAC"}
@@ -1,8 +0,0 @@
1
- export {
2
- HttpHeaderPair,
3
- HttpHeaders,
4
- HttpMethod,
5
- HttpRequest,
6
- HttpResponse,
7
- HttpVersion,
8
- } from './autogen/types';