cloesce 0.0.4-unstable.7 → 0.0.4-unstable.9
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/README.md +23 -10
- package/dist/cli.js +2 -3
- package/dist/common.d.ts +1 -94
- package/dist/common.d.ts.map +1 -1
- package/dist/common.js +0 -105
- package/dist/extractor/extract.d.ts.map +1 -1
- package/dist/extractor/extract.js +20 -7
- package/dist/generator.wasm +0 -0
- package/dist/orm.wasm +0 -0
- package/dist/router/router.d.ts +71 -15
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/router.js +170 -77
- package/dist/ui/backend.d.ts +5 -6
- package/dist/ui/backend.d.ts.map +1 -1
- package/dist/ui/backend.js +22 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Internal documentation going over design decisions and general thoughts for each
|
|
|
17
17
|
Create an NPM project and install cloesce
|
|
18
18
|
|
|
19
19
|
```sh
|
|
20
|
-
npm i cloesce@0.0.4-unstable.
|
|
20
|
+
npm i cloesce@0.0.4-unstable.9
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
### 2) TypeScript
|
|
@@ -70,6 +70,8 @@ export default defineConfig({
|
|
|
70
70
|
});
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Middleware support for CORS is also supported (see Middleware section).
|
|
74
|
+
|
|
73
75
|
### 5) Wrangler Config
|
|
74
76
|
|
|
75
77
|
Cloesce will generate any missing `wrangler.toml` values (or the file if missing). A minimal `wrangler.toml` looks like this:
|
|
@@ -445,7 +447,7 @@ class Horse {
|
|
|
445
447
|
await orm.list(
|
|
446
448
|
Horse,
|
|
447
449
|
Horse.default,
|
|
448
|
-
"SELECT * FROM Horse ORDER BY name LIMIT 10"
|
|
450
|
+
"SELECT * FROM Horse ORDER BY name LIMIT 10",
|
|
449
451
|
);
|
|
450
452
|
```
|
|
451
453
|
|
|
@@ -488,11 +490,11 @@ static async get(
|
|
|
488
490
|
|
|
489
491
|
### Middleware
|
|
490
492
|
|
|
491
|
-
Cloesce supports middleware at the global level (before routing to a model+method), the model level (before
|
|
493
|
+
Cloesce supports middleware at the global level (before routing to a model+method), the model level (before validation) and the method level (before hydration). Middleware also exposes read/write access to the dependency injection instance that all models use.
|
|
492
494
|
|
|
493
495
|
Middleware is capable of exiting from the Cloesce Router early with an HTTP Result.
|
|
494
496
|
|
|
495
|
-
An example of all levels of middleware is below. All middleware must be defined in the file `app.cloesce.ts
|
|
497
|
+
An example of all levels of middleware is below. All middleware must be defined in the file `app.cloesce.ts` which exports a `CloesceApp` instance as default.
|
|
496
498
|
|
|
497
499
|
```ts
|
|
498
500
|
@PlainOldObject
|
|
@@ -520,30 +522,41 @@ export class Model {
|
|
|
520
522
|
}
|
|
521
523
|
}
|
|
522
524
|
|
|
523
|
-
// Middleware instance
|
|
524
525
|
const app: CloesceApp = new CloesceApp();
|
|
525
526
|
|
|
526
|
-
app.
|
|
527
|
+
app.onRequest((request: Request, env, ir) => {
|
|
527
528
|
if (request.method === "POST") {
|
|
528
529
|
return { ok: false, status: 401, message: "POST methods aren't allowed." };
|
|
529
530
|
}
|
|
530
531
|
});
|
|
531
532
|
|
|
532
|
-
app.
|
|
533
|
+
app.onModel(Model, (request, env, ir) => {
|
|
533
534
|
ir.set(InjectedThing.name, {
|
|
534
535
|
value: "hello world",
|
|
535
536
|
});
|
|
536
537
|
});
|
|
537
538
|
|
|
538
|
-
app.
|
|
539
|
+
app.onMethod(Model, "blockedMethod", (request, env, ir) => {
|
|
539
540
|
return { ok: false, status: 401, message: "Blocked method" };
|
|
540
541
|
});
|
|
541
542
|
|
|
542
|
-
|
|
543
|
+
app.onResponse(async (request, env, di, response: Response) => {
|
|
544
|
+
// basic CORS, allow all origins
|
|
545
|
+
response.headers.set("Access-Control-Allow-Origin", "*");
|
|
546
|
+
response.headers.set(
|
|
547
|
+
"Access-Control-Allow-Methods",
|
|
548
|
+
"GET, POST, PUT, DELETE, OPTIONS",
|
|
549
|
+
);
|
|
550
|
+
response.headers.set(
|
|
551
|
+
"Access-Control-Allow-Headers",
|
|
552
|
+
"Content-Type, Authorization",
|
|
553
|
+
);
|
|
554
|
+
});
|
|
555
|
+
|
|
543
556
|
export default app;
|
|
544
557
|
```
|
|
545
558
|
|
|
546
|
-
With this middleware, all POST methods will be blocked, and all methods for the model `Model` will be able to inject `InjectedThing
|
|
559
|
+
With this middleware, all POST methods will be blocked, and all methods for the model `Model` will be able to inject `InjectedThing`,and `blockedMethod` will return a 401. Additionally, all responses will have CORS headers.
|
|
547
560
|
|
|
548
561
|
### Plain Old Objects
|
|
549
562
|
|
package/dist/cli.js
CHANGED
|
@@ -22,8 +22,8 @@ const cmds = subcommands({
|
|
|
22
22
|
},
|
|
23
23
|
handler: async (args) => {
|
|
24
24
|
const config = loadCloesceConfig(process.cwd(), args.debug);
|
|
25
|
-
if (!config.workersUrl
|
|
26
|
-
console.error("Error: `workersUrl
|
|
25
|
+
if (!config.workersUrl) {
|
|
26
|
+
console.error("Error: `workersUrl`` must be defined in cloesce.config.json");
|
|
27
27
|
process.exit(1);
|
|
28
28
|
}
|
|
29
29
|
// Creates a `cidl.json` file. Exits the process on failure.
|
|
@@ -39,7 +39,6 @@ const cmds = subcommands({
|
|
|
39
39
|
"wrangler.toml",
|
|
40
40
|
path.join(outputDir, "workers.ts"),
|
|
41
41
|
path.join(outputDir, "client.ts"),
|
|
42
|
-
config.clientUrl,
|
|
43
42
|
config.workersUrl,
|
|
44
43
|
],
|
|
45
44
|
};
|
package/dist/common.d.ts
CHANGED
|
@@ -134,103 +134,9 @@ export type HttpResult<T = unknown> = {
|
|
|
134
134
|
data?: T;
|
|
135
135
|
message?: string;
|
|
136
136
|
};
|
|
137
|
-
/**
|
|
138
|
-
* Dependency injection container, mapping an object type name to an instance of that object.
|
|
139
|
-
*
|
|
140
|
-
* Comes with the WranglerEnv and Request by default.
|
|
141
|
-
*/
|
|
142
|
-
export type InstanceRegistry = Map<string, any>;
|
|
143
|
-
export type MiddlewareFn = (request: Request, env: any, ir: InstanceRegistry) => Promise<HttpResult | undefined>;
|
|
144
137
|
export type KeysOfType<T, U> = {
|
|
145
138
|
[K in keyof T]: T[K] extends U ? (K extends string ? K : never) : never;
|
|
146
139
|
}[keyof T];
|
|
147
|
-
/**
|
|
148
|
-
* Represents the core middleware container for a Cloesce application.
|
|
149
|
-
*
|
|
150
|
-
* The `CloesceApp` class provides scoped middleware registration and
|
|
151
|
-
* management across three primary levels of execution:
|
|
152
|
-
*
|
|
153
|
-
* 1. **Global Middleware** — Executed before any routing or model resolution occurs.
|
|
154
|
-
* 2. **Model-Level Middleware** — Executed for requests targeting a specific model type.
|
|
155
|
-
* 3. **Method-Level Middleware** — Executed for requests targeting a specific method on a model.
|
|
156
|
-
*
|
|
157
|
-
* When an instance of `CloesceApp` is exported from `app.cloesce.ts`,
|
|
158
|
-
* it becomes the central container that the Cloesce runtime uses to
|
|
159
|
-
* assemble and apply middleware in the correct execution order.
|
|
160
|
-
*
|
|
161
|
-
* ### Middleware Execution Order
|
|
162
|
-
* Middleware is executed in FIFO order per scope. For example:
|
|
163
|
-
* ```ts
|
|
164
|
-
* app.use(Foo, A);
|
|
165
|
-
* app.use(Foo, B);
|
|
166
|
-
* app.use(Foo, C);
|
|
167
|
-
* // Executed in order: A → B → C
|
|
168
|
-
* ```
|
|
169
|
-
*
|
|
170
|
-
* Each middleware function (`MiddlewareFn`) can optionally short-circuit
|
|
171
|
-
* execution by returning a result, in which case subsequent middleware
|
|
172
|
-
* at the same or lower scope will not run.
|
|
173
|
-
*
|
|
174
|
-
* ### Example Usage
|
|
175
|
-
* ```ts
|
|
176
|
-
* import { app } from "cloesce";
|
|
177
|
-
*
|
|
178
|
-
* // Global authentication middleware
|
|
179
|
-
* app.useGlobal((request, env, di) => {
|
|
180
|
-
* // ... authenticate and inject user
|
|
181
|
-
* });
|
|
182
|
-
*
|
|
183
|
-
* // Model-level authorization
|
|
184
|
-
* app.useModel(User, (user) => user.hasPermissions([UserPermissions.canUseFoo]));
|
|
185
|
-
*
|
|
186
|
-
* // Method-level middleware (e.g., CRUD operation)
|
|
187
|
-
* app.useMethod(Foo, "someMethod", (user) => user.hasPermissions([UserPermissions.canUseFooMethod]));
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
export declare class CloesceApp {
|
|
191
|
-
global: MiddlewareFn[];
|
|
192
|
-
model: Map<string, MiddlewareFn[]>;
|
|
193
|
-
method: Map<string, Map<string, MiddlewareFn[]>>;
|
|
194
|
-
/**
|
|
195
|
-
* Registers a new global middleware function.
|
|
196
|
-
*
|
|
197
|
-
* Global middleware runs before all routing and model resolution.
|
|
198
|
-
* It is the ideal place to perform tasks such as:
|
|
199
|
-
* - Authentication (e.g., JWT verification)
|
|
200
|
-
* - Global request logging
|
|
201
|
-
* - Dependency injection of shared context
|
|
202
|
-
*
|
|
203
|
-
* @param m - The middleware function to register.
|
|
204
|
-
*/
|
|
205
|
-
useGlobal(m: MiddlewareFn): void;
|
|
206
|
-
/**
|
|
207
|
-
* Registers middleware for a specific model type.
|
|
208
|
-
*
|
|
209
|
-
* Model-level middleware runs after all global middleware,
|
|
210
|
-
* but before method-specific middleware. This scope allows
|
|
211
|
-
* logic to be applied consistently across all endpoints
|
|
212
|
-
* associated with a given model (e.g., authorization).
|
|
213
|
-
*
|
|
214
|
-
* @typeParam T - The model type.
|
|
215
|
-
* @param ctor - The model constructor (used to derive its name).
|
|
216
|
-
* @param m - The middleware function to register.
|
|
217
|
-
*/
|
|
218
|
-
useModel<T>(ctor: new () => T, m: MiddlewareFn): void;
|
|
219
|
-
/**
|
|
220
|
-
* Registers middleware for a specific method on a model.
|
|
221
|
-
*
|
|
222
|
-
* Method-level middleware is executed after model middleware,
|
|
223
|
-
* and before the method implementation itself. It can be used for:
|
|
224
|
-
* - Fine-grained permission checks
|
|
225
|
-
* - Custom logging or tracing per endpoint
|
|
226
|
-
*
|
|
227
|
-
* @typeParam T - The model type.
|
|
228
|
-
* @param ctor - The model constructor (used to derive its name).
|
|
229
|
-
* @param method - The method name on the model.
|
|
230
|
-
* @param m - The middleware function to register.
|
|
231
|
-
*/
|
|
232
|
-
useMethod<T>(ctor: new () => T, method: KeysOfType<T, (...args: any) => any>, m: MiddlewareFn): void;
|
|
233
|
-
}
|
|
234
140
|
export type CrudKind = "SAVE" | "GET" | "LIST";
|
|
235
141
|
export type CidlType = "Void" | "Integer" | "Real" | "Text" | "Blob" | "DateIso" | "Boolean" | {
|
|
236
142
|
DataSource: string;
|
|
@@ -316,6 +222,7 @@ export interface WranglerEnv {
|
|
|
316
222
|
name: string;
|
|
317
223
|
source_path: string;
|
|
318
224
|
db_binding: string;
|
|
225
|
+
vars: Record<string, CidlType>;
|
|
319
226
|
}
|
|
320
227
|
export interface CloesceAst {
|
|
321
228
|
version: string;
|
package/dist/common.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,oBAAY,kBAAkB;IAC5B,aAAa,IAAA;IACb,uBAAuB,IAAA;IACvB,WAAW,IAAA;IACX,mBAAmB,IAAA;IACnB,2BAA2B,IAAA;IAC3B,kBAAkB,IAAA;IAClB,kBAAkB,IAAA;IAClB,wBAAwB,IAAA;IACxB,wBAAwB,IAAA;IACxB,kCAAkC,IAAA;IAClC,kCAAkC,KAAA;IAClC,kCAAkC,KAAA;IAClC,yBAAyB,KAAA;IACzB,iBAAiB,KAAA;IACjB,sBAAsB,KAAA;IACtB,kBAAkB,KAAA;IAClB,mBAAmB,KAAA;IACnB,WAAW,KAAA;CACZ;AAyFD,wBAAgB,YAAY,CAAC,IAAI,EAAE,kBAAkB;iBArFpC,MAAM;gBAAc,MAAM;EAuF1C;AAED,qBAAa,cAAc;IAIN,IAAI,EAAE,kBAAkB;IAH3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;gBAEE,IAAI,EAAE,kBAAkB;IAE3C,UAAU,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS;CAG/D;AAED,KAAK,gBAAgB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAC5C,gBAAgB,CAAC,CAAC,CAAC,EAAE,GACrB,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAC3C,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAE3E,qBAAa,MAAM,CAAC,CAAC,EAAE,CAAC;IAEpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IADxB,OAAO;IAIP,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,CAEjB;IAED,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAIjD,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAIlD,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC;IAIlC,OAAO,IAAI,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAInC,MAAM,IAAI,CAAC;IAOX,UAAU,IAAI,CAAC;IAOf,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAMvC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;CAK5C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,GAAG,OAAO,IAAI;IACpC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"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"}
|
package/dist/common.js
CHANGED
|
@@ -150,111 +150,6 @@ export class Either {
|
|
|
150
150
|
: Either.left(fn(this.inner.left));
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
/**
|
|
154
|
-
* Represents the core middleware container for a Cloesce application.
|
|
155
|
-
*
|
|
156
|
-
* The `CloesceApp` class provides scoped middleware registration and
|
|
157
|
-
* management across three primary levels of execution:
|
|
158
|
-
*
|
|
159
|
-
* 1. **Global Middleware** — Executed before any routing or model resolution occurs.
|
|
160
|
-
* 2. **Model-Level Middleware** — Executed for requests targeting a specific model type.
|
|
161
|
-
* 3. **Method-Level Middleware** — Executed for requests targeting a specific method on a model.
|
|
162
|
-
*
|
|
163
|
-
* When an instance of `CloesceApp` is exported from `app.cloesce.ts`,
|
|
164
|
-
* it becomes the central container that the Cloesce runtime uses to
|
|
165
|
-
* assemble and apply middleware in the correct execution order.
|
|
166
|
-
*
|
|
167
|
-
* ### Middleware Execution Order
|
|
168
|
-
* Middleware is executed in FIFO order per scope. For example:
|
|
169
|
-
* ```ts
|
|
170
|
-
* app.use(Foo, A);
|
|
171
|
-
* app.use(Foo, B);
|
|
172
|
-
* app.use(Foo, C);
|
|
173
|
-
* // Executed in order: A → B → C
|
|
174
|
-
* ```
|
|
175
|
-
*
|
|
176
|
-
* Each middleware function (`MiddlewareFn`) can optionally short-circuit
|
|
177
|
-
* execution by returning a result, in which case subsequent middleware
|
|
178
|
-
* at the same or lower scope will not run.
|
|
179
|
-
*
|
|
180
|
-
* ### Example Usage
|
|
181
|
-
* ```ts
|
|
182
|
-
* import { app } from "cloesce";
|
|
183
|
-
*
|
|
184
|
-
* // Global authentication middleware
|
|
185
|
-
* app.useGlobal((request, env, di) => {
|
|
186
|
-
* // ... authenticate and inject user
|
|
187
|
-
* });
|
|
188
|
-
*
|
|
189
|
-
* // Model-level authorization
|
|
190
|
-
* app.useModel(User, (user) => user.hasPermissions([UserPermissions.canUseFoo]));
|
|
191
|
-
*
|
|
192
|
-
* // Method-level middleware (e.g., CRUD operation)
|
|
193
|
-
* app.useMethod(Foo, "someMethod", (user) => user.hasPermissions([UserPermissions.canUseFooMethod]));
|
|
194
|
-
* ```
|
|
195
|
-
*/
|
|
196
|
-
export class CloesceApp {
|
|
197
|
-
global = [];
|
|
198
|
-
model = new Map();
|
|
199
|
-
method = new Map();
|
|
200
|
-
/**
|
|
201
|
-
* Registers a new global middleware function.
|
|
202
|
-
*
|
|
203
|
-
* Global middleware runs before all routing and model resolution.
|
|
204
|
-
* It is the ideal place to perform tasks such as:
|
|
205
|
-
* - Authentication (e.g., JWT verification)
|
|
206
|
-
* - Global request logging
|
|
207
|
-
* - Dependency injection of shared context
|
|
208
|
-
*
|
|
209
|
-
* @param m - The middleware function to register.
|
|
210
|
-
*/
|
|
211
|
-
useGlobal(m) {
|
|
212
|
-
this.global.push(m);
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Registers middleware for a specific model type.
|
|
216
|
-
*
|
|
217
|
-
* Model-level middleware runs after all global middleware,
|
|
218
|
-
* but before method-specific middleware. This scope allows
|
|
219
|
-
* logic to be applied consistently across all endpoints
|
|
220
|
-
* associated with a given model (e.g., authorization).
|
|
221
|
-
*
|
|
222
|
-
* @typeParam T - The model type.
|
|
223
|
-
* @param ctor - The model constructor (used to derive its name).
|
|
224
|
-
* @param m - The middleware function to register.
|
|
225
|
-
*/
|
|
226
|
-
useModel(ctor, m) {
|
|
227
|
-
if (this.model.has(ctor.name)) {
|
|
228
|
-
this.model.get(ctor.name).push(m);
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
this.model.set(ctor.name, [m]);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Registers middleware for a specific method on a model.
|
|
236
|
-
*
|
|
237
|
-
* Method-level middleware is executed after model middleware,
|
|
238
|
-
* and before the method implementation itself. It can be used for:
|
|
239
|
-
* - Fine-grained permission checks
|
|
240
|
-
* - Custom logging or tracing per endpoint
|
|
241
|
-
*
|
|
242
|
-
* @typeParam T - The model type.
|
|
243
|
-
* @param ctor - The model constructor (used to derive its name).
|
|
244
|
-
* @param method - The method name on the model.
|
|
245
|
-
* @param m - The middleware function to register.
|
|
246
|
-
*/
|
|
247
|
-
useMethod(ctor, method, m) {
|
|
248
|
-
if (!this.method.has(ctor.name)) {
|
|
249
|
-
this.method.set(ctor.name, new Map());
|
|
250
|
-
}
|
|
251
|
-
const methods = this.method.get(ctor.name);
|
|
252
|
-
if (!methods.has(method)) {
|
|
253
|
-
methods.set(method, []);
|
|
254
|
-
}
|
|
255
|
-
methods.get(method).push(m);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
153
|
export function isNullableType(ty) {
|
|
259
154
|
return typeof ty === "object" && ty !== null && "Nullable" in ty;
|
|
260
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/extractor/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,OAAO,EACP,IAAI,EACJ,UAAU,EAEV,iBAAiB,EAEjB,gBAAgB,EAEhB,UAAU,EAEX,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EAER,MAAM,EACN,QAAQ,EACR,KAAK,EAEL,WAAW,EAGX,WAAW,EACX,cAAc,EAEd,cAAc,
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/extractor/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,OAAO,EACP,IAAI,EACJ,UAAU,EAEV,iBAAiB,EAEjB,gBAAgB,EAEhB,UAAU,EAEX,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EAER,MAAM,EACN,QAAQ,EACR,KAAK,EAEL,WAAW,EAGX,WAAW,EACX,cAAc,EAEd,cAAc,EAEf,MAAM,cAAc,CAAC;AAuBtB,qBAAa,aAAa;IAEf,WAAW,EAAE,MAAM;IACnB,OAAO,EAAE,MAAM;gBADf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM;IAGxB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,cAAc,EAAE,UAAU,CAAC;IA8F7D,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC;IA8BlE,MAAM,CAAC,KAAK,CACV,SAAS,EAAE,gBAAgB,EAC3B,UAAU,EAAE,UAAU,GACrB,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC;IAgQhC,MAAM,CAAC,GAAG,CACR,SAAS,EAAE,gBAAgB,EAC3B,UAAU,EAAE,UAAU,GACrB,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC;IAmCzC,MAAM,CAAC,GAAG,CACR,SAAS,EAAE,gBAAgB,EAC3B,UAAU,EAAE,UAAU,GACrB,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC;IAuCtC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CASjC;IAEF,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,IAAI,EACV,MAAM,GAAE,OAAe,GACtB,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC;IAkJnC,MAAM,CAAC,WAAW,CAChB,IAAI,EAAE,UAAU,GAAG,SAAS,EAC5B,YAAY,EAAE,gBAAgB,EAC9B,EAAE,EAAE,UAAU,GACb,MAAM,CAAC,cAAc,EAAE,eAAe,CAAC;IAiF1C,MAAM,CAAC,MAAM,CACX,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,QAAQ,GACjB,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC;CA0EvC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Node as MorphNode, SyntaxKind, Scope, } from "ts-morph";
|
|
2
|
-
import { Either, HttpVerb, ExtractorError, ExtractorErrorCode,
|
|
2
|
+
import { Either, HttpVerb, ExtractorError, ExtractorErrorCode, } from "../common.js";
|
|
3
3
|
import { TypeFormatFlags } from "typescript";
|
|
4
4
|
var AttributeDecoratorKind;
|
|
5
5
|
(function (AttributeDecoratorKind) {
|
|
@@ -123,7 +123,7 @@ export class CidlExtractor {
|
|
|
123
123
|
return type?.getText(undefined, TypeFormatFlags.UseAliasDefinedOutsideCurrentScope);
|
|
124
124
|
};
|
|
125
125
|
const typeText = getTypeText();
|
|
126
|
-
if (typeText === CloesceApp
|
|
126
|
+
if (typeText === "CloesceApp") {
|
|
127
127
|
return Either.right(sourceFile.getFilePath().toString());
|
|
128
128
|
}
|
|
129
129
|
return err(ExtractorErrorCode.AppMissingDefaultExport);
|
|
@@ -357,18 +357,31 @@ export class CidlExtractor {
|
|
|
357
357
|
});
|
|
358
358
|
}
|
|
359
359
|
static env(classDecl, sourceFile) {
|
|
360
|
-
const
|
|
361
|
-
|
|
360
|
+
const vars = {};
|
|
361
|
+
let binding;
|
|
362
|
+
for (const prop of classDecl.getProperties()) {
|
|
363
|
+
if (prop
|
|
362
364
|
.getType()
|
|
363
|
-
.getText(undefined, TypeFormatFlags.UseAliasDefinedOutsideCurrentScope) === "D1Database")
|
|
364
|
-
|
|
365
|
+
.getText(undefined, TypeFormatFlags.UseAliasDefinedOutsideCurrentScope) === "D1Database") {
|
|
366
|
+
binding = prop.getName();
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const ty = CidlExtractor.cidlType(prop.getType());
|
|
370
|
+
if (ty.isLeft()) {
|
|
371
|
+
ty.value.context = prop.getName();
|
|
372
|
+
ty.value.snippet = prop.getText();
|
|
373
|
+
return ty;
|
|
374
|
+
}
|
|
375
|
+
vars[prop.getName()] = ty.unwrap();
|
|
376
|
+
}
|
|
365
377
|
if (!binding) {
|
|
366
378
|
return err(ExtractorErrorCode.MissingDatabaseBinding);
|
|
367
379
|
}
|
|
368
380
|
return Either.right({
|
|
369
381
|
name: classDecl.getName(),
|
|
370
382
|
source_path: sourceFile.getFilePath().toString(),
|
|
371
|
-
db_binding: binding
|
|
383
|
+
db_binding: binding,
|
|
384
|
+
vars,
|
|
372
385
|
});
|
|
373
386
|
}
|
|
374
387
|
static primTypeMap = {
|
package/dist/generator.wasm
CHANGED
|
Binary file
|
package/dist/orm.wasm
CHANGED
|
Binary file
|
package/dist/router/router.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { HttpResult, Either, ModelMethod, CloesceAst, Model,
|
|
1
|
+
import { HttpResult, Either, ModelMethod, CloesceAst, Model, KeysOfType } from "../common.js";
|
|
2
2
|
import { OrmWasmExports } from "./wasm.js";
|
|
3
3
|
import { CrudContext } from "./crud.js";
|
|
4
|
+
/**
|
|
5
|
+
* Dependency injection container, mapping an object type name to an instance of that object.
|
|
6
|
+
*
|
|
7
|
+
* Comes with the WranglerEnv and Request by default.
|
|
8
|
+
*/
|
|
9
|
+
export type DependencyInjector = Map<string, any>;
|
|
4
10
|
/**
|
|
5
11
|
* Map of model names to their respective constructor.
|
|
6
12
|
*
|
|
@@ -8,11 +14,6 @@ import { CrudContext } from "./crud.js";
|
|
|
8
14
|
* is guaranteed to contain all model definitions.
|
|
9
15
|
*/
|
|
10
16
|
type ModelConstructorRegistry = Record<string, new () => any>;
|
|
11
|
-
/**
|
|
12
|
-
* Given a request, this represents a map of each body / url param name to
|
|
13
|
-
* its actual value. Unknown, as the a request can be anything.
|
|
14
|
-
*/
|
|
15
|
-
type RequestParamMap = Record<string, unknown>;
|
|
16
17
|
/**
|
|
17
18
|
* Meta information on the wrangler env and db bindings
|
|
18
19
|
*/
|
|
@@ -20,6 +21,68 @@ interface MetaWranglerEnv {
|
|
|
20
21
|
envName: string;
|
|
21
22
|
dbName: string;
|
|
22
23
|
}
|
|
24
|
+
export type MiddlewareFn = (request: Request, env: any, di: DependencyInjector) => Promise<HttpResult | void>;
|
|
25
|
+
export type ResponseMiddlewareFn = (request: Request, env: any, di: DependencyInjector, response: Response) => Promise<HttpResult | void>;
|
|
26
|
+
export declare class CloesceApp {
|
|
27
|
+
private globalMiddleware;
|
|
28
|
+
private modelMiddleware;
|
|
29
|
+
private methodMiddleware;
|
|
30
|
+
private responseMiddleware;
|
|
31
|
+
routePrefix: string;
|
|
32
|
+
/**
|
|
33
|
+
* Registers global middleware which runs before any route matching.
|
|
34
|
+
*
|
|
35
|
+
* @param m - The middleware function to register.
|
|
36
|
+
*/
|
|
37
|
+
onRequest(m: MiddlewareFn): void;
|
|
38
|
+
/**
|
|
39
|
+
* Registers middleware which runs after the response is generated, but before
|
|
40
|
+
* it is returned to the client.
|
|
41
|
+
*
|
|
42
|
+
* Optionally, return a new HttpResult to short-circuit the response.
|
|
43
|
+
*
|
|
44
|
+
* Errors thrown in response middleware are caught and returned as a 500 response.
|
|
45
|
+
*
|
|
46
|
+
* Errors thrown in earlier middleware or route processing are not caught here.
|
|
47
|
+
*
|
|
48
|
+
* @param m - The middleware function to register.
|
|
49
|
+
*/
|
|
50
|
+
onResponse(m: ResponseMiddlewareFn): void;
|
|
51
|
+
/**
|
|
52
|
+
* Registers middleware for a specific model type.
|
|
53
|
+
*
|
|
54
|
+
* Runs before request validation and method middleware.
|
|
55
|
+
*
|
|
56
|
+
* @typeParam T - The model type.
|
|
57
|
+
* @param ctor - The model constructor (used to derive its name).
|
|
58
|
+
* @param m - The middleware function to register.
|
|
59
|
+
*/
|
|
60
|
+
onModel<T>(ctor: new () => T, m: MiddlewareFn): void;
|
|
61
|
+
/**
|
|
62
|
+
* Registers middleware for a specific method on a model.
|
|
63
|
+
*
|
|
64
|
+
* Runs after model middleware and request validation.
|
|
65
|
+
*
|
|
66
|
+
* @typeParam T - The model type.
|
|
67
|
+
* @param ctor - The model constructor (used to derive its name).
|
|
68
|
+
* @param method - The method name on the model.
|
|
69
|
+
* @param m - The middleware function to register.
|
|
70
|
+
*/
|
|
71
|
+
onMethod<T>(ctor: new () => T, method: KeysOfType<T, (...args: any) => any>, m: MiddlewareFn): void;
|
|
72
|
+
/**
|
|
73
|
+
* Router entry point. Undergoes route matching, request validation, hydration, and method dispatch.
|
|
74
|
+
*/
|
|
75
|
+
private cloesce;
|
|
76
|
+
/**
|
|
77
|
+
* Runs the Cloesce app. Intended to be called from the generated workers code.
|
|
78
|
+
*/
|
|
79
|
+
run(request: Request, env: any, ast: CloesceAst, constructorRegistry: ModelConstructorRegistry, envMeta: MetaWranglerEnv): Promise<Response>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Given a request, this represents a map of each body / url param name to
|
|
83
|
+
* its actual value. Unknown, as the a request can be anything.
|
|
84
|
+
*/
|
|
85
|
+
export type RequestParamMap = Record<string, unknown>;
|
|
23
86
|
/**
|
|
24
87
|
* Singleton instance containing the cidl, constructor registry, and wasm binary.
|
|
25
88
|
* These values are guaranteed to never change throughout a workers lifetime.
|
|
@@ -33,19 +96,12 @@ export declare class RuntimeContainer {
|
|
|
33
96
|
static init(ast: CloesceAst, constructorRegistry: ModelConstructorRegistry, wasm?: WebAssembly.Instance): Promise<void>;
|
|
34
97
|
static get(): RuntimeContainer;
|
|
35
98
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Runtime entry point. Given a request, undergoes: routing, validating,
|
|
38
|
-
* hydrating, and method dispatch.
|
|
39
|
-
*
|
|
40
|
-
* @returns A Response with an `HttpResult` JSON body.
|
|
41
|
-
*/
|
|
42
|
-
export declare function cloesce(request: Request, env: any, ast: CloesceAst, app: CloesceApp, constructorRegistry: ModelConstructorRegistry, envMeta: MetaWranglerEnv, apiRoute: string): Promise<Response>;
|
|
43
99
|
/**
|
|
44
100
|
* Matches a request to a method on a model.
|
|
45
101
|
* @param apiRoute The route from the domain to the actual API, ie https://foo.com/route/to/api => route/to/api/
|
|
46
102
|
* @returns 404 or a `MatchedRoute`
|
|
47
103
|
*/
|
|
48
|
-
declare function matchRoute(request: Request, ast: CloesceAst,
|
|
104
|
+
declare function matchRoute(request: Request, ast: CloesceAst, routePrefix: string): Either<HttpResult, {
|
|
49
105
|
model: Model;
|
|
50
106
|
method: ModelMethod;
|
|
51
107
|
id: string | null;
|
|
@@ -63,7 +119,7 @@ declare function validateRequest(request: Request, ast: CloesceAst, model: Model
|
|
|
63
119
|
* Calls a method on a model given a list of parameters.
|
|
64
120
|
* @returns 500 on an uncaught client error, 200 with a result body on success
|
|
65
121
|
*/
|
|
66
|
-
declare function methodDispatch(crudCtx: CrudContext, instanceRegistry:
|
|
122
|
+
declare function methodDispatch(crudCtx: CrudContext, instanceRegistry: DependencyInjector, method: ModelMethod, params: Record<string, unknown>): Promise<HttpResult<unknown>>;
|
|
67
123
|
/**
|
|
68
124
|
* For testing purposes
|
|
69
125
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AACA,OAAO,EACL,UAAU,EACV,MAAM,EACN,WAAW,EAEX,UAAU,EAEV,KAAK,EAGL,UAAU,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"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"}
|
package/dist/router/router.js
CHANGED
|
@@ -2,6 +2,159 @@ import { Either, isNullableType, getNavigationPropertyCidlType, NO_DATA_SOURCE,
|
|
|
2
2
|
import { mapSql, loadOrmWasm } from "./wasm.js";
|
|
3
3
|
import { CrudContext } from "./crud.js";
|
|
4
4
|
import { Orm } from "../ui/backend.js";
|
|
5
|
+
export class CloesceApp {
|
|
6
|
+
globalMiddleware = [];
|
|
7
|
+
modelMiddleware = new Map();
|
|
8
|
+
methodMiddleware = new Map();
|
|
9
|
+
responseMiddleware = [];
|
|
10
|
+
routePrefix = "api";
|
|
11
|
+
/**
|
|
12
|
+
* Registers global middleware which runs before any route matching.
|
|
13
|
+
*
|
|
14
|
+
* @param m - The middleware function to register.
|
|
15
|
+
*/
|
|
16
|
+
onRequest(m) {
|
|
17
|
+
this.globalMiddleware.push(m);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Registers middleware which runs after the response is generated, but before
|
|
21
|
+
* it is returned to the client.
|
|
22
|
+
*
|
|
23
|
+
* Optionally, return a new HttpResult to short-circuit the response.
|
|
24
|
+
*
|
|
25
|
+
* Errors thrown in response middleware are caught and returned as a 500 response.
|
|
26
|
+
*
|
|
27
|
+
* Errors thrown in earlier middleware or route processing are not caught here.
|
|
28
|
+
*
|
|
29
|
+
* @param m - The middleware function to register.
|
|
30
|
+
*/
|
|
31
|
+
onResponse(m) {
|
|
32
|
+
this.responseMiddleware.push(m);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Registers middleware for a specific model type.
|
|
36
|
+
*
|
|
37
|
+
* Runs before request validation and method middleware.
|
|
38
|
+
*
|
|
39
|
+
* @typeParam T - The model type.
|
|
40
|
+
* @param ctor - The model constructor (used to derive its name).
|
|
41
|
+
* @param m - The middleware function to register.
|
|
42
|
+
*/
|
|
43
|
+
onModel(ctor, m) {
|
|
44
|
+
if (this.modelMiddleware.has(ctor.name)) {
|
|
45
|
+
this.modelMiddleware.get(ctor.name).push(m);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
this.modelMiddleware.set(ctor.name, [m]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Registers middleware for a specific method on a model.
|
|
53
|
+
*
|
|
54
|
+
* Runs after model middleware and request validation.
|
|
55
|
+
*
|
|
56
|
+
* @typeParam T - The model type.
|
|
57
|
+
* @param ctor - The model constructor (used to derive its name).
|
|
58
|
+
* @param method - The method name on the model.
|
|
59
|
+
* @param m - The middleware function to register.
|
|
60
|
+
*/
|
|
61
|
+
onMethod(ctor, method, m) {
|
|
62
|
+
if (!this.methodMiddleware.has(ctor.name)) {
|
|
63
|
+
this.methodMiddleware.set(ctor.name, new Map());
|
|
64
|
+
}
|
|
65
|
+
const methods = this.methodMiddleware.get(ctor.name);
|
|
66
|
+
if (!methods.has(method)) {
|
|
67
|
+
methods.set(method, []);
|
|
68
|
+
}
|
|
69
|
+
methods.get(method).push(m);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Router entry point. Undergoes route matching, request validation, hydration, and method dispatch.
|
|
73
|
+
*/
|
|
74
|
+
async cloesce(request, env, ast, constructorRegistry, di, d1) {
|
|
75
|
+
// Global middleware
|
|
76
|
+
for (const m of this.globalMiddleware) {
|
|
77
|
+
const res = await m(request, env, di);
|
|
78
|
+
if (res) {
|
|
79
|
+
return toResponse(res);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Route match
|
|
83
|
+
const route = matchRoute(request, ast, this.routePrefix);
|
|
84
|
+
if (route.isLeft()) {
|
|
85
|
+
return toResponse(route.value);
|
|
86
|
+
}
|
|
87
|
+
const { method, model, id } = route.unwrap();
|
|
88
|
+
// Model middleware
|
|
89
|
+
for (const m of this.modelMiddleware.get(model.name) ?? []) {
|
|
90
|
+
const res = await m(request, env, di);
|
|
91
|
+
if (res) {
|
|
92
|
+
return toResponse(res);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Request validation
|
|
96
|
+
const validation = await validateRequest(request, ast, model, method, id);
|
|
97
|
+
if (validation.isLeft()) {
|
|
98
|
+
return toResponse(validation.value);
|
|
99
|
+
}
|
|
100
|
+
const { params, dataSource } = validation.unwrap();
|
|
101
|
+
// Method middleware
|
|
102
|
+
for (const m of this.methodMiddleware.get(model.name)?.get(method.name) ??
|
|
103
|
+
[]) {
|
|
104
|
+
const res = await m(request, env, di);
|
|
105
|
+
if (res) {
|
|
106
|
+
return toResponse(res);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Hydration
|
|
110
|
+
const crudCtx = await (async () => {
|
|
111
|
+
if (method.is_static) {
|
|
112
|
+
return Either.right(CrudContext.fromCtor(d1, constructorRegistry[model.name]));
|
|
113
|
+
}
|
|
114
|
+
const hydratedModel = await hydrateModel(constructorRegistry, d1, model, id, // id must exist after matchRoute
|
|
115
|
+
dataSource);
|
|
116
|
+
return hydratedModel.map((_) => CrudContext.fromInstance(d1, hydratedModel.value, constructorRegistry[model.name]));
|
|
117
|
+
})();
|
|
118
|
+
if (crudCtx.isLeft()) {
|
|
119
|
+
return toResponse(crudCtx.value);
|
|
120
|
+
}
|
|
121
|
+
// Method dispatch
|
|
122
|
+
return toResponse(await methodDispatch(crudCtx.unwrap(), di, method, params));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Runs the Cloesce app. Intended to be called from the generated workers code.
|
|
126
|
+
*/
|
|
127
|
+
async run(request, env, ast, constructorRegistry, envMeta) {
|
|
128
|
+
const di = new Map();
|
|
129
|
+
di.set(envMeta.envName, env);
|
|
130
|
+
di.set("Request", request);
|
|
131
|
+
await RuntimeContainer.init(ast, constructorRegistry);
|
|
132
|
+
const d1 = env[envMeta.dbName]; // TODO: multiple dbs
|
|
133
|
+
try {
|
|
134
|
+
// Core cloesce processing
|
|
135
|
+
const response = await this.cloesce(request, env, ast, constructorRegistry, di, d1);
|
|
136
|
+
// Response middleware
|
|
137
|
+
for (const m of this.responseMiddleware) {
|
|
138
|
+
const res = await m(request, env, di, response);
|
|
139
|
+
if (res) {
|
|
140
|
+
return toResponse(res);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return response;
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
console.error(JSON.stringify(e));
|
|
147
|
+
return new Response(JSON.stringify({
|
|
148
|
+
ok: false,
|
|
149
|
+
status: 500,
|
|
150
|
+
message: e.toString(),
|
|
151
|
+
}), {
|
|
152
|
+
status: 500,
|
|
153
|
+
headers: { "Content-Type": "application/json" },
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
5
158
|
/**
|
|
6
159
|
* Singleton instance containing the cidl, constructor registry, and wasm binary.
|
|
7
160
|
* These values are guaranteed to never change throughout a workers lifetime.
|
|
@@ -26,94 +179,29 @@ export class RuntimeContainer {
|
|
|
26
179
|
return this.instance;
|
|
27
180
|
}
|
|
28
181
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Runtime entry point. Given a request, undergoes: routing, validating,
|
|
31
|
-
* hydrating, and method dispatch.
|
|
32
|
-
*
|
|
33
|
-
* @returns A Response with an `HttpResult` JSON body.
|
|
34
|
-
*/
|
|
35
|
-
export async function cloesce(request, env, ast, app, constructorRegistry, envMeta, apiRoute) {
|
|
36
|
-
//#region Initialization
|
|
37
|
-
const ir = new Map();
|
|
38
|
-
ir.set(envMeta.envName, env);
|
|
39
|
-
ir.set("Request", request);
|
|
40
|
-
await RuntimeContainer.init(ast, constructorRegistry);
|
|
41
|
-
const d1 = env[envMeta.dbName]; // TODO: multiple dbs
|
|
42
|
-
//#endregion
|
|
43
|
-
//#region Global Middleware
|
|
44
|
-
for (const m of app.global) {
|
|
45
|
-
const res = await m(request, env, ir);
|
|
46
|
-
if (res) {
|
|
47
|
-
return toResponse(res);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region Match the route to a model method
|
|
52
|
-
const route = matchRoute(request, ast, apiRoute);
|
|
53
|
-
if (route.isLeft()) {
|
|
54
|
-
return toResponse(route.value);
|
|
55
|
-
}
|
|
56
|
-
const { method, model, id } = route.unwrap();
|
|
57
|
-
//#endregion
|
|
58
|
-
//#region Model Middleware
|
|
59
|
-
for (const m of app.model.get(model.name) ?? []) {
|
|
60
|
-
const res = await m(request, env, ir);
|
|
61
|
-
if (res) {
|
|
62
|
-
return toResponse(res);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
//#endregion
|
|
66
|
-
//#region Validate request body to the model method
|
|
67
|
-
const validation = await validateRequest(request, ast, model, method, id);
|
|
68
|
-
if (validation.isLeft()) {
|
|
69
|
-
return toResponse(validation.value);
|
|
70
|
-
}
|
|
71
|
-
const { params, dataSource } = validation.unwrap();
|
|
72
|
-
//#endregion
|
|
73
|
-
//#region Method Middleware
|
|
74
|
-
for (const m of app.method.get(model.name)?.get(method.name) ?? []) {
|
|
75
|
-
const res = await m(request, env, ir);
|
|
76
|
-
if (res) {
|
|
77
|
-
return toResponse(res);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region Instantatiate the model
|
|
82
|
-
const crudCtx = await (async () => {
|
|
83
|
-
if (method.is_static) {
|
|
84
|
-
return Either.right(CrudContext.fromCtor(d1, constructorRegistry[model.name]));
|
|
85
|
-
}
|
|
86
|
-
const hydratedModel = await hydrateModel(constructorRegistry, d1, model, id, // id must exist after matchRoute
|
|
87
|
-
dataSource);
|
|
88
|
-
return hydratedModel.map((_) => CrudContext.fromInstance(d1, hydratedModel.value, constructorRegistry[model.name]));
|
|
89
|
-
})();
|
|
90
|
-
if (crudCtx.isLeft()) {
|
|
91
|
-
return toResponse(crudCtx.value);
|
|
92
|
-
}
|
|
93
|
-
//#endregion
|
|
94
|
-
return toResponse(await methodDispatch(crudCtx.unwrap(), ir, method, params));
|
|
95
|
-
}
|
|
96
182
|
/**
|
|
97
183
|
* Matches a request to a method on a model.
|
|
98
184
|
* @param apiRoute The route from the domain to the actual API, ie https://foo.com/route/to/api => route/to/api/
|
|
99
185
|
* @returns 404 or a `MatchedRoute`
|
|
100
186
|
*/
|
|
101
|
-
function matchRoute(request, ast,
|
|
187
|
+
function matchRoute(request, ast, routePrefix) {
|
|
102
188
|
const url = new URL(request.url);
|
|
189
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
190
|
+
const prefix = routePrefix.split("/").filter(Boolean);
|
|
103
191
|
// Error state: We expect an exact request format, and expect that the model
|
|
104
192
|
// and are apart of the CIDL
|
|
105
193
|
const notFound = (e) => Either.left(errorState(404, `Path not found: ${e} ${url.pathname}`));
|
|
106
|
-
const
|
|
107
|
-
.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (
|
|
194
|
+
for (const p of prefix) {
|
|
195
|
+
if (parts.shift() !== p)
|
|
196
|
+
return notFound(`Missing prefix segment "${p}"`);
|
|
197
|
+
}
|
|
198
|
+
if (parts.length < 2) {
|
|
111
199
|
return notFound("Expected /model/method or /model/:id/method");
|
|
112
200
|
}
|
|
113
201
|
// Attempt to extract from routeParts
|
|
114
|
-
const modelName =
|
|
115
|
-
const methodName =
|
|
116
|
-
const id =
|
|
202
|
+
const modelName = parts[0];
|
|
203
|
+
const methodName = parts[parts.length - 1];
|
|
204
|
+
const id = parts.length === 3 ? parts[1] : null;
|
|
117
205
|
const model = ast.models[modelName];
|
|
118
206
|
if (!model) {
|
|
119
207
|
return notFound(`Unknown model ${modelName}`);
|
|
@@ -203,7 +291,7 @@ async function hydrateModel(constructorRegistry, d1, model, id, dataSource) {
|
|
|
203
291
|
? null
|
|
204
292
|
: constructorRegistry[model.name][dataSource];
|
|
205
293
|
records = await d1
|
|
206
|
-
.prepare(Orm.getQuery(constructorRegistry[model.name], includeTree)
|
|
294
|
+
.prepare(Orm.getQuery(constructorRegistry[model.name], includeTree))
|
|
207
295
|
.bind(id)
|
|
208
296
|
.run();
|
|
209
297
|
if (!records?.results) {
|
|
@@ -261,6 +349,11 @@ async function methodDispatch(crudCtx, instanceRegistry, method, params) {
|
|
|
261
349
|
return uncaughtException(e);
|
|
262
350
|
}
|
|
263
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Runtime type validation for CIDL types.
|
|
354
|
+
*
|
|
355
|
+
* Returns true if the value matches the CIDL type, false otherwise.
|
|
356
|
+
*/
|
|
264
357
|
function validateCidlType(ast, value, cidlType, isPartial) {
|
|
265
358
|
if (value === undefined)
|
|
266
359
|
return isPartial;
|
package/dist/ui/backend.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { D1Database } from "@cloudflare/workers-types/experimental/index.js";
|
|
2
2
|
import { CrudKind, DeepPartial, Either, KeysOfType } from "../common.js";
|
|
3
|
-
export {
|
|
4
|
-
export type { HttpResult, Either, DeepPartial,
|
|
5
|
-
export { CloesceApp } from "../common.js";
|
|
3
|
+
export { CloesceApp, MiddlewareFn, ResponseMiddlewareFn, DependencyInjector, } from "../router/router.js";
|
|
4
|
+
export type { HttpResult, Either, DeepPartial, CrudKind } from "../common.js";
|
|
6
5
|
/**
|
|
7
6
|
* Marks a class as a D1-backed SQL model.
|
|
8
7
|
*
|
|
@@ -209,7 +208,7 @@ export declare const ManyToMany: (_uniqueId: string) => PropertyDecorator;
|
|
|
209
208
|
* dogId: number;
|
|
210
209
|
* ```
|
|
211
210
|
*/
|
|
212
|
-
export declare const ForeignKey: <T>(
|
|
211
|
+
export declare const ForeignKey: <T>(_Model: T | string) => PropertyDecorator;
|
|
213
212
|
/**
|
|
214
213
|
* Marks a method parameter for dependency injection.
|
|
215
214
|
*
|
|
@@ -434,7 +433,7 @@ export declare class Orm {
|
|
|
434
433
|
includeTree?: IncludeTree<T> | null;
|
|
435
434
|
from?: string;
|
|
436
435
|
tagCte?: string;
|
|
437
|
-
}):
|
|
436
|
+
}): string;
|
|
438
437
|
/**
|
|
439
438
|
* Returns a select query for a single model by primary key, creating a CTE view using the provided include tree.
|
|
440
439
|
*
|
|
@@ -460,7 +459,7 @@ export declare class Orm {
|
|
|
460
459
|
* SELECT * FROM Person_view WHERE [Person].[id] = ?
|
|
461
460
|
* ```
|
|
462
461
|
*/
|
|
463
|
-
static getQuery<T extends object>(ctor: new () => T, includeTree?: IncludeTree<T> | null):
|
|
462
|
+
static getQuery<T extends object>(ctor: new () => T, includeTree?: IncludeTree<T> | null): string;
|
|
464
463
|
/**
|
|
465
464
|
* Retrieves all instances of a model from the database.
|
|
466
465
|
* @param ctor The model constructor.
|
package/dist/ui/backend.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/ui/backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iDAAiD,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAQzE,OAAO,
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/ui/backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iDAAiD,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAQzE,OAAO,EACL,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,EAAE,EAAE,cAAyB,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,cAAc,EAAE,cAAyB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,WAAW,EAAE,cAAyB,CAAC;AAEpD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,EAAE,iBAA4B,CAAC;AAEtD;;;GAGG;AACH,eAAO,MAAM,GAAG,EAAE,eAA0B,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,IAAI,EAAE,eAA0B,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,GAAG,EAAE,eAA0B,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,eAA0B,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,eAA0B,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,eAAO,MAAM,UAAU,EAAE,iBAA4B,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,GACnB,mBAAmB,MAAM,KAAG,iBACrB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,GAClB,mBAAmB,MAAM,KAAG,iBACrB,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,GACpB,WAAW,MAAM,KAAG,iBACb,CAAC;AAEX;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,UAAU,GACpB,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,KAAG,iBACjB,CAAC;AAEX;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,MAAM,EAAE,kBAA6B,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,IAAI,GACd,QAAQ,QAAQ,EAAE,KAAG,cACd,CAAC;AAEX,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,SAAS,GAC7C,KAAK,GACL;KACG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GACrC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAC3B,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACnC,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,aAAa,CAAA;CAAE,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI,CACzC,UAAU,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,GAC7B,MAAM,CACT,GAAG;IAAE,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC;AAE/B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,OAAO,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAEvD;;GAEG;AACH,qBAAa,GAAG;IACM,OAAO,CAAC,EAAE;IAA9B,OAAO;IAEP;;;OAGG;IACH,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,UAAU,GAAG,GAAG;IAIlC;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,EAC5B,IAAI,EAAE,UAAU,CAAC,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAC9B,WAAW,GAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAW,GACxC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;IAItB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACG,MAAM,CAAC,CAAC,SAAS,MAAM,EAC3B,IAAI,EAAE,UAAU,CAAC,EACjB,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EACxB,WAAW,GAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAW,GACxC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IA6C/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,MAAM,EAC/B,IAAI,EAAE,UAAU,CAAC,EACjB,IAAI,EAAE;QACJ,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QACpC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,MAAM;IAiBT;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,MAAM,EAC9B,IAAI,EAAE,UAAU,CAAC,EACjB,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,GAClC,MAAM;IAKT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACG,IAAI,CAAC,CAAC,SAAS,MAAM,EACzB,IAAI,EAAE,UAAU,CAAC,EACjB,IAAI,EAAE;QACJ,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QACpC,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GACA,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAmB/B;;;;;;;;;;;;OAYG;IACG,GAAG,CAAC,CAAC,SAAS,MAAM,EACxB,IAAI,EAAE,UAAU,CAAC,EACjB,EAAE,EAAE,GAAG,EACP,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,GAClC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;CAqBrC"}
|
package/dist/ui/backend.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Either } from "../common.js";
|
|
2
2
|
import { RuntimeContainer } from "../router/router.js";
|
|
3
3
|
import { WasmResource, mapSql as mapSql, invokeOrmWasm, } from "../router/wasm.js";
|
|
4
|
-
export {
|
|
5
|
-
export { CloesceApp } from "../common.js";
|
|
4
|
+
export { CloesceApp, } from "../router/router.js";
|
|
6
5
|
/**
|
|
7
6
|
* Marks a class as a D1-backed SQL model.
|
|
8
7
|
*
|
|
@@ -23,7 +22,7 @@ export { CloesceApp } from "../common.js";
|
|
|
23
22
|
* }
|
|
24
23
|
* ```
|
|
25
24
|
*/
|
|
26
|
-
export const D1 = (
|
|
25
|
+
export const D1 = () => { };
|
|
27
26
|
/**
|
|
28
27
|
* Marks a class as a plain serializable object.
|
|
29
28
|
*
|
|
@@ -50,7 +49,7 @@ export const D1 = (_) => { };
|
|
|
50
49
|
* async function foo(): Promise<HttpResult<CatStuff>> { ... }
|
|
51
50
|
* ```
|
|
52
51
|
*/
|
|
53
|
-
export const PlainOldObject = (
|
|
52
|
+
export const PlainOldObject = () => { };
|
|
54
53
|
/**
|
|
55
54
|
* Declares a Wrangler environment definition.
|
|
56
55
|
*
|
|
@@ -72,7 +71,7 @@ export const PlainOldObject = (_) => { };
|
|
|
72
71
|
* foo(@Inject env: WranglerEnv) {...}
|
|
73
72
|
* ```
|
|
74
73
|
*/
|
|
75
|
-
export const WranglerEnv = (
|
|
74
|
+
export const WranglerEnv = () => { };
|
|
76
75
|
/**
|
|
77
76
|
* Marks a property as the SQL primary key for a model.
|
|
78
77
|
*
|
|
@@ -89,32 +88,32 @@ export const WranglerEnv = (_) => { };
|
|
|
89
88
|
* }
|
|
90
89
|
* ```
|
|
91
90
|
*/
|
|
92
|
-
export const PrimaryKey = (
|
|
91
|
+
export const PrimaryKey = () => { };
|
|
93
92
|
/**
|
|
94
93
|
* Exposes a class method as an HTTP GET endpoint.
|
|
95
94
|
* The method will appear in both backend and generated client APIs.
|
|
96
95
|
*/
|
|
97
|
-
export const GET = (
|
|
96
|
+
export const GET = () => { };
|
|
98
97
|
/**
|
|
99
98
|
* Exposes a class method as an HTTP POST endpoint.
|
|
100
99
|
* The method will appear in both backend and generated client APIs.
|
|
101
100
|
*/
|
|
102
|
-
export const POST = (
|
|
101
|
+
export const POST = () => { };
|
|
103
102
|
/**
|
|
104
103
|
* Exposes a class method as an HTTP PUT endpoint.
|
|
105
104
|
* The method will appear in both backend and generated client APIs.
|
|
106
105
|
*/
|
|
107
|
-
export const PUT = (
|
|
106
|
+
export const PUT = () => { };
|
|
108
107
|
/**
|
|
109
108
|
* Exposes a class method as an HTTP PATCH endpoint.
|
|
110
109
|
* The method will appear in both backend and generated client APIs.
|
|
111
110
|
*/
|
|
112
|
-
export const PATCH = (
|
|
111
|
+
export const PATCH = () => { };
|
|
113
112
|
/**
|
|
114
113
|
* Exposes a class method as an HTTP DEL endpoint.
|
|
115
114
|
* The method will appear in both backend and generated client APIs.
|
|
116
115
|
*/
|
|
117
|
-
export const DELETE = (
|
|
116
|
+
export const DELETE = () => { };
|
|
118
117
|
/**
|
|
119
118
|
* Declares a static property as a data source.
|
|
120
119
|
*
|
|
@@ -155,7 +154,7 @@ export const DELETE = (_) => { };
|
|
|
155
154
|
* // => Person { id: 1, dogId: 2, dog: { id: 2, name: "Fido" } }[]
|
|
156
155
|
* ```
|
|
157
156
|
*/
|
|
158
|
-
export const DataSource = (
|
|
157
|
+
export const DataSource = () => { };
|
|
159
158
|
/**
|
|
160
159
|
* Declares a one-to-many relationship between models.
|
|
161
160
|
*
|
|
@@ -209,7 +208,7 @@ export const ManyToMany = (_uniqueId) => () => { };
|
|
|
209
208
|
* dogId: number;
|
|
210
209
|
* ```
|
|
211
210
|
*/
|
|
212
|
-
export const ForeignKey = (
|
|
211
|
+
export const ForeignKey = (_Model) => () => { };
|
|
213
212
|
/**
|
|
214
213
|
* Marks a method parameter for dependency injection.
|
|
215
214
|
*
|
|
@@ -393,7 +392,11 @@ export class Orm {
|
|
|
393
392
|
WasmResource.fromString(JSON.stringify(opts.tagCte ?? null), wasm),
|
|
394
393
|
WasmResource.fromString(JSON.stringify(opts.from ?? null), wasm),
|
|
395
394
|
];
|
|
396
|
-
|
|
395
|
+
const res = invokeOrmWasm(wasm.list_models, args, wasm);
|
|
396
|
+
if (res.isLeft()) {
|
|
397
|
+
throw new Error(`Error invoking the Cloesce WASM Binary: ${res.value}`);
|
|
398
|
+
}
|
|
399
|
+
return res.unwrap();
|
|
397
400
|
}
|
|
398
401
|
/**
|
|
399
402
|
* Returns a select query for a single model by primary key, creating a CTE view using the provided include tree.
|
|
@@ -422,9 +425,7 @@ export class Orm {
|
|
|
422
425
|
*/
|
|
423
426
|
static getQuery(ctor, includeTree) {
|
|
424
427
|
const { ast } = RuntimeContainer.get();
|
|
425
|
-
return this.listQuery(ctor, {
|
|
426
|
-
includeTree,
|
|
427
|
-
}).map((inner) => `${inner} WHERE [${ast.models[ctor.name].primary_key.name}] = ?`);
|
|
428
|
+
return `${this.listQuery(ctor, { includeTree })} WHERE [${ast.models[ctor.name].primary_key.name}] = ?`;
|
|
428
429
|
}
|
|
429
430
|
/**
|
|
430
431
|
* Retrieves all instances of a model from the database.
|
|
@@ -457,11 +458,8 @@ export class Orm {
|
|
|
457
458
|
*
|
|
458
459
|
*/
|
|
459
460
|
async list(ctor, opts) {
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
return Either.left(queryRes.value);
|
|
463
|
-
}
|
|
464
|
-
const stmt = this.db.prepare(queryRes.value);
|
|
461
|
+
const sql = Orm.listQuery(ctor, opts);
|
|
462
|
+
const stmt = this.db.prepare(sql);
|
|
465
463
|
const records = await stmt.all();
|
|
466
464
|
if (!records.success) {
|
|
467
465
|
return Either.left(records.error ?? "D1 query failed, but no error was returned.");
|
|
@@ -486,11 +484,8 @@ export class Orm {
|
|
|
486
484
|
* ```
|
|
487
485
|
*/
|
|
488
486
|
async get(ctor, id, includeTree) {
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
return Either.left(queryRes.value);
|
|
492
|
-
}
|
|
493
|
-
const record = await this.db.prepare(queryRes.value).bind(id).run();
|
|
487
|
+
const sql = Orm.getQuery(ctor, includeTree);
|
|
488
|
+
const record = await this.db.prepare(sql).bind(id).run();
|
|
494
489
|
if (!record.success) {
|
|
495
490
|
return Either.left(record.error ?? "D1 query failed, but no error was returned.");
|
|
496
491
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloesce",
|
|
3
|
-
"version": "0.0.4-unstable.
|
|
3
|
+
"version": "0.0.4-unstable.9",
|
|
4
4
|
"description": "A tool to extract and compile TypeScript code into something wrangler can consume and deploy for D1 Databases and Cloudflare Workers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|