cloesce 0.0.3 → 0.0.4-unstable.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.
- package/README.md +488 -23
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +221 -254
- package/dist/common.d.ts +69 -1
- package/dist/common.d.ts.map +1 -1
- package/dist/common.js +72 -11
- package/dist/{extract.d.ts → extractor/extract.d.ts} +5 -2
- package/dist/extractor/extract.d.ts.map +1 -0
- package/dist/{extract.js → extractor/extract.js} +242 -43
- package/dist/generator.wasm +0 -0
- package/dist/orm.wasm +0 -0
- package/dist/router/crud.d.ts +22 -0
- package/dist/router/crud.d.ts.map +1 -0
- package/dist/router/crud.js +65 -0
- package/dist/router/router.d.ts +77 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/router.js +358 -0
- package/dist/router/wasm.d.ts +37 -0
- package/dist/router/wasm.d.ts.map +1 -0
- package/dist/router/wasm.js +98 -0
- package/dist/ui/backend.d.ts +124 -0
- package/dist/ui/backend.d.ts.map +1 -0
- package/dist/ui/backend.js +201 -0
- package/dist/ui/client.d.ts +5 -0
- package/dist/ui/client.d.ts.map +1 -0
- package/dist/ui/client.js +7 -0
- package/package.json +70 -58
- package/LICENSE +0 -201
- package/dist/cli.wasm +0 -0
- package/dist/cloesce.d.ts +0 -108
- package/dist/cloesce.d.ts.map +0 -1
- package/dist/cloesce.js +0 -453
- package/dist/decorators.d.ts +0 -13
- package/dist/decorators.d.ts.map +0 -1
- package/dist/decorators.js +0 -13
- package/dist/dog.cloesce.js +0 -111
- package/dist/extract.d.ts.map +0 -1
- package/dist/index.d.ts +0 -24
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -24
- package/dist/types.d.ts +0 -4
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { D1Database } from "@cloudflare/workers-types/experimental/index.js";
|
|
2
|
+
import { CrudKind, Either, KeysOfType } from "../common.js";
|
|
3
|
+
export { cloesce } from "../router/router.js";
|
|
4
|
+
export type { HttpResult, Either, DeepPartial, InstanceRegistry, CrudKind, } from "../common.js";
|
|
5
|
+
export { CloesceApp } from "../common.js";
|
|
6
|
+
export declare const D1: ClassDecorator;
|
|
7
|
+
export declare const PlainOldObject: ClassDecorator;
|
|
8
|
+
export declare const WranglerEnv: ClassDecorator;
|
|
9
|
+
export declare const PrimaryKey: PropertyDecorator;
|
|
10
|
+
export declare const GET: MethodDecorator;
|
|
11
|
+
export declare const POST: MethodDecorator;
|
|
12
|
+
export declare const PUT: MethodDecorator;
|
|
13
|
+
export declare const PATCH: MethodDecorator;
|
|
14
|
+
export declare const DELETE: MethodDecorator;
|
|
15
|
+
export declare const DataSource: PropertyDecorator;
|
|
16
|
+
export declare const OneToMany: (_: string) => PropertyDecorator;
|
|
17
|
+
export declare const OneToOne: (_: string) => PropertyDecorator;
|
|
18
|
+
export declare const ManyToMany: (_: string) => PropertyDecorator;
|
|
19
|
+
export declare const ForeignKey: <T>(_: T | string) => PropertyDecorator;
|
|
20
|
+
export declare const Inject: ParameterDecorator;
|
|
21
|
+
export declare const CRUD: (_kinds: CrudKind[]) => ClassDecorator;
|
|
22
|
+
type Primitive = string | number | boolean | bigint | symbol | null | undefined;
|
|
23
|
+
export type IncludeTree<T> = T extends Primitive ? never : {
|
|
24
|
+
[K in keyof T]?: T[K] extends (infer U)[] ? IncludeTree<NonNullable<U>> : IncludeTree<NonNullable<T[K]>>;
|
|
25
|
+
};
|
|
26
|
+
export type DataSourceOf<T extends object> = KeysOfType<T, IncludeTree<T>> | "none";
|
|
27
|
+
/**
|
|
28
|
+
* ORM functions which use metadata to translate arguments to valid SQL queries.
|
|
29
|
+
*/
|
|
30
|
+
export declare class Orm {
|
|
31
|
+
private db;
|
|
32
|
+
private constructor();
|
|
33
|
+
/**
|
|
34
|
+
* Creates an instance of an `Orm`
|
|
35
|
+
* @param db The database to use for ORM calls.
|
|
36
|
+
*/
|
|
37
|
+
static fromD1(db: D1Database): Orm;
|
|
38
|
+
/**
|
|
39
|
+
* Maps SQL records to an instantiated Model. The records must be flat
|
|
40
|
+
* (e.g., of the form "id, name, address") or derive from a Cloesce data source view
|
|
41
|
+
* (e.g., of the form "Horse.id, Horse.name, Horse.address")
|
|
42
|
+
* @param ctor The model constructor
|
|
43
|
+
* @param records D1 Result records
|
|
44
|
+
* @param includeTree Include tree to define the relationships to join.
|
|
45
|
+
* @returns
|
|
46
|
+
*/
|
|
47
|
+
static fromSql<T extends object>(ctor: new () => T, records: Record<string, any>[], includeTree: IncludeTree<T> | null): Either<string, T[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Returns a SQL query to insert a model into the database. Uses an IncludeTree as a guide for
|
|
50
|
+
* foreign key relationships, only inserting the explicitly stated pattern in the tree.
|
|
51
|
+
*
|
|
52
|
+
* TODO: We should be able to leave primary keys and foreign keys undefined, with
|
|
53
|
+
* primary keys being auto incremented and foreign keys being assumed by navigation property
|
|
54
|
+
* context.
|
|
55
|
+
*
|
|
56
|
+
* @param ctor A model constructor.
|
|
57
|
+
* @param newModel The new model to insert.
|
|
58
|
+
* @param includeTree An include tree describing which foreign keys to join.
|
|
59
|
+
* @returns Either an error string, or the insert query string.
|
|
60
|
+
*/
|
|
61
|
+
static upsertQuery<T extends object>(ctor: new () => T, newModel: T, includeTree: IncludeTree<T> | null): Either<string, string>;
|
|
62
|
+
/**
|
|
63
|
+
* Executes an "upsert" query, adding or augmenting a model in the database.
|
|
64
|
+
* If a model's primary key is not defined in `newModel`, the query is assumed to be an insert.
|
|
65
|
+
* If a model's primary key _is_ defined, but some attributes are missing, the query is assumed to be an update.
|
|
66
|
+
* Finally, if the primary key is defined, but all attributes are included, a SQLite upsert will be performed.
|
|
67
|
+
*
|
|
68
|
+
* Capable of inferring foreign keys from the surrounding context of the model. A missing primary key is allowed
|
|
69
|
+
* only if the primary key is an integer, in which case it will be auto incremented and assigned.
|
|
70
|
+
*
|
|
71
|
+
* ### Inserting a new Model
|
|
72
|
+
* ```ts
|
|
73
|
+
* const model = {name: "julio", lastname: "pumpkin"};
|
|
74
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* ### Updating an existing model
|
|
78
|
+
* ```ts
|
|
79
|
+
* const model = {id: 1, name: "timothy"};
|
|
80
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
81
|
+
* // (in db)=> {id: 1, name: "timothy", lastname: "pumpkin"}
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* ### Upserting a model
|
|
85
|
+
* ```ts
|
|
86
|
+
* // (assume a Person already exists)
|
|
87
|
+
* const model = {
|
|
88
|
+
* id: 1,
|
|
89
|
+
* lastname: "burger", // updates last name
|
|
90
|
+
* dog: {
|
|
91
|
+
* name: "fido" // insert dog relationship
|
|
92
|
+
* }
|
|
93
|
+
* };
|
|
94
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
95
|
+
* // (in db)=> Person: {id: 1, dogId: 1 ...} ; Dog: {id: 1, name: "fido"}
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* @param ctor A model constructor.
|
|
99
|
+
* @param newModel The new or augmented model.
|
|
100
|
+
* @param includeTree An include tree describing which foreign keys to join.
|
|
101
|
+
* @returns An error string, or the primary key of the inserted model.
|
|
102
|
+
*/
|
|
103
|
+
upsert<T extends object>(ctor: new () => T, newModel: T, includeTree: IncludeTree<T> | null): Promise<Either<string, any>>;
|
|
104
|
+
/**
|
|
105
|
+
* Returns a query of the form `SELECT * FROM [Model.DataSource]`
|
|
106
|
+
*/
|
|
107
|
+
static listQuery<T extends object>(ctor: new () => T, includeTree: KeysOfType<T, IncludeTree<T>> | null): string;
|
|
108
|
+
/**
|
|
109
|
+
* Returns a query of the form `SELECT * FROM [Model.DataSource] WHERE [Model.PrimaryKey] = ?`.
|
|
110
|
+
* Requires the id parameter to be bound (use db.prepare().bind)
|
|
111
|
+
*/
|
|
112
|
+
static getQuery<T extends object>(ctor: new () => T, includeTree: KeysOfType<T, IncludeTree<T>> | null): string;
|
|
113
|
+
/**
|
|
114
|
+
* Executes a query of the form `SELECT * FROM [Model.DataSource]`, returning all results
|
|
115
|
+
* as instantiated models.
|
|
116
|
+
*/
|
|
117
|
+
list<T extends object>(ctor: new () => T, includeTreeKey: KeysOfType<T, IncludeTree<T>> | null): Promise<Either<string, T[]>>;
|
|
118
|
+
/**
|
|
119
|
+
* Executes a query of the form `SELECT * FROM [Model.DataSource] WHERE [Model.PrimaryKey] = ?`
|
|
120
|
+
* returning all results as instantiated models.
|
|
121
|
+
*/
|
|
122
|
+
get<T extends object>(ctor: new () => T, id: any, includeTreeKey: KeysOfType<T, IncludeTree<T>> | null): Promise<Either<string, T>>;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/ui/backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { left, right } from "../common.js";
|
|
2
|
+
import { RuntimeContainer } from "../router/router.js";
|
|
3
|
+
import { WasmResource, fromSql, invokeOrmWasm } from "../router/wasm.js";
|
|
4
|
+
export { cloesce } from "../router/router.js";
|
|
5
|
+
export { CloesceApp } from "../common.js";
|
|
6
|
+
// Compiler hints
|
|
7
|
+
export const D1 = () => { };
|
|
8
|
+
export const PlainOldObject = () => { };
|
|
9
|
+
export const WranglerEnv = () => { };
|
|
10
|
+
export const PrimaryKey = () => { };
|
|
11
|
+
export const GET = () => { };
|
|
12
|
+
export const POST = () => { };
|
|
13
|
+
export const PUT = () => { };
|
|
14
|
+
export const PATCH = () => { };
|
|
15
|
+
export const DELETE = () => { };
|
|
16
|
+
export const DataSource = () => { };
|
|
17
|
+
export const OneToMany = (_) => () => { };
|
|
18
|
+
export const OneToOne = (_) => () => { };
|
|
19
|
+
export const ManyToMany = (_) => () => { };
|
|
20
|
+
export const ForeignKey = (_) => () => { };
|
|
21
|
+
export const Inject = () => { };
|
|
22
|
+
export const CRUD = (_kinds) => () => { };
|
|
23
|
+
/**
|
|
24
|
+
* ORM functions which use metadata to translate arguments to valid SQL queries.
|
|
25
|
+
*/
|
|
26
|
+
export class Orm {
|
|
27
|
+
db;
|
|
28
|
+
constructor(db) {
|
|
29
|
+
this.db = db;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates an instance of an `Orm`
|
|
33
|
+
* @param db The database to use for ORM calls.
|
|
34
|
+
*/
|
|
35
|
+
static fromD1(db) {
|
|
36
|
+
return new Orm(db);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Maps SQL records to an instantiated Model. The records must be flat
|
|
40
|
+
* (e.g., of the form "id, name, address") or derive from a Cloesce data source view
|
|
41
|
+
* (e.g., of the form "Horse.id, Horse.name, Horse.address")
|
|
42
|
+
* @param ctor The model constructor
|
|
43
|
+
* @param records D1 Result records
|
|
44
|
+
* @param includeTree Include tree to define the relationships to join.
|
|
45
|
+
* @returns
|
|
46
|
+
*/
|
|
47
|
+
static fromSql(ctor, records, includeTree) {
|
|
48
|
+
return fromSql(ctor, records, includeTree);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Returns a SQL query to insert a model into the database. Uses an IncludeTree as a guide for
|
|
52
|
+
* foreign key relationships, only inserting the explicitly stated pattern in the tree.
|
|
53
|
+
*
|
|
54
|
+
* TODO: We should be able to leave primary keys and foreign keys undefined, with
|
|
55
|
+
* primary keys being auto incremented and foreign keys being assumed by navigation property
|
|
56
|
+
* context.
|
|
57
|
+
*
|
|
58
|
+
* @param ctor A model constructor.
|
|
59
|
+
* @param newModel The new model to insert.
|
|
60
|
+
* @param includeTree An include tree describing which foreign keys to join.
|
|
61
|
+
* @returns Either an error string, or the insert query string.
|
|
62
|
+
*/
|
|
63
|
+
static upsertQuery(ctor, newModel, includeTree) {
|
|
64
|
+
const { wasm } = RuntimeContainer.get();
|
|
65
|
+
const args = [
|
|
66
|
+
WasmResource.fromString(ctor.name, wasm),
|
|
67
|
+
WasmResource.fromString(JSON.stringify(newModel), wasm),
|
|
68
|
+
WasmResource.fromString(JSON.stringify(includeTree), wasm),
|
|
69
|
+
];
|
|
70
|
+
return invokeOrmWasm(wasm.upsert_model, args, wasm);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Executes an "upsert" query, adding or augmenting a model in the database.
|
|
74
|
+
* If a model's primary key is not defined in `newModel`, the query is assumed to be an insert.
|
|
75
|
+
* If a model's primary key _is_ defined, but some attributes are missing, the query is assumed to be an update.
|
|
76
|
+
* Finally, if the primary key is defined, but all attributes are included, a SQLite upsert will be performed.
|
|
77
|
+
*
|
|
78
|
+
* Capable of inferring foreign keys from the surrounding context of the model. A missing primary key is allowed
|
|
79
|
+
* only if the primary key is an integer, in which case it will be auto incremented and assigned.
|
|
80
|
+
*
|
|
81
|
+
* ### Inserting a new Model
|
|
82
|
+
* ```ts
|
|
83
|
+
* const model = {name: "julio", lastname: "pumpkin"};
|
|
84
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* ### Updating an existing model
|
|
88
|
+
* ```ts
|
|
89
|
+
* const model = {id: 1, name: "timothy"};
|
|
90
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
91
|
+
* // (in db)=> {id: 1, name: "timothy", lastname: "pumpkin"}
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* ### Upserting a model
|
|
95
|
+
* ```ts
|
|
96
|
+
* // (assume a Person already exists)
|
|
97
|
+
* const model = {
|
|
98
|
+
* id: 1,
|
|
99
|
+
* lastname: "burger", // updates last name
|
|
100
|
+
* dog: {
|
|
101
|
+
* name: "fido" // insert dog relationship
|
|
102
|
+
* }
|
|
103
|
+
* };
|
|
104
|
+
* const idRes = await orm.upsert(Person, model, null);
|
|
105
|
+
* // (in db)=> Person: {id: 1, dogId: 1 ...} ; Dog: {id: 1, name: "fido"}
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @param ctor A model constructor.
|
|
109
|
+
* @param newModel The new or augmented model.
|
|
110
|
+
* @param includeTree An include tree describing which foreign keys to join.
|
|
111
|
+
* @returns An error string, or the primary key of the inserted model.
|
|
112
|
+
*/
|
|
113
|
+
async upsert(ctor, newModel, includeTree) {
|
|
114
|
+
let upsertQueryRes = Orm.upsertQuery(ctor, newModel, includeTree);
|
|
115
|
+
if (!upsertQueryRes.ok) {
|
|
116
|
+
return upsertQueryRes;
|
|
117
|
+
}
|
|
118
|
+
// Split the query into individual statements.
|
|
119
|
+
const statements = upsertQueryRes.value
|
|
120
|
+
.split(";")
|
|
121
|
+
.map((s) => s.trim())
|
|
122
|
+
.filter((s) => s.length > 0);
|
|
123
|
+
// One of these statements is a "SELECT", which is the root model id stmt.
|
|
124
|
+
let selectIndex;
|
|
125
|
+
for (let i = statements.length - 1; i >= 0; i--) {
|
|
126
|
+
if (/^SELECT/i.test(statements[i])) {
|
|
127
|
+
selectIndex = i;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Execute all statements in a batch.
|
|
132
|
+
const batchRes = await this.db.batch(statements.map((s) => this.db.prepare(s)));
|
|
133
|
+
if (!batchRes.every((r) => r.success)) {
|
|
134
|
+
const failed = batchRes.find((r) => !r.success);
|
|
135
|
+
return left(failed?.error ?? "D1 batch failed, but no error was returned.");
|
|
136
|
+
}
|
|
137
|
+
// Return the result of the SELECT statement
|
|
138
|
+
const selectResult = batchRes[selectIndex].results[0];
|
|
139
|
+
return right(selectResult.id);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Returns a query of the form `SELECT * FROM [Model.DataSource]`
|
|
143
|
+
*/
|
|
144
|
+
static listQuery(ctor, includeTree) {
|
|
145
|
+
if (includeTree) {
|
|
146
|
+
return `SELECT * FROM [${ctor.name}.${includeTree.toString()}]`;
|
|
147
|
+
}
|
|
148
|
+
return `SELECT * FROM [${ctor.name}]`;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Returns a query of the form `SELECT * FROM [Model.DataSource] WHERE [Model.PrimaryKey] = ?`.
|
|
152
|
+
* Requires the id parameter to be bound (use db.prepare().bind)
|
|
153
|
+
*/
|
|
154
|
+
static getQuery(ctor, includeTree) {
|
|
155
|
+
const { ast } = RuntimeContainer.get();
|
|
156
|
+
if (includeTree) {
|
|
157
|
+
return `${this.listQuery(ctor, includeTree)} WHERE [${ctor.name}.${ast.models[ctor.name].primary_key.name}] = ?`;
|
|
158
|
+
}
|
|
159
|
+
return `${this.listQuery(ctor, includeTree)} WHERE [${ast.models[ctor.name].primary_key.name}] = ?`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Executes a query of the form `SELECT * FROM [Model.DataSource]`, returning all results
|
|
163
|
+
* as instantiated models.
|
|
164
|
+
*/
|
|
165
|
+
async list(ctor, includeTreeKey) {
|
|
166
|
+
const q = Orm.listQuery(ctor, includeTreeKey);
|
|
167
|
+
const res = await this.db.prepare(q).run();
|
|
168
|
+
if (!res.success) {
|
|
169
|
+
return left(res.error ?? "D1 failed but no error was returned.");
|
|
170
|
+
}
|
|
171
|
+
const { ast } = RuntimeContainer.get();
|
|
172
|
+
const includeTree = includeTreeKey === null
|
|
173
|
+
? null
|
|
174
|
+
: ast.models[ctor.name].data_sources[includeTreeKey.toString()].tree;
|
|
175
|
+
const fromSqlRes = fromSql(ctor, res.results, includeTree);
|
|
176
|
+
if (!fromSqlRes.ok) {
|
|
177
|
+
return fromSqlRes;
|
|
178
|
+
}
|
|
179
|
+
return right(fromSqlRes.value);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Executes a query of the form `SELECT * FROM [Model.DataSource] WHERE [Model.PrimaryKey] = ?`
|
|
183
|
+
* returning all results as instantiated models.
|
|
184
|
+
*/
|
|
185
|
+
async get(ctor, id, includeTreeKey) {
|
|
186
|
+
const q = Orm.getQuery(ctor, includeTreeKey);
|
|
187
|
+
const res = await this.db.prepare(q).bind(id).run();
|
|
188
|
+
if (!res.success) {
|
|
189
|
+
return left(res.error ?? "D1 failed but no error was returned.");
|
|
190
|
+
}
|
|
191
|
+
const { ast } = RuntimeContainer.get();
|
|
192
|
+
const includeTree = includeTreeKey === null
|
|
193
|
+
? null
|
|
194
|
+
: ast.models[ctor.name].data_sources[includeTreeKey.toString()].tree;
|
|
195
|
+
const fromSqlRes = fromSql(ctor, res.results, includeTree);
|
|
196
|
+
if (!fromSqlRes.ok) {
|
|
197
|
+
return fromSqlRes;
|
|
198
|
+
}
|
|
199
|
+
return right(fromSqlRes.value[0]);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ui/client.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGpE,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,EACrD,IAAI,EAAE,GAAG,EACT,IAAI,EAAE;IAAE,QAAQ,CAAC,CAAA;CAAE,GAClB,CAAC,EAAE,CAKL"}
|
package/package.json
CHANGED
|
@@ -1,58 +1,70 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cloesce",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "A tool to extract and compile TypeScript code into something wrangler can consume and deploy for D1 Databases and Cloudflare Workers",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "Apache-2.0",
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "cloesce",
|
|
3
|
+
"version": "0.0.4-unstable.1",
|
|
4
|
+
"description": "A tool to extract and compile TypeScript code into something wrangler can consume and deploy for D1 Databases and Cloudflare Workers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "vitest",
|
|
9
|
+
"format:fix": "prettier --write .",
|
|
10
|
+
"format": "prettier --check .",
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"build": "tsc -p tsconfig.json && npm run copy-rs-orm-wasm && npm run copy-generator-wasm && chmod +x dist/cli.js",
|
|
13
|
+
"copy-rs-orm-wasm": "cp ../orm/target/wasm32-unknown-unknown/release/orm.wasm ./dist/orm.wasm",
|
|
14
|
+
"copy-generator-wasm": "cp ../../generator/target/wasm32-wasip1/release/cli.wasm ./dist/generator.wasm"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"cmd-ts": "^0.14.1",
|
|
18
|
+
"ts-morph": "^22.0.0",
|
|
19
|
+
"wrangler": "^4.34.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@cloudflare/workers-types": "^4.20250906.0",
|
|
23
|
+
"ts-node": "^10.9.2",
|
|
24
|
+
"typescript": "^5.6.0",
|
|
25
|
+
"prettier": "^3.6.2",
|
|
26
|
+
"vitest": "^3.2.4"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
"./client": {
|
|
30
|
+
"types": "./dist/ui/client.d.ts",
|
|
31
|
+
"import": "./dist/ui/client.js"
|
|
32
|
+
},
|
|
33
|
+
"./backend": {
|
|
34
|
+
"types": "./dist/ui/backend.d.ts",
|
|
35
|
+
"import": "./dist/ui/backend.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"bin": {
|
|
39
|
+
"cloesce": "dist/cli.js"
|
|
40
|
+
},
|
|
41
|
+
"typesVersions": {
|
|
42
|
+
"*": {
|
|
43
|
+
"backend": [
|
|
44
|
+
"dist/ui/backend.d.ts"
|
|
45
|
+
],
|
|
46
|
+
"client": [
|
|
47
|
+
"dist/ui/client.d.ts"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist/**/*"
|
|
53
|
+
],
|
|
54
|
+
"sideEffects": false,
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=18.17"
|
|
57
|
+
},
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git+https://github.com/bens-schreiber/cloesce.git"
|
|
61
|
+
},
|
|
62
|
+
"homepage": "https://github.com/bens-schreiber/cloesce",
|
|
63
|
+
"keywords": [
|
|
64
|
+
"cloudflare",
|
|
65
|
+
"workers",
|
|
66
|
+
"d1",
|
|
67
|
+
"orm",
|
|
68
|
+
"cli"
|
|
69
|
+
]
|
|
70
|
+
}
|