@isaijs/core 0.1.4 → 0.1.6
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/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +2 -2
- package/dist/case-DpXlJCL9.js +63 -0
- package/dist/cli/index.js +10 -6
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.js +119 -5
- package/dist/{create-auth-9y_43vJf.js → create-auth-BFKvQVOG.js} +18 -10
- package/dist/{data-layer-D1BFo3wO.d.ts → data-layer-43pme0Gy.d.ts} +13 -1
- package/dist/{data-layer-_TZtuy-F.js → data-layer-C5oJZ8V1.js} +16 -3
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +4 -4
- package/dist/{index-DlgVg3D8.d.ts → index-a7ElyL3B.d.ts} +67 -34
- package/dist/index.d.ts +1 -1
- package/dist/index.js +136 -17
- package/dist/{make-DKBn79cH.js → make-ByA-84h8.js} +1 -1
- package/dist/{makers-DeSNM0Nd.js → makers-P9kg68C8.js} +2 -2
- package/dist/{migrator-BU3_PHk8.js → migrator-B25prc9n.js} +152 -108
- package/dist/{base64url-C5GTYIL5.js → model-Dc3HunKb.js} +424 -418
- package/dist/{policies-D_G5Rmxv.js → policies-KsqmlX67.js} +1 -1
- package/dist/{resource-CkzoR3Rq.js → resource-BQK7bkPQ.js} +5 -3
- package/dist/{tables-IrLjsomf.js → tables-DgSwge7s.js} +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +4 -4
- package/dist/{types-S6zF5IXV.d.ts → types-BgOkJy5d.d.ts} +17 -3
- package/package.json +1 -1
- package/dist/case-BnpcvhdW.js +0 -11
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { r as AuthTablesOptions } from "../data-layer-
|
|
2
|
-
import { A as Permissions, F as
|
|
1
|
+
import { r as AuthTablesOptions } from "../data-layer-43pme0Gy.js";
|
|
2
|
+
import { A as Permissions, F as Policy, I as Rules, L as StandardAction, M as Bound, N as DefinePolicy, P as Perms, a as OAuthMethod, c as Roles, i as Methods, j as AnyPolicy, l as SignInMethod, n as AuthConfig, o as Provider, r as AuthDefinition, s as RoleDefinition, t as Auth, u as createAuth } from "../index-a7ElyL3B.js";
|
|
3
3
|
export { type AnyPolicy, Auth, type AuthConfig, type AuthDefinition, type AuthTablesOptions, type Bound, type DefinePolicy, type Methods, type OAuthMethod, type Permissions, type Perms, Policy, type Provider, type RoleDefinition, type Roles, type Rules, type SignInMethod, type StandardAction, createAuth };
|
package/dist/auth/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as Policy } from "../policies-
|
|
2
|
-
import { a as createAuth, t as Auth } from "../create-auth-
|
|
1
|
+
import { t as Policy } from "../policies-KsqmlX67.js";
|
|
2
|
+
import { a as createAuth, t as Auth } from "../create-auth-BFKvQVOG.js";
|
|
3
3
|
export { Auth, Policy, createAuth };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//#region src/internal/ulid.ts
|
|
2
|
+
/**
|
|
3
|
+
* ULIDs: 48 bits of milliseconds + 80 random bits, Crockford base32, 26 characters.
|
|
4
|
+
* Generated in JS (works inside a D1 batch, the same on every driver) and sortable by time.
|
|
5
|
+
*
|
|
6
|
+
* Monotonic: ids made in the same millisecond (or after the clock stepped back) reuse the
|
|
7
|
+
* last time and add one to the last random part, so ids always sort in the order they were
|
|
8
|
+
* made within an isolate or process.
|
|
9
|
+
*/
|
|
10
|
+
const ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
11
|
+
const RANDOM_LENGTH = 16;
|
|
12
|
+
function encodeTime(time) {
|
|
13
|
+
let rest = time;
|
|
14
|
+
let text = "";
|
|
15
|
+
for (let i = 0; i < 10; i++) {
|
|
16
|
+
text = ALPHABET.charAt(rest % 32) + text;
|
|
17
|
+
rest = Math.floor(rest / 32);
|
|
18
|
+
}
|
|
19
|
+
return text;
|
|
20
|
+
}
|
|
21
|
+
function randomDigits() {
|
|
22
|
+
return Array.from(crypto.getRandomValues(new Uint8Array(RANDOM_LENGTH)), (byte) => byte % 32);
|
|
23
|
+
}
|
|
24
|
+
/** Adds one to base-32 digits in place; false when they were all at the maximum. */
|
|
25
|
+
function increment(digits) {
|
|
26
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
27
|
+
if ((digits[i] ?? 0) < 31) {
|
|
28
|
+
digits[i] = (digits[i] ?? 0) + 1;
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
digits[i] = 0;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
function monotonicUlid() {
|
|
36
|
+
let lastTime = -1;
|
|
37
|
+
let lastRandom = [];
|
|
38
|
+
return (now) => {
|
|
39
|
+
const time = now.getTime();
|
|
40
|
+
if (time > lastTime) {
|
|
41
|
+
lastTime = time;
|
|
42
|
+
lastRandom = randomDigits();
|
|
43
|
+
} else if (!increment(lastRandom)) {
|
|
44
|
+
lastTime += 1;
|
|
45
|
+
lastRandom = randomDigits();
|
|
46
|
+
}
|
|
47
|
+
return encodeTime(lastTime) + lastRandom.map((digit) => ALPHABET.charAt(digit)).join("");
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** The process-wide generator every write uses. */
|
|
51
|
+
const ulid = monotonicUlid();
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/internal/case.ts
|
|
54
|
+
/** `manageProducts` → `manage-products`, `markPaid` → `mark-paid`: path segments. */
|
|
55
|
+
function kebabCase(name) {
|
|
56
|
+
return snakeCase(name).replace(/_/g, "-");
|
|
57
|
+
}
|
|
58
|
+
/** `RegistrationMember` → `registration_member`, `startsAt` → `starts_at`. */
|
|
59
|
+
function snakeCase(name) {
|
|
60
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toLowerCase();
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { snakeCase as n, ulid as r, kebabCase as t };
|
package/dist/cli/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { V as toKind, z as object } from "../validation-Cppmd0RV.js";
|
|
3
|
-
import {
|
|
4
|
-
import { a as lookupsOf, i as filterableOf, n as isRequired, t as Resource, u as Route } from "../resource-
|
|
5
|
-
import {
|
|
6
|
-
import { t as kebabCase } from "../case-
|
|
7
|
-
import { i as makeMigrations, n as checkSteps, t as checkMigrations } from "../make-
|
|
3
|
+
import { F as dialectFor, m as emptySnapshot, r as sync, t as migrate, y as MigrationError } from "../migrator-B25prc9n.js";
|
|
4
|
+
import { a as lookupsOf, i as filterableOf, n as isRequired, t as Resource, u as Route } from "../resource-BQK7bkPQ.js";
|
|
5
|
+
import { o as fieldOf, p as sensitivity, t as Model } from "../model-Dc3HunKb.js";
|
|
6
|
+
import { t as kebabCase } from "../case-DpXlJCL9.js";
|
|
7
|
+
import { i as makeMigrations, n as checkSteps, t as checkMigrations } from "../make-ByA-84h8.js";
|
|
8
8
|
import { d1 } from "../adapters/database/d1/index.js";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
import { parseArgs } from "node:util";
|
|
@@ -57,7 +57,11 @@ function typeOf(node, models, registry) {
|
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/codegen/client.ts
|
|
59
59
|
/** Names the client has for itself; an export can't take them. */
|
|
60
|
-
const TAKEN = /* @__PURE__ */ new Set([
|
|
60
|
+
const TAKEN = /* @__PURE__ */ new Set([
|
|
61
|
+
"auth",
|
|
62
|
+
"onSignedOut",
|
|
63
|
+
"onPending"
|
|
64
|
+
]);
|
|
61
65
|
function generateClient(source) {
|
|
62
66
|
const names = [...source.resources.map((r) => r.name), ...source.routes.map((r) => r.name)];
|
|
63
67
|
const clash = names.find((name, i) => names.indexOf(name) !== i || TAKEN.has(name));
|
package/dist/client/index.d.ts
CHANGED
|
@@ -181,6 +181,11 @@ interface ClientBase<U> {
|
|
|
181
181
|
readonly auth: AuthApi<U>;
|
|
182
182
|
/** Called on any 401 (but `auth.me()`'s): the session ended or never was. Returns an unsubscribe. */
|
|
183
183
|
onSignedOut(listener: () => void): () => void;
|
|
184
|
+
/**
|
|
185
|
+
* Called with how many writes are waiting to be saved: now, then on every change (0 once all
|
|
186
|
+
* are). Returns an unsubscribe.
|
|
187
|
+
*/
|
|
188
|
+
onPending(listener: (count: number) => void): () => void;
|
|
184
189
|
}
|
|
185
190
|
/** The client for an app's endpoints; the generated `createApi` types it. */
|
|
186
191
|
export declare function createClient(endpoints: Endpoints, options?: ClientOptions): unknown;
|
package/dist/client/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as kebabCase } from "../case-
|
|
1
|
+
import { r as ulid, t as kebabCase } from "../case-DpXlJCL9.js";
|
|
2
2
|
//#region src/client/errors.ts
|
|
3
3
|
/**
|
|
4
4
|
* A failed call: the API's one error shape,
|
|
@@ -160,19 +160,50 @@ async function encoded(canvas, name, clear) {
|
|
|
160
160
|
* (a singleton's calls take no key)
|
|
161
161
|
* routes api.<name>(args) (path params and input in one object)
|
|
162
162
|
* auth api.auth.me() · signIn() · signOut() · users · invites
|
|
163
|
+
*
|
|
164
|
+
* Writes survive a dropping connection. Every write (any call but a GET) carries an
|
|
165
|
+
* `Idempotency-Key` of its own, and goes out through one queue, in the order it was made: a
|
|
166
|
+
* product isn't created before the upload it names. A write the network lost (`fetch` threw, the
|
|
167
|
+
* connection went offline under it, or a 5xx came from a proxy rather than the app) is sent again
|
|
168
|
+
* with the same key, so the server runs it once (`api/idempotency.ts`); so is one the server says
|
|
169
|
+
* is still running (409 `InProgress`). It waits 1 s, 2 s, 4 s… up to 30 s between tries, and for
|
|
170
|
+
* the browser to be back online, and never gives up: the call resolves once it's saved. An answer
|
|
171
|
+
* from the app (a 400, a refusal, a 500) fails the call as it did. `api.onPending(count => …)`
|
|
172
|
+
* says how many writes are waiting, for a "saving…" sign; while any are, the page asks before
|
|
173
|
+
* it's closed. Reads aren't queued or retried: a frontend's cache retries them.
|
|
163
174
|
*/
|
|
164
175
|
const QUERY_METHODS = /* @__PURE__ */ new Set(["GET", "DELETE"]);
|
|
176
|
+
/** The waits between a lost write's tries, in ms; the last repeats. */
|
|
177
|
+
const BACKOFF = [
|
|
178
|
+
1e3,
|
|
179
|
+
2e3,
|
|
180
|
+
4e3,
|
|
181
|
+
8e3,
|
|
182
|
+
16e3,
|
|
183
|
+
3e4
|
|
184
|
+
];
|
|
165
185
|
/** The client for an app's endpoints; the generated `createApi` types it. */
|
|
166
186
|
function createClient(endpoints, options = {}) {
|
|
167
187
|
const base = (options.baseUrl ?? "/api").replace(/\/$/, "");
|
|
168
188
|
const send = options.fetch ?? ((input, init) => fetch(input, init));
|
|
169
189
|
const listeners = /* @__PURE__ */ new Set();
|
|
170
|
-
|
|
190
|
+
const writes = writeQueue();
|
|
191
|
+
function call(method, path, options = {}) {
|
|
192
|
+
if (method === "GET") return attempt(method, path, options);
|
|
193
|
+
const key = { "Idempotency-Key": ulid(/* @__PURE__ */ new Date()) };
|
|
194
|
+
return writes.add(() => retried((signal) => attempt(method, path, {
|
|
195
|
+
...options,
|
|
196
|
+
key,
|
|
197
|
+
signal
|
|
198
|
+
})));
|
|
199
|
+
}
|
|
200
|
+
async function attempt(method, path, { query, body, headers: extra, key, signal, signedOutIsAnswer = false }) {
|
|
171
201
|
const search = query && query.size > 0 ? `?${query.toString().replace(/=(?=&|$)/g, "")}` : "";
|
|
172
202
|
const headers = {
|
|
173
203
|
Accept: "application/json",
|
|
174
204
|
...options.headers,
|
|
175
|
-
...extra
|
|
205
|
+
...extra,
|
|
206
|
+
...key
|
|
176
207
|
};
|
|
177
208
|
const file = body instanceof Blob ? body : void 0;
|
|
178
209
|
if (file) {
|
|
@@ -183,8 +214,10 @@ function createClient(endpoints, options = {}) {
|
|
|
183
214
|
const response = await send(`${base}${path}${search}`, {
|
|
184
215
|
method,
|
|
185
216
|
headers,
|
|
186
|
-
...body === void 0 ? {} : { body: file ?? JSON.stringify(body) }
|
|
217
|
+
...body === void 0 ? {} : { body: file ?? JSON.stringify(body) },
|
|
218
|
+
...signal ? { signal } : {}
|
|
187
219
|
});
|
|
220
|
+
if (key && await lost(response)) throw new Lost();
|
|
188
221
|
if (response.status === 401 && signedOutIsAnswer) return void 0;
|
|
189
222
|
if (!response.ok) {
|
|
190
223
|
const error = await errorOf(response);
|
|
@@ -199,7 +232,8 @@ function createClient(endpoints, options = {}) {
|
|
|
199
232
|
onSignedOut(listener) {
|
|
200
233
|
listeners.add(listener);
|
|
201
234
|
return () => listeners.delete(listener);
|
|
202
|
-
}
|
|
235
|
+
},
|
|
236
|
+
onPending: writes.onPending
|
|
203
237
|
};
|
|
204
238
|
for (const [name, endpoint] of Object.entries(endpoints)) {
|
|
205
239
|
if (Object.hasOwn(api, name)) throw new TypeError(`isai: the client's ${name} is taken`);
|
|
@@ -207,6 +241,86 @@ function createClient(endpoints, options = {}) {
|
|
|
207
241
|
}
|
|
208
242
|
return api;
|
|
209
243
|
}
|
|
244
|
+
/** A try the network lost: sent again. */
|
|
245
|
+
var Lost = class extends Error {};
|
|
246
|
+
/**
|
|
247
|
+
* A write's answer that isn't the app's: a 5xx from a proxy (every answer from the app carries
|
|
248
|
+
* `X-Request-Id`), or the app saying the same key is still running.
|
|
249
|
+
*/
|
|
250
|
+
async function lost(response) {
|
|
251
|
+
if (response.status >= 500) return !response.headers.has("X-Request-Id");
|
|
252
|
+
if (response.status !== 409) return false;
|
|
253
|
+
return (await response.clone().json().catch(() => ({}))).error?.code === "InProgress";
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* `run` until it's answered: again after each try the network lost, waiting longer each time and
|
|
257
|
+
* for the browser to be online. A try in flight is aborted when the browser goes offline, since a
|
|
258
|
+
* request on a dropped connection may never end.
|
|
259
|
+
*/
|
|
260
|
+
async function retried(run) {
|
|
261
|
+
for (let tries = 0;; tries++) {
|
|
262
|
+
const aborted = new AbortController();
|
|
263
|
+
const stop = on("offline", () => aborted.abort());
|
|
264
|
+
try {
|
|
265
|
+
return await run(aborted.signal);
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (!(error instanceof Lost) && !(error instanceof TypeError) && !aborted.signal.aborted) throw error;
|
|
268
|
+
} finally {
|
|
269
|
+
stop();
|
|
270
|
+
}
|
|
271
|
+
await Promise.all([pause(BACKOFF[Math.min(tries, BACKOFF.length - 1)]), online()]);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const pause = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
275
|
+
/** Resolves once the browser is online (at once outside one). */
|
|
276
|
+
function online() {
|
|
277
|
+
if (globalThis.navigator?.onLine !== false) return Promise.resolve();
|
|
278
|
+
return new Promise((resolve) => {
|
|
279
|
+
const stop = on("online", () => {
|
|
280
|
+
stop();
|
|
281
|
+
resolve();
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/** Listens for a window event; nothing outside a browser. Returns the unsubscribe. */
|
|
286
|
+
function on(event, listener) {
|
|
287
|
+
const target = globalThis;
|
|
288
|
+
if (typeof target.addEventListener !== "function") return () => {};
|
|
289
|
+
target.addEventListener(event, listener);
|
|
290
|
+
return () => globalThis.removeEventListener(event, listener);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Writes one at a time, in the order they were added, each settling as it's done. A failed one
|
|
294
|
+
* doesn't hold back the next. While any are waiting, closing the page asks first.
|
|
295
|
+
*/
|
|
296
|
+
function writeQueue() {
|
|
297
|
+
let last = Promise.resolve();
|
|
298
|
+
let pending = 0;
|
|
299
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
300
|
+
let stopAsking;
|
|
301
|
+
const changed = (by) => {
|
|
302
|
+
pending += by;
|
|
303
|
+
if (pending > 0) stopAsking ??= on("beforeunload", (event) => event.preventDefault());
|
|
304
|
+
else {
|
|
305
|
+
stopAsking?.();
|
|
306
|
+
stopAsking = void 0;
|
|
307
|
+
}
|
|
308
|
+
for (const listener of [...listeners]) listener(pending);
|
|
309
|
+
};
|
|
310
|
+
return {
|
|
311
|
+
add(write) {
|
|
312
|
+
changed(1);
|
|
313
|
+
const done = last.then(write);
|
|
314
|
+
last = done.catch(() => void 0);
|
|
315
|
+
return done.finally(() => changed(-1));
|
|
316
|
+
},
|
|
317
|
+
onPending(listener) {
|
|
318
|
+
listeners.add(listener);
|
|
319
|
+
listener(pending);
|
|
320
|
+
return () => listeners.delete(listener);
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
}
|
|
210
324
|
const segment = (value) => encodeURIComponent(String(value));
|
|
211
325
|
function resourceCalls(call, endpoint) {
|
|
212
326
|
const base = endpoint.resource;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as PROVIDERS } from "./tables-
|
|
3
|
-
import { a as byRole, c as tenant, i as anyone, l as user, n as PolicyRegistry, o as owner, s as readsTenant } from "./policies-
|
|
1
|
+
import { I as fromBase64url } from "./model-Dc3HunKb.js";
|
|
2
|
+
import { n as PROVIDERS } from "./tables-DgSwge7s.js";
|
|
3
|
+
import { a as byRole, c as tenant, i as anyone, l as user, n as PolicyRegistry, o as owner, s as readsTenant } from "./policies-KsqmlX67.js";
|
|
4
4
|
//#region src/auth/create-auth.ts
|
|
5
5
|
const methods = { oauth: (provider, options) => ({
|
|
6
6
|
kind: "oauth",
|
|
@@ -23,8 +23,8 @@ var Auth = class {
|
|
|
23
23
|
perms = authPerms;
|
|
24
24
|
/** The policies made with this instance's `policy()`. */
|
|
25
25
|
policies = new PolicyRegistry();
|
|
26
|
-
/** Set by the app's core when it starts: `invite` on its current database. */
|
|
27
|
-
|
|
26
|
+
/** Set by the app's core when it starts: `invite` and `revoke` on its current database. */
|
|
27
|
+
people;
|
|
28
28
|
constructor(define) {
|
|
29
29
|
this.define = define;
|
|
30
30
|
}
|
|
@@ -34,12 +34,20 @@ var Auth = class {
|
|
|
34
34
|
* `held: "platform"` puts the assignment beyond the tenant's reach.
|
|
35
35
|
*/
|
|
36
36
|
invite(input) {
|
|
37
|
-
if (!this.
|
|
38
|
-
return this.
|
|
37
|
+
if (!this.people) return Promise.reject(/* @__PURE__ */ new Error("isai: auth.invite is used before the runtime started the app"));
|
|
38
|
+
return this.people.invite(input);
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Takes a role from `email`, from code (replacing a tenant's owner): its invite to the role is
|
|
42
|
+
* deleted, and the role taken away if it has an account in the current database. Safe to repeat.
|
|
43
|
+
*/
|
|
44
|
+
revoke(input) {
|
|
45
|
+
if (!this.people) return Promise.reject(/* @__PURE__ */ new Error("isai: auth.revoke is used before the runtime started the app"));
|
|
46
|
+
return this.people.revoke(input);
|
|
47
|
+
}
|
|
48
|
+
/** The core's: where `invite` and `revoke` write. */
|
|
49
|
+
attach(people) {
|
|
50
|
+
this.people = people;
|
|
43
51
|
}
|
|
44
52
|
/** The config, for this env. Checked here for itself; against the databases by the core. */
|
|
45
53
|
resolve(env) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as DatabaseDriver, o as DialectName } from "./index-Ce5p2-EB.js";
|
|
2
2
|
import { t as Issue } from "./issues-CKto95IW.js";
|
|
3
3
|
import { M as IdInput, Y as StoredFile } from "./index-CYcklQ1l.js";
|
|
4
|
-
import { A as Dialect, G as Model, H as Columns, I as Clock, K as ModelSpec, M as RetiredSnapshot, N as SchemaSnapshot, U as ComputedFields, V as AnyModel, W as Fields, X as Condition, at as count, b as RowOf, dt as Kinds, et as Now, f as seed, ft as SchemaDefaults, ht as Field, i as Row, it as any, mt as AnyField, n as Patch, ot as not, p as Database, q as ModelRegistry, rt as all, yt as Slot } from "./types-
|
|
4
|
+
import { $ as Expr, A as Dialect, G as Model, H as Columns, I as Clock, K as ModelSpec, M as RetiredSnapshot, N as SchemaSnapshot, U as ComputedFields, V as AnyModel, W as Fields, X as Condition, at as count, b as RowOf, dt as Kinds, et as Now, f as seed, ft as SchemaDefaults, ht as Field, i as Row, it as any, mt as AnyField, n as Patch, ot as not, p as Database, q as ModelRegistry, rt as all, yt as Slot } from "./types-BgOkJy5d.js";
|
|
5
5
|
//#region src/db/schema/traits.d.ts
|
|
6
6
|
type ComputedDefinitions = Record<string, (row: any) => Condition>;
|
|
7
7
|
interface TraitSpec {
|
|
@@ -948,6 +948,17 @@ type Base = Kinds & {
|
|
|
948
948
|
type ProjectKinds<P> = { readonly [K in keyof P]: P[K] extends AnyField ? () => P[K] : P[K]; };
|
|
949
949
|
/** The placeholder for conditions over a model's rows: `const event = row(Event)`. */
|
|
950
950
|
declare function row<M extends AnyModel>(target: M): Columns<M["~fields"], M["name"]>;
|
|
951
|
+
/** Every row of a model, for a rule that counts them. See `rows`. */
|
|
952
|
+
interface TableRows<Rows> {
|
|
953
|
+
/** How many rows there are, or how many match. */
|
|
954
|
+
count(build?: (row: Rows) => Condition): Expr<number>;
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Every row of a model, for a rule over all of them: `rows(Product).count()` in a policy's create
|
|
958
|
+
* rule caps how many a tenant may have (`create: rows(Product).count().lt(tenant.maxProducts)`).
|
|
959
|
+
* A create checks it with one query before the insert; two creates at once may both pass.
|
|
960
|
+
*/
|
|
961
|
+
declare function rows<M extends AnyModel>(target: M): TableRows<Columns<M["~fields"], M["name"]>>;
|
|
951
962
|
declare function createDataLayer<P extends Record<string, ProjectKind> = {}, const U extends readonly AnyTableSet[] = []>(define?: (base: Base) => DataLayerDefinition<P, U>): {
|
|
952
963
|
model: {
|
|
953
964
|
<const Name extends string, const T extends readonly AnyTrait[], F extends Fields>(name: Name, ...rest: [...traits: T, fields: F]): Model<Name, TraitFields<T> & F>;
|
|
@@ -979,6 +990,7 @@ declare function createDataLayer<P extends Record<string, ProjectKind> = {}, con
|
|
|
979
990
|
};
|
|
980
991
|
defaults: Readonly<SchemaDefaults>;
|
|
981
992
|
row: typeof row;
|
|
993
|
+
rows: typeof rows;
|
|
982
994
|
all: typeof all;
|
|
983
995
|
any: typeof any;
|
|
984
996
|
not: typeof not;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { F as quantity, k as datetime, m as host, r as isPhoneRegion } from "./validation-Cppmd0RV.js";
|
|
2
|
-
import "./migrator-
|
|
3
|
-
import {
|
|
4
|
-
import { a as TableSet, i as platformAuthDefinitions, o as defineBuiltins, r as authTables } from "./tables-
|
|
2
|
+
import "./migrator-B25prc9n.js";
|
|
3
|
+
import { D as now, E as not, S as any, T as count, a as defineModel, c as rowOf, d as fieldKinds, u as field, x as all, y as Relation } from "./model-Dc3HunKb.js";
|
|
4
|
+
import { a as TableSet, i as platformAuthDefinitions, o as defineBuiltins, r as authTables } from "./tables-DgSwge7s.js";
|
|
5
5
|
import { n as seed } from "./seed-BObmdKdP.js";
|
|
6
6
|
//#region src/db/fields/slot.ts
|
|
7
7
|
var Slot = class {
|
|
@@ -233,6 +233,18 @@ const isOptions = (value) => typeof value === "object" && value !== null && !(va
|
|
|
233
233
|
function row(target) {
|
|
234
234
|
return rowOf(target.spec, target.registry);
|
|
235
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Every row of a model, for a rule over all of them: `rows(Product).count()` in a policy's create
|
|
238
|
+
* rule caps how many a tenant may have (`create: rows(Product).count().lt(tenant.maxProducts)`).
|
|
239
|
+
* A create checks it with one query before the insert; two creates at once may both pass.
|
|
240
|
+
*/
|
|
241
|
+
function rows(target) {
|
|
242
|
+
const { spec, registry } = target;
|
|
243
|
+
return new Relation({
|
|
244
|
+
table: spec.table,
|
|
245
|
+
column: ""
|
|
246
|
+
}, (inner) => rowOf(spec, registry, inner));
|
|
247
|
+
}
|
|
236
248
|
function checkDefaults(defaults) {
|
|
237
249
|
const { phoneRegion, currency } = defaults;
|
|
238
250
|
if (phoneRegion !== void 0 && !isPhoneRegion(phoneRegion)) throw new TypeError(`isai: defaults.phoneRegion "${phoneRegion}" isn't a region (an ISO country code such as "IN")`);
|
|
@@ -286,6 +298,7 @@ function createDataLayer(define) {
|
|
|
286
298
|
traits: builtinTraits(),
|
|
287
299
|
defaults,
|
|
288
300
|
row,
|
|
301
|
+
rows,
|
|
289
302
|
all,
|
|
290
303
|
any,
|
|
291
304
|
not,
|
package/dist/db/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { a as ValidationError } from "../issues-CKto95IW.js";
|
|
2
|
-
import { $ as Expr, A as Dialect, B as newSecretKey, F as snapshotOf, G as Model, I as Clock, J as Models, K as ModelSpec, L as FixedClock, M as RetiredSnapshot, N as SchemaSnapshot, O as Write, P as emptySnapshot, R as fixedClock, V as AnyModel, X as Condition, Y as Column, _ as database, _t as Storage, a as Visible, at as count, bt as slot, c as Many, d as SeedContext, dt as Kinds, et as Now, ft as SchemaDefaults, g as Transaction, gt as FieldSpec, h as RawValue, ht as Field, i as Row, it as any, j as Rule, k as WriteListener, l as Overrides, lt as ConditionNode, m as DatabaseOptions, n as Patch, nt as Total, o as Make, ot as not, p as Database, pt as fieldKinds, r as Planned, rt as all, st as now, t as Insert, tt as Relation, u as Seed, v as OrderKey, vt as sensitivity, y as Query, yt as Slot, z as systemClock } from "../types-
|
|
3
|
-
import { A as MigrateOptions, B as NotFound, C as MigrationErrorCode, D as Cleanup, E as UnsafeMigration, F as DataStep, H as UniqueFailed, I as TODO, L as dataStep, M as migrate, N as migrateFresh, O as cleanupMigration, P as sync, R as CheckFailed, S as MigrationError, T as UnsafeChange, U as dialectFor, V as ReferenceFailed, W as sqlite, _ as Generated, b as manifest, c as acquireLock, d as setReleaseStatus, f as startRelease, g as makeMigrations, h as makeCleanup, j as Migration, k as Manifest, l as releaseLock, m as checkMigrations, n as row, o as Release, p as applyRules, s as ReleaseStatus, t as createDataLayer, u as rollback, v as generateMigration, w as SuspectedRename, x as structureStep, y as cleanupStep, z as DatabaseError } from "../data-layer-
|
|
2
|
+
import { $ as Expr, A as Dialect, B as newSecretKey, F as snapshotOf, G as Model, I as Clock, J as Models, K as ModelSpec, L as FixedClock, M as RetiredSnapshot, N as SchemaSnapshot, O as Write, P as emptySnapshot, R as fixedClock, V as AnyModel, X as Condition, Y as Column, _ as database, _t as Storage, a as Visible, at as count, bt as slot, c as Many, d as SeedContext, dt as Kinds, et as Now, ft as SchemaDefaults, g as Transaction, gt as FieldSpec, h as RawValue, ht as Field, i as Row, it as any, j as Rule, k as WriteListener, l as Overrides, lt as ConditionNode, m as DatabaseOptions, n as Patch, nt as Total, o as Make, ot as not, p as Database, pt as fieldKinds, r as Planned, rt as all, st as now, t as Insert, tt as Relation, u as Seed, v as OrderKey, vt as sensitivity, y as Query, yt as Slot, z as systemClock } from "../types-BgOkJy5d.js";
|
|
3
|
+
import { A as MigrateOptions, B as NotFound, C as MigrationErrorCode, D as Cleanup, E as UnsafeMigration, F as DataStep, H as UniqueFailed, I as TODO, L as dataStep, M as migrate, N as migrateFresh, O as cleanupMigration, P as sync, R as CheckFailed, S as MigrationError, T as UnsafeChange, U as dialectFor, V as ReferenceFailed, W as sqlite, _ as Generated, b as manifest, c as acquireLock, d as setReleaseStatus, f as startRelease, g as makeMigrations, h as makeCleanup, j as Migration, k as Manifest, l as releaseLock, m as checkMigrations, n as row, o as Release, p as applyRules, s as ReleaseStatus, t as createDataLayer, u as rollback, v as generateMigration, w as SuspectedRename, x as structureStep, y as cleanupStep, z as DatabaseError } from "../data-layer-43pme0Gy.js";
|
|
4
4
|
export { type AnyModel, CheckFailed, type Cleanup, type Clock, Column, Condition, type ConditionNode, type DataStep, Database, DatabaseError, type DatabaseOptions, type Dialect, Expr, Field, type FieldSpec, type FixedClock, type Generated, type Insert, type Kinds, type Make, type Manifest, type Many, type MigrateOptions, type Migration, MigrationError, type MigrationErrorCode, Model, type ModelSpec, type Models, NotFound, Now, type OrderKey, type Overrides, type Patch, type Planned, Query, type RawValue, ReferenceFailed, Relation, type Release, type ReleaseStatus, type RetiredSnapshot, type Row, type Rule, type SchemaDefaults, type SchemaSnapshot, Seed, type SeedContext, Slot, type Storage, type SuspectedRename, TODO, Total, Transaction, UniqueFailed, type UnsafeChange, UnsafeMigration, ValidationError, type Visible, type Write, type WriteListener, acquireLock, all, any, applyRules, checkMigrations, cleanupMigration, cleanupStep, count, createDataLayer, dataStep, database, dialectFor, emptySnapshot, fieldKinds, fixedClock, generateMigration, makeCleanup, makeMigrations, manifest, migrate, migrateFresh, newSecretKey, not, now, releaseLock, rollback, row, sensitivity, setReleaseStatus, slot, snapshotOf, sqlite, startRelease, structureStep, sync, systemClock };
|
package/dist/db/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { G as ValidationError } from "../validation-Cppmd0RV.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { i as slot, n as row, r as Slot, t as createDataLayer } from "../data-layer-
|
|
2
|
+
import { C as database, F as dialectFor, G as newSecretKey, H as fixedClock, I as sqlite, J as NotFound, K as CheckFailed, M as Query, U as systemClock, X as UniqueFailed, Y as ReferenceFailed, _ as TODO, b as Database, c as rollback, d as applyRules, g as UnsafeMigration, h as snapshotOf, i as acquireLock, l as setReleaseStatus, m as emptySnapshot, n as migrateFresh, p as generateMigration, q as DatabaseError, r as sync, s as releaseLock, t as migrate, u as startRelease, v as dataStep, x as Transaction, y as MigrationError } from "../migrator-B25prc9n.js";
|
|
3
|
+
import { D as now, E as not, S as any, T as count, _ as Expr, b as Total, d as fieldKinds, f as Field, h as Condition, m as Column, p as sensitivity, t as Model, v as Now, x as all, y as Relation } from "../model-Dc3HunKb.js";
|
|
4
|
+
import { i as slot, n as row, r as Slot, t as createDataLayer } from "../data-layer-C5oJZ8V1.js";
|
|
5
5
|
import { t as Seed } from "../seed-BObmdKdP.js";
|
|
6
|
-
import { a as cleanupMigration, i as makeMigrations, r as makeCleanup, t as checkMigrations } from "../make-
|
|
6
|
+
import { a as cleanupMigration, i as makeMigrations, r as makeCleanup, t as checkMigrations } from "../make-ByA-84h8.js";
|
|
7
7
|
//#region src/db/migrations/files.ts
|
|
8
8
|
/** A structure step file: adds tables and columns. Applied once, never edited. */
|
|
9
9
|
function structureStep(options) {
|
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import { a as DatabaseDriver, b as TenantDatabases, d as RateLimiter, g as Storage, l as PdfRenderer, n as Body, p as Runtime, r as Cache, s as MailDriver, u as Queue } from "./index-Ce5p2-EB.js";
|
|
2
2
|
import { C as ObjectShape, Y as StoredFile, w as Output } from "./index-CYcklQ1l.js";
|
|
3
|
-
import { $ as Expr, C as WithIncludes, D as PageOptions, E as Page, J as Models, Q as Embed, S as Key, T as NumberedPageOptions, V as AnyModel, X as Condition, Z as Conditional, b as RowOf, ct as ColumnNode, gt as FieldSpec, i as Row, lt as ConditionNode, n as Patch, p as Database, t as Insert, ut as Operand, v as OrderKey, w as NumberedPage, x as IncludePath } from "./types-
|
|
4
|
-
import { a as PROVIDERS, i as HELD, k as Manifest } from "./data-layer-
|
|
3
|
+
import { $ as Expr, C as WithIncludes, D as PageOptions, E as Page, J as Models, Q as Embed, S as Key, T as NumberedPageOptions, V as AnyModel, X as Condition, Z as Conditional, b as RowOf, ct as ColumnNode, gt as FieldSpec, i as Row, lt as ConditionNode, n as Patch, p as Database, t as Insert, u as Seed, ut as Operand, v as OrderKey, w as NumberedPage, x as IncludePath } from "./types-BgOkJy5d.js";
|
|
4
|
+
import { a as PROVIDERS, i as HELD, k as Manifest } from "./data-layer-43pme0Gy.js";
|
|
5
|
+
//#region src/api/fail.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* `fail(code, message)`: the app's own business rules, for what can't be a `.check()`, a flow or a
|
|
8
|
+
* unique. Always a 409; app code never picks a status.
|
|
9
|
+
*/
|
|
10
|
+
declare class Rejected extends Error {
|
|
11
|
+
/** Stable and machine-readable (`alreadyCheckedIn`). */
|
|
12
|
+
readonly code: string;
|
|
13
|
+
readonly name = "Rejected";
|
|
14
|
+
constructor(
|
|
15
|
+
/** Stable and machine-readable (`alreadyCheckedIn`). */
|
|
16
|
+
code: string, message: string);
|
|
17
|
+
}
|
|
18
|
+
declare function fail(code: string, message: string): never;
|
|
19
|
+
//#endregion
|
|
5
20
|
//#region src/auth/policies.d.ts
|
|
6
21
|
/** The actions every model's policy has. */
|
|
7
22
|
declare const STANDARD_ACTIONS: readonly ["read", "create", "update", "delete"];
|
|
@@ -16,6 +31,15 @@ interface BuiltinUser {
|
|
|
16
31
|
readonly emailVerifiedAt: Date | null;
|
|
17
32
|
readonly suspendedAt: Date | null;
|
|
18
33
|
}
|
|
34
|
+
type UserRow = Models extends {
|
|
35
|
+
readonly User: infer U extends AnyModel;
|
|
36
|
+
} ? Row<U> : BuiltinUser;
|
|
37
|
+
type TenantRow$1 = Models extends {
|
|
38
|
+
readonly Tenant: infer T extends AnyModel;
|
|
39
|
+
} ? Row<T> : {
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
};
|
|
19
43
|
type Rules = Readonly<Record<string, Conditional>>;
|
|
20
44
|
/** Each action's permission key, and `all` of them. */
|
|
21
45
|
type Perms<Action extends string> = { readonly [K in Action]: string; } & {
|
|
@@ -55,21 +79,6 @@ interface DefinePolicy {
|
|
|
55
79
|
<const N extends string, const R extends Rules>(name: N, rules: R): Policy<keyof R & string>;
|
|
56
80
|
}
|
|
57
81
|
//#endregion
|
|
58
|
-
//#region src/api/fail.d.ts
|
|
59
|
-
/**
|
|
60
|
-
* `fail(code, message)`: the app's own business rules, for what can't be a `.check()`, a flow or a
|
|
61
|
-
* unique. Always a 409; app code never picks a status.
|
|
62
|
-
*/
|
|
63
|
-
declare class Rejected extends Error {
|
|
64
|
-
/** Stable and machine-readable (`alreadyCheckedIn`). */
|
|
65
|
-
readonly code: string;
|
|
66
|
-
readonly name = "Rejected";
|
|
67
|
-
constructor(
|
|
68
|
-
/** Stable and machine-readable (`alreadyCheckedIn`). */
|
|
69
|
-
code: string, message: string);
|
|
70
|
-
}
|
|
71
|
-
declare function fail(code: string, message: string): never;
|
|
72
|
-
//#endregion
|
|
73
82
|
//#region src/auth/roles.d.ts
|
|
74
83
|
/** What a user's roles give them: every permission (`{ all: true }`), or these keys. */
|
|
75
84
|
interface Permissions {
|
|
@@ -519,6 +528,12 @@ interface TenantHandle {
|
|
|
519
528
|
* are copied (structured clones), so they're plain values.
|
|
520
529
|
*/
|
|
521
530
|
run<S extends Service>(service: S, ...args: Parameters<S>): Promise<Awaited<ReturnType<S>>>;
|
|
531
|
+
/**
|
|
532
|
+
* Runs a seed from `db/seeds.ts` in the tenant, as `inTenant` does from the platform's seed: it
|
|
533
|
+
* fills only an empty database, so on one with rows it does nothing. On a deployed app too (a
|
|
534
|
+
* tenant filled with demo data).
|
|
535
|
+
*/
|
|
536
|
+
run(seed: Seed): Promise<void>;
|
|
522
537
|
}
|
|
523
538
|
/** The app's seeds (`db/seeds.ts`), as a lazy import: `() => import("#db/seeds")`. */
|
|
524
539
|
type AppSeeds = () => Promise<object>;
|
|
@@ -538,6 +553,11 @@ interface InviteInput {
|
|
|
538
553
|
/** `"platform"`: the tenant's people can't take the role away. */
|
|
539
554
|
readonly held?: (typeof HELD)[number];
|
|
540
555
|
}
|
|
556
|
+
/** What `auth.revoke` takes: an email, and the key of a role from `app.ts`. */
|
|
557
|
+
interface RevokeInput {
|
|
558
|
+
readonly email: string;
|
|
559
|
+
readonly role: string;
|
|
560
|
+
}
|
|
541
561
|
//#endregion
|
|
542
562
|
//#region src/auth/create-auth.d.ts
|
|
543
563
|
type Provider = (typeof PROVIDERS)[number];
|
|
@@ -585,6 +605,11 @@ interface AuthConfig {
|
|
|
585
605
|
/** Every permission key: every policy's actions, and `auth.perms`. */
|
|
586
606
|
permissionKeys(): readonly string[];
|
|
587
607
|
}
|
|
608
|
+
/** `auth.invite` and `auth.revoke`, on the app's current database: the core's to attach. */
|
|
609
|
+
interface AuthPeople {
|
|
610
|
+
invite(input: InviteInput): Promise<void>;
|
|
611
|
+
revoke(input: RevokeInput): Promise<void>;
|
|
612
|
+
}
|
|
588
613
|
declare class Auth<Env = unknown> {
|
|
589
614
|
private readonly define;
|
|
590
615
|
readonly perms: {
|
|
@@ -597,8 +622,8 @@ declare class Auth<Env = unknown> {
|
|
|
597
622
|
};
|
|
598
623
|
/** The policies made with this instance's `policy()`. */
|
|
599
624
|
readonly policies: PolicyRegistry;
|
|
600
|
-
/** Set by the app's core when it starts: `invite` on its current database. */
|
|
601
|
-
private
|
|
625
|
+
/** Set by the app's core when it starts: `invite` and `revoke` on its current database. */
|
|
626
|
+
private people;
|
|
602
627
|
constructor(define: (env: Env) => AuthDefinition);
|
|
603
628
|
/**
|
|
604
629
|
* Gives `email` a role from `app.ts`, from code (a tenant's setup service, a seed): now, if it has
|
|
@@ -606,8 +631,13 @@ declare class Auth<Env = unknown> {
|
|
|
606
631
|
* `held: "platform"` puts the assignment beyond the tenant's reach.
|
|
607
632
|
*/
|
|
608
633
|
invite(input: InviteInput): Promise<void>;
|
|
609
|
-
/**
|
|
610
|
-
|
|
634
|
+
/**
|
|
635
|
+
* Takes a role from `email`, from code (replacing a tenant's owner): its invite to the role is
|
|
636
|
+
* deleted, and the role taken away if it has an account in the current database. Safe to repeat.
|
|
637
|
+
*/
|
|
638
|
+
revoke(input: RevokeInput): Promise<void>;
|
|
639
|
+
/** The core's: where `invite` and `revoke` write. */
|
|
640
|
+
attach(people: AuthPeople): void;
|
|
611
641
|
/** The config, for this env. Checked here for itself; against the databases by the core. */
|
|
612
642
|
resolve(env: Env): AuthConfig;
|
|
613
643
|
}
|
|
@@ -616,18 +646,21 @@ type RoleDefinition = {
|
|
|
616
646
|
readonly all: true;
|
|
617
647
|
} | readonly string[];
|
|
618
648
|
type Roles = Readonly<Record<string, RoleDefinition>>;
|
|
649
|
+
/**
|
|
650
|
+
* What `createAuth` gives. Written out so `user` and `tenant` stay typed by the app's `Models`
|
|
651
|
+
* (its `User` and `Tenant` columns): an inferred type would be fixed to the built-in rows when
|
|
652
|
+
* isai's declarations are built.
|
|
653
|
+
*/
|
|
654
|
+
interface CreatedAuth<Env> {
|
|
655
|
+
readonly auth: Auth<Env>;
|
|
656
|
+
readonly policy: DefinePolicy;
|
|
657
|
+
readonly user: Bound<UserRow>;
|
|
658
|
+
readonly tenant: Bound<TenantRow$1>;
|
|
659
|
+
readonly owner: Condition;
|
|
660
|
+
readonly byRole: Condition;
|
|
661
|
+
readonly anyone: Condition;
|
|
662
|
+
}
|
|
619
663
|
/** The auth instance, from `auth.ts`, with `policy()` and the placeholders policies are written with. */
|
|
620
|
-
declare function createAuth<Env = unknown>(define: (env: Env) => AuthDefinition):
|
|
621
|
-
auth: Auth<Env>;
|
|
622
|
-
policy: DefinePolicy;
|
|
623
|
-
user: Bound<BuiltinUser>;
|
|
624
|
-
tenant: Bound<{
|
|
625
|
-
readonly id: string;
|
|
626
|
-
readonly name: string;
|
|
627
|
-
}>;
|
|
628
|
-
owner: Condition;
|
|
629
|
-
byRole: Condition;
|
|
630
|
-
anyone: Condition;
|
|
631
|
-
};
|
|
664
|
+
declare function createAuth<Env = unknown>(define: (env: Env) => AuthDefinition): CreatedAuth<Env>;
|
|
632
665
|
//#endregion
|
|
633
|
-
export { Permissions as A, Params as C, RouteHandler as D, RouteContext as E,
|
|
666
|
+
export { Permissions as A, Params as C, RouteHandler as D, RouteContext as E, Policy as F, Rules as I, StandardAction as L, Bound as M, DefinePolicy as N, RouteOptions as O, Perms as P, Rejected as R, Method as S, RouteBuilder as T, CustomAction as _, OAuthMethod as a, AppConfig as b, Roles as c, NotImplementedError as d, AppModules as f, createApp as g, CreatedApp as h, Methods as i, AnyPolicy as j, User as k, SignInMethod as l, AppOptions as m, AuthConfig as n, Provider as o, App as p, AuthDefinition as r, RoleDefinition as s, Auth as t, createAuth as u, Resource as v, Route as w, Named as x, ResourceOptions as y, fail as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { p as Runtime, t as AppCore } from "./index-Ce5p2-EB.js";
|
|
2
|
-
import { C as Params, D as RouteHandler, E as RouteContext,
|
|
2
|
+
import { C as Params, D as RouteHandler, E as RouteContext, O as RouteOptions, R as Rejected, S as Method, T as RouteBuilder, _ as CustomAction, b as AppConfig, d as NotImplementedError, f as AppModules, g as createApp, h as CreatedApp, k as User, m as AppOptions, p as App, v as Resource, w as Route, x as Named, y as ResourceOptions, z as fail } from "./index-a7ElyL3B.js";
|
|
3
3
|
export { type App, type AppConfig, type AppCore, type AppModules, type AppOptions, type CreatedApp, type CustomAction, type Method, type Named, NotImplementedError, type Params, Rejected, type Resource, type ResourceOptions, Route, type RouteBuilder, type RouteContext, type RouteHandler, type RouteOptions, type Runtime, type User, createApp, fail };
|