trellis 3.2.0 → 3.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +61 -171
- package/dist/browser/index.d.ts +18 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +95 -0
- package/dist/{chunk-3ETIIPPB.js → chunk-2AACZRII.js} +312 -30
- package/dist/{chunk-3GDRZTAW.js → chunk-5KSGGKET.js} +1 -1
- package/dist/{chunk-MBNBTJCR.js → chunk-6GEZ6DN5.js} +2 -2
- package/dist/chunk-6RWGFC3N.js +403 -0
- package/dist/{chunk-X762XWVC.js → chunk-7DUMWO5L.js} +1 -1
- package/dist/chunk-CAG4FULI.js +121 -0
- package/dist/{chunk-GD5QJXSS.js → chunk-FWRS4CSC.js} +2 -2
- package/dist/{chunk-36VSSTL7.js → chunk-GU374KWZ.js} +1 -1
- package/dist/{chunk-BJ7EZ7FP.js → chunk-JHHEXEDM.js} +17 -0
- package/dist/{chunk-7WQGTFVJ.js → chunk-L5N5PR2S.js} +130 -75
- package/dist/{chunk-BXSTJVE3.js → chunk-N6MYZT4O.js} +2 -1
- package/dist/chunk-NWSW5YNS.js +225 -0
- package/dist/{chunk-HO4TURXW.js → chunk-S3XLFZ27.js} +28 -11
- package/dist/{chunk-BQBUVMRN.js → chunk-S6GBJ2ZB.js} +25 -14
- package/dist/{chunk-B3ZIFA2O.js → chunk-VBYUTRXX.js} +1 -1
- package/dist/cli/deploy-cli.d.ts +18 -0
- package/dist/cli/deploy-cli.d.ts.map +1 -0
- package/dist/cli/deploy-cli.js +67 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +153 -100
- package/dist/client/index.browser.d.ts +29 -0
- package/dist/client/index.browser.d.ts.map +1 -0
- package/dist/client/index.browser.js +64 -0
- package/dist/client/index.js +10 -10
- package/dist/client/sdk.browser.d.ts +131 -0
- package/dist/client/sdk.browser.d.ts.map +1 -0
- package/dist/{sdk-LZ7W3EEY.js → client/sdk.browser.js} +2 -2
- package/dist/client/sdk.js +1 -1
- package/dist/db/index.js +16 -16
- package/dist/db/inspector.js +6 -6
- package/dist/decisions/index.js +2 -2
- package/dist/embeddings/auto-embed.d.ts.map +1 -1
- package/dist/embeddings/index.js +1 -1
- package/dist/embeddings/store.d.ts.map +1 -1
- package/dist/engine.d.ts +27 -7
- package/dist/engine.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/react/index.js +2 -2
- package/dist/react/schema-hooks.js +7 -7
- package/dist/{remote-manager-SG545WNY.js → remote-manager-ODE3T2KR.js} +5 -5
- package/dist/scaffold/seed.d.ts.map +1 -1
- package/dist/scaffold/write.d.ts +1 -1
- package/dist/scaffold/write.d.ts.map +1 -1
- package/dist/schema/index.js +4 -3
- package/dist/server/cors.d.ts +13 -0
- package/dist/server/cors.d.ts.map +1 -0
- package/dist/server/deploy-meta.d.ts +25 -0
- package/dist/server/deploy-meta.d.ts.map +1 -0
- package/dist/server/deploy.d.ts +8 -3
- package/dist/server/deploy.d.ts.map +1 -1
- package/dist/server/deploy.js +9 -0
- package/dist/server/index.d.ts +5 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +51 -17
- package/dist/server/realtime.d.ts +4 -1
- package/dist/server/realtime.d.ts.map +1 -1
- package/dist/server/server.d.ts +1 -0
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/sprites.d.ts +18 -1
- package/dist/server/sprites.d.ts.map +1 -1
- package/dist/server/tenancy.d.ts +4 -0
- package/dist/server/tenancy.d.ts.map +1 -1
- package/dist/server/usage-meter.d.ts +53 -0
- package/dist/server/usage-meter.d.ts.map +1 -0
- package/dist/{server-IGBIIJSF.js → server-OGVWNDNK.js} +6 -1
- package/dist/sprites-KQGTGM6W.js +27 -0
- package/dist/{tenancy-OP34NFFS.js → tenancy-POMWQP6M.js} +5 -3
- package/dist/vcs/index.js +3 -3
- package/dist/vcs/types.d.ts +2 -0
- package/dist/vcs/types.d.ts.map +1 -1
- package/package.json +17 -6
- package/dist/better-sqlite-backend-PII64VE6.js +0 -159
- package/dist/better-sqlite-backend-VUBVQ7SN.js +0 -209
- package/dist/better-sqlite-backend-Y3AQN65E.js +0 -159
- package/dist/better-sqlite-backend-Y3M7DXOX.js +0 -159
- package/dist/boot-middleware-FJDGVUM4.js +0 -9
- package/dist/boot-middleware-MLJUTLUM.js +0 -9
- package/dist/boot-middleware-ZZPDZNYR.js +0 -9
- package/dist/chunk-276LKLZR.js +0 -359
- package/dist/chunk-2CX5UCRV.js +0 -111
- package/dist/chunk-2ESYSVXG.js +0 -48
- package/dist/chunk-2I5JU73Y.js +0 -340
- package/dist/chunk-2UNSRRNB.js +0 -171
- package/dist/chunk-335UEHQR.js +0 -907
- package/dist/chunk-4CF2L46N.js +0 -29
- package/dist/chunk-5CINODKT.js +0 -41
- package/dist/chunk-5ESGWJ5L.js +0 -45
- package/dist/chunk-5FGLQGMF.js +0 -1676
- package/dist/chunk-5IQZFITY.js +0 -357
- package/dist/chunk-5JWFAQDW.js +0 -150
- package/dist/chunk-62UHTVU3.js +0 -141
- package/dist/chunk-66UJQT2I.js +0 -35
- package/dist/chunk-6RNNVOAS.js +0 -355
- package/dist/chunk-6X23PZ6H.js +0 -969
- package/dist/chunk-7C7LL6MB.js +0 -315
- package/dist/chunk-7F4HM3JG.js +0 -394
- package/dist/chunk-7KJ7T4D3.js +0 -910
- package/dist/chunk-7QQQNUB5.js +0 -92
- package/dist/chunk-7QWJBS72.js +0 -946
- package/dist/chunk-7R36OZK3.js +0 -957
- package/dist/chunk-7UPKCOHE.js +0 -946
- package/dist/chunk-A3BONW34.js +0 -35
- package/dist/chunk-AHMDVHBL.js +0 -141
- package/dist/chunk-AW6A4OZY.js +0 -171
- package/dist/chunk-BJ5EKCJ5.js +0 -458
- package/dist/chunk-BRGYDO7D.js +0 -223
- package/dist/chunk-C5KPSEDN.js +0 -359
- package/dist/chunk-CCTNYTUC.js +0 -940
- package/dist/chunk-CYQ2OVD2.js +0 -35
- package/dist/chunk-DDAK7YOE.js +0 -299
- package/dist/chunk-DRILKBY6.js +0 -965
- package/dist/chunk-DXE24HNN.js +0 -45
- package/dist/chunk-E7ICUNW7.js +0 -945
- package/dist/chunk-EAL2PUOE.js +0 -10022
- package/dist/chunk-ELT7MLZB.js +0 -109
- package/dist/chunk-EWEIRF6G.js +0 -171
- package/dist/chunk-F5VDGQJC.js +0 -120
- package/dist/chunk-FCPL3IEQ.js +0 -98
- package/dist/chunk-FDPKYSV7.js +0 -96
- package/dist/chunk-FES3TC24.js +0 -171
- package/dist/chunk-FF36CQHZ.js +0 -61
- package/dist/chunk-FOWKR5TW.js +0 -129
- package/dist/chunk-FZVCXDYW.js +0 -150
- package/dist/chunk-G3XIHPSQ.js +0 -361
- package/dist/chunk-GKJLYLVU.js +0 -359
- package/dist/chunk-GNXHXNVQ.js +0 -113
- package/dist/chunk-GSR6ILTM.js +0 -277
- package/dist/chunk-GWRIMRSX.js +0 -45
- package/dist/chunk-H72UW2HJ.js +0 -45
- package/dist/chunk-HGI74PXB.js +0 -7417
- package/dist/chunk-HGRA37LO.js +0 -145
- package/dist/chunk-HXSRQO3L.js +0 -145
- package/dist/chunk-IG2X2BVO.js +0 -373
- package/dist/chunk-IIJVDD54.js +0 -373
- package/dist/chunk-IUWVEEOX.js +0 -145
- package/dist/chunk-IX4BBOIT.js +0 -394
- package/dist/chunk-IXU4RMQM.js +0 -349
- package/dist/chunk-J6OUIION.js +0 -857
- package/dist/chunk-K46RNFDE.js +0 -171
- package/dist/chunk-KAGU2XMY.js +0 -359
- package/dist/chunk-KCVYJNVX.js +0 -394
- package/dist/chunk-KKDRMIV6.js +0 -419
- package/dist/chunk-KYLIQ3YI.js +0 -399
- package/dist/chunk-KZYJJIRN.js +0 -946
- package/dist/chunk-LFOX744K.js +0 -96
- package/dist/chunk-LHOVJEWR.js +0 -7403
- package/dist/chunk-LOPXTPF3.js +0 -120
- package/dist/chunk-LZR3VIFU.js +0 -907
- package/dist/chunk-MCKGQKYU.js +0 -15
- package/dist/chunk-MU6EOS6F.js +0 -0
- package/dist/chunk-MWRQ2TXT.js +0 -357
- package/dist/chunk-NO73OK2I.js +0 -102
- package/dist/chunk-NPE2YJHK.js +0 -394
- package/dist/chunk-NSDXU6QX.js +0 -2213
- package/dist/chunk-NXIRDSZ6.js +0 -145
- package/dist/chunk-NZWFNHCS.js +0 -407
- package/dist/chunk-OB4CMMX6.js +0 -260
- package/dist/chunk-OBKU74FU.js +0 -7411
- package/dist/chunk-OQNDWRDE.js +0 -145
- package/dist/chunk-OVWAJMB6.js +0 -394
- package/dist/chunk-PDHLBTTD.js +0 -45
- package/dist/chunk-PEQNRKLG.js +0 -210
- package/dist/chunk-QERIS7QY.js +0 -7403
- package/dist/chunk-QHA2DM3C.js +0 -373
- package/dist/chunk-QLM4HSYC.js +0 -45
- package/dist/chunk-S2OT3TQJ.js +0 -283
- package/dist/chunk-S5PHSN5K.js +0 -907
- package/dist/chunk-SIAA4J6H.js +0 -21
- package/dist/chunk-SQBNLUIA.js +0 -171
- package/dist/chunk-STLN6A6B.js +0 -355
- package/dist/chunk-U7HV7GU2.js +0 -17
- package/dist/chunk-UGZHOGRA.js +0 -39
- package/dist/chunk-UICF66FS.js +0 -359
- package/dist/chunk-UK3EQREE.js +0 -1078
- package/dist/chunk-UPKPURVY.js +0 -394
- package/dist/chunk-URC74VCN.js +0 -959
- package/dist/chunk-V3G7Q3QQ.js +0 -102
- package/dist/chunk-VUJ6SA55.js +0 -303
- package/dist/chunk-VUJQLIML.js +0 -141
- package/dist/chunk-VWKLKLYB.js +0 -267
- package/dist/chunk-VYC3RZMK.js +0 -277
- package/dist/chunk-WMERMSWI.js +0 -154
- package/dist/chunk-WMR777PO.js +0 -2213
- package/dist/chunk-X46IECAC.js +0 -517
- package/dist/chunk-XEN3OEYY.js +0 -2234
- package/dist/chunk-XZQ66K7A.js +0 -124
- package/dist/chunk-YY3GF7DH.js +0 -7411
- package/dist/chunk-ZE5R3H4C.js +0 -907
- package/dist/chunk-ZHVI7BQN.js +0 -1077
- package/dist/chunk-ZMN5LUB7.js +0 -7411
- package/dist/chunk-ZUV4MD5U.js +0 -94
- package/dist/config-KMY6RRK3.js +0 -19
- package/dist/config-VDMK2DUJ.js +0 -19
- package/dist/db/trellis.css +0 -1
- package/dist/deploy-66EC752W.js +0 -9
- package/dist/deploy-SO7AFK6L.js +0 -9
- package/dist/engine-7GXBM4IT.js +0 -7
- package/dist/engine-NSR6BIF7.js +0 -7
- package/dist/factory-2P64OC7M.js +0 -34
- package/dist/factory-YP4ZZK5K.js +0 -34
- package/dist/import-AJLYHFIA.js +0 -10
- package/dist/launch-explorer-AI6L2AWJ.js +0 -91
- package/dist/query-GJL3CVGN.js +0 -31
- package/dist/query-MBJSK3EB.js +0 -31
- package/dist/query-TJHEVSKL.js +0 -31
- package/dist/query-WUIKOHPE.js +0 -524
- package/dist/remote-manager-BLJZ6KF6.js +0 -224
- package/dist/remote-manager-BPYE46SI.js +0 -223
- package/dist/remote-manager-FMESEAFA.js +0 -224
- package/dist/remote-manager-K2WZ5RHY.js +0 -223
- package/dist/remote-manager-SG5PQKCH.js +0 -224
- package/dist/remote-manager-WGP6MIQZ.js +0 -224
- package/dist/sdk-3KBB3E6V.js +0 -16
- package/dist/sdk-4ZQO6UTU.js +0 -16
- package/dist/sdk-6JA6GV3G.js +0 -16
- package/dist/sdk-6VTP5UTZ.js +0 -16
- package/dist/sdk-7VS6TYCD.js +0 -16
- package/dist/sdk-HQ3FTLRT.js +0 -16
- package/dist/sdk-HZ7NU3XE.js +0 -15
- package/dist/sdk-KBQE2OXT.js +0 -16
- package/dist/sdk-MSCDZ7JU.js +0 -15
- package/dist/sdk-WNZOGO3S.js +0 -15
- package/dist/sdk-YLV33ZCW.js +0 -9
- package/dist/sdk-ZSUD2LLJ.js +0 -16
- package/dist/server-AFXFFBWA.js +0 -11
- package/dist/server-AGHC4VUL.js +0 -11
- package/dist/server-BOH7M4TT.js +0 -13
- package/dist/server-DBUY2KY5.js +0 -11
- package/dist/server-GWBQJPRG.js +0 -11
- package/dist/server-JZZFULVU.js +0 -11
- package/dist/server-L5XAF4M5.js +0 -11
- package/dist/server-NYFUHANA.js +0 -12
- package/dist/server-OABUB2LO.js +0 -12
- package/dist/server-P2CKZWWV.js +0 -12
- package/dist/sprites-RU3E4XQN.js +0 -15
- package/dist/sprites-XVSMQLSI.js +0 -15
- package/dist/sql-wasm-FORCZFHZ.js +0 -2148
- package/dist/sql-wasm-JZH76RLO.js +0 -2148
- package/dist/sqljs-backend-CJQOIQYE.js +0 -266
- package/dist/sqljs-backend-KWXBUDUO.js +0 -266
- package/dist/state-demo.bundle.js +0 -1033
- package/dist/tenancy-CBWYEVUB.js +0 -11
- package/dist/tenancy-FO6WVYFN.js +0 -13
- package/dist/tenancy-FWDBESMX.js +0 -14
- package/dist/tenancy-HGPIS5QA.js +0 -13
- package/dist/tenancy-HXFALA37.js +0 -14
- package/dist/tenancy-S676GLID.js +0 -14
- package/dist/tenancy-V7ARWNNV.js +0 -14
- package/dist/tenancy-ZDN4GXK5.js +0 -13
- package/dist/tenancy-ZT5VMY7B.js +0 -14
- package/dist/vm-config-YZRJ3KUB.js +0 -21
- /package/dist/{chunk-2BRTCEHB.js → chunk-PZ4XYZ4J.js} +0 -0
- /package/dist/{chunk-EO3J7GRP.js → chunk-WXSWA3MV.js} +0 -0
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_TENANT
|
|
3
|
+
} from "./chunk-JHHEXEDM.js";
|
|
1
4
|
import {
|
|
2
5
|
rel
|
|
3
6
|
} from "./chunk-44FFQKQX.js";
|
|
@@ -11,8 +14,8 @@ import {
|
|
|
11
14
|
} from "./chunk-X5FLTRUB.js";
|
|
12
15
|
|
|
13
16
|
// src/server/server.ts
|
|
14
|
-
import { existsSync, readFileSync } from "fs";
|
|
15
|
-
import { dirname, join } from "path";
|
|
17
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
18
|
+
import { dirname, join as join2 } from "path";
|
|
16
19
|
import { fileURLToPath } from "url";
|
|
17
20
|
|
|
18
21
|
// src/server/auth.ts
|
|
@@ -367,14 +370,124 @@ async function hydrateAndResolve(kernel, bindings, entityType, resolve) {
|
|
|
367
370
|
});
|
|
368
371
|
}
|
|
369
372
|
|
|
373
|
+
// src/server/usage-meter.ts
|
|
374
|
+
import { existsSync, readdirSync, statSync } from "fs";
|
|
375
|
+
import { join } from "path";
|
|
376
|
+
var EMPTY_BUCKET = () => ({
|
|
377
|
+
graph_io: 0,
|
|
378
|
+
storage_bytes: 0,
|
|
379
|
+
egress_bytes: 0
|
|
380
|
+
});
|
|
381
|
+
function resolveUsageTenantId(tenantId) {
|
|
382
|
+
return tenantId ?? DEFAULT_TENANT;
|
|
383
|
+
}
|
|
384
|
+
function dayKey(date) {
|
|
385
|
+
return date.toISOString().slice(0, 10);
|
|
386
|
+
}
|
|
387
|
+
function dirSize(dir) {
|
|
388
|
+
let total = 0;
|
|
389
|
+
for (const ent of readdirSync(dir, { withFileTypes: true })) {
|
|
390
|
+
const p = join(dir, ent.name);
|
|
391
|
+
if (ent.isDirectory()) total += dirSize(p);
|
|
392
|
+
else if (ent.isFile()) total += statSync(p).size;
|
|
393
|
+
}
|
|
394
|
+
return total;
|
|
395
|
+
}
|
|
396
|
+
function sampleTenantStorage(pool, tenantId) {
|
|
397
|
+
let total = 0;
|
|
398
|
+
const sqlitePath = pool.dbFilePath(tenantId);
|
|
399
|
+
if (existsSync(sqlitePath)) {
|
|
400
|
+
total += statSync(sqlitePath).size;
|
|
401
|
+
}
|
|
402
|
+
const blobDir = join(pool.dataPath(), "blobs");
|
|
403
|
+
if (existsSync(blobDir)) {
|
|
404
|
+
total += dirSize(blobDir);
|
|
405
|
+
}
|
|
406
|
+
return total;
|
|
407
|
+
}
|
|
408
|
+
function verifyAdminKey(req) {
|
|
409
|
+
const expected = process.env.TURTLEDB_ADMIN_KEY;
|
|
410
|
+
if (!expected) return false;
|
|
411
|
+
const auth = req.headers.get("authorization");
|
|
412
|
+
if (auth?.startsWith("Bearer ")) {
|
|
413
|
+
return auth.slice("Bearer ".length) === expected;
|
|
414
|
+
}
|
|
415
|
+
return req.headers.get("x-turtledb-admin-key") === expected;
|
|
416
|
+
}
|
|
417
|
+
var UsageMeter = class {
|
|
418
|
+
buckets = /* @__PURE__ */ new Map();
|
|
419
|
+
storageSampledAt = /* @__PURE__ */ new Map();
|
|
420
|
+
now;
|
|
421
|
+
constructor(opts = {}) {
|
|
422
|
+
this.now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
423
|
+
}
|
|
424
|
+
recordGraphIo(tenantId, count = 1) {
|
|
425
|
+
if (count <= 0) return;
|
|
426
|
+
const bucket = this._bucket(tenantId);
|
|
427
|
+
bucket.graph_io += count;
|
|
428
|
+
}
|
|
429
|
+
recordEgress(tenantId, bytes) {
|
|
430
|
+
if (bytes <= 0) return;
|
|
431
|
+
const bucket = this._bucket(tenantId);
|
|
432
|
+
bucket.egress_bytes += bytes;
|
|
433
|
+
}
|
|
434
|
+
/** Set storage gauge for the current day (from sampler, not incremental). */
|
|
435
|
+
recordStorage(tenantId, bytes) {
|
|
436
|
+
const bucket = this._bucket(tenantId);
|
|
437
|
+
bucket.storage_bytes = bytes;
|
|
438
|
+
this.storageSampledAt.set(`${tenantId}:${this._today()}`, this.now().toISOString());
|
|
439
|
+
}
|
|
440
|
+
sampleStorage(pool, tenantId) {
|
|
441
|
+
const id = resolveUsageTenantId(tenantId);
|
|
442
|
+
const bytes = sampleTenantStorage(pool, id);
|
|
443
|
+
this.recordStorage(id, bytes);
|
|
444
|
+
return bytes;
|
|
445
|
+
}
|
|
446
|
+
getUsage(tenantId, day) {
|
|
447
|
+
const d = day ?? this._today();
|
|
448
|
+
const tenantBuckets = this.buckets.get(tenantId);
|
|
449
|
+
const meters = tenantBuckets?.get(d) ?? EMPTY_BUCKET();
|
|
450
|
+
const sampledAt = this.storageSampledAt.get(`${tenantId}:${d}`);
|
|
451
|
+
return {
|
|
452
|
+
tenantId,
|
|
453
|
+
day: d,
|
|
454
|
+
meters: { ...meters },
|
|
455
|
+
...sampledAt ? { storageSampledAt: sampledAt } : {}
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
/** All day keys recorded for a tenant (sorted ascending). */
|
|
459
|
+
listDays(tenantId) {
|
|
460
|
+
const tenantBuckets = this.buckets.get(tenantId);
|
|
461
|
+
if (!tenantBuckets) return [];
|
|
462
|
+
return Array.from(tenantBuckets.keys()).sort();
|
|
463
|
+
}
|
|
464
|
+
_today() {
|
|
465
|
+
return dayKey(this.now());
|
|
466
|
+
}
|
|
467
|
+
_bucket(tenantId) {
|
|
468
|
+
const id = resolveUsageTenantId(tenantId);
|
|
469
|
+
const d = this._today();
|
|
470
|
+
if (!this.buckets.has(id)) {
|
|
471
|
+
this.buckets.set(id, /* @__PURE__ */ new Map());
|
|
472
|
+
}
|
|
473
|
+
const tenantBuckets = this.buckets.get(id);
|
|
474
|
+
if (!tenantBuckets.has(d)) {
|
|
475
|
+
tenantBuckets.set(d, EMPTY_BUCKET());
|
|
476
|
+
}
|
|
477
|
+
return tenantBuckets.get(d);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
|
|
370
481
|
// src/server/realtime.ts
|
|
371
482
|
var SubscriptionManager = class {
|
|
372
483
|
clients = /* @__PURE__ */ new Map();
|
|
373
484
|
pool;
|
|
374
485
|
permissions;
|
|
375
|
-
|
|
486
|
+
meter;
|
|
487
|
+
constructor(pool, permissions = null, meter = null) {
|
|
376
488
|
this.pool = pool;
|
|
377
489
|
this.permissions = permissions;
|
|
490
|
+
this.meter = meter;
|
|
378
491
|
}
|
|
379
492
|
// -------------------------------------------------------------------------
|
|
380
493
|
// Client lifecycle
|
|
@@ -463,10 +576,11 @@ var SubscriptionManager = class {
|
|
|
463
576
|
});
|
|
464
577
|
return;
|
|
465
578
|
}
|
|
466
|
-
const kernel = this.pool.
|
|
579
|
+
const kernel = await this.pool.preload(tid);
|
|
467
580
|
let result;
|
|
468
581
|
try {
|
|
469
582
|
const qr = await kernel.query(parsedQuery);
|
|
583
|
+
this._recordGraphIo(tid);
|
|
470
584
|
result = await hydrateAndResolve(
|
|
471
585
|
kernel,
|
|
472
586
|
qr.bindings,
|
|
@@ -502,11 +616,12 @@ var SubscriptionManager = class {
|
|
|
502
616
|
});
|
|
503
617
|
}
|
|
504
618
|
async _pushUpdate(client, sub) {
|
|
505
|
-
const kernel = this.pool.
|
|
619
|
+
const kernel = await this.pool.preload(sub.tenantId);
|
|
506
620
|
let newResult;
|
|
507
621
|
try {
|
|
508
622
|
const parsed = parseSimple(sub.query);
|
|
509
623
|
const qr = await kernel.query(parsed);
|
|
624
|
+
this._recordGraphIo(sub.tenantId);
|
|
510
625
|
newResult = await hydrateAndResolve(
|
|
511
626
|
kernel,
|
|
512
627
|
qr.bindings,
|
|
@@ -530,9 +645,17 @@ var SubscriptionManager = class {
|
|
|
530
645
|
...resolved ? { resolved: true } : {}
|
|
531
646
|
});
|
|
532
647
|
}
|
|
648
|
+
_recordGraphIo(tenantId) {
|
|
649
|
+
this.meter?.recordGraphIo(resolveUsageTenantId(tenantId));
|
|
650
|
+
}
|
|
533
651
|
_send(client, payload) {
|
|
652
|
+
const data = JSON.stringify(payload);
|
|
653
|
+
if (this.meter) {
|
|
654
|
+
const tid = resolveUsageTenantId(client.tenantId ?? DEFAULT_TENANT);
|
|
655
|
+
this.meter.recordEgress(tid, new TextEncoder().encode(data).length);
|
|
656
|
+
}
|
|
534
657
|
try {
|
|
535
|
-
client.ws.send(
|
|
658
|
+
client.ws.send(data);
|
|
536
659
|
} catch {
|
|
537
660
|
}
|
|
538
661
|
}
|
|
@@ -559,6 +682,55 @@ function computeDiff(prev, next) {
|
|
|
559
682
|
return { added, updated, removed };
|
|
560
683
|
}
|
|
561
684
|
|
|
685
|
+
// src/server/cors.ts
|
|
686
|
+
var DEFAULT_METHODS = "GET, POST, PUT, DELETE, OPTIONS";
|
|
687
|
+
var DEFAULT_HEADERS = "Content-Type, Authorization";
|
|
688
|
+
function corsEnabledForConfig(apiKey) {
|
|
689
|
+
return Boolean(process.env.TRELLIS_CORS_ORIGINS) || Boolean(apiKey);
|
|
690
|
+
}
|
|
691
|
+
function allowedOrigins() {
|
|
692
|
+
const raw = process.env.TRELLIS_CORS_ORIGINS?.trim();
|
|
693
|
+
if (!raw || raw === "*") return "*";
|
|
694
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
695
|
+
}
|
|
696
|
+
function corsHeaders(req) {
|
|
697
|
+
const origins = allowedOrigins();
|
|
698
|
+
const requestOrigin = req.headers.get("Origin");
|
|
699
|
+
let allowOrigin = "*";
|
|
700
|
+
if (origins !== "*") {
|
|
701
|
+
if (requestOrigin && origins.includes(requestOrigin)) {
|
|
702
|
+
allowOrigin = requestOrigin;
|
|
703
|
+
} else if (origins.length === 1) {
|
|
704
|
+
allowOrigin = origins[0];
|
|
705
|
+
} else {
|
|
706
|
+
allowOrigin = origins[0] ?? "*";
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return {
|
|
710
|
+
"Access-Control-Allow-Origin": allowOrigin,
|
|
711
|
+
"Access-Control-Allow-Methods": DEFAULT_METHODS,
|
|
712
|
+
"Access-Control-Allow-Headers": DEFAULT_HEADERS,
|
|
713
|
+
Vary: "Origin"
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
function withCors(req, res) {
|
|
717
|
+
const headers = new Headers(res.headers);
|
|
718
|
+
for (const [key, value] of Object.entries(corsHeaders(req))) {
|
|
719
|
+
headers.set(key, value);
|
|
720
|
+
}
|
|
721
|
+
return new Response(res.body, {
|
|
722
|
+
status: res.status,
|
|
723
|
+
statusText: res.statusText,
|
|
724
|
+
headers
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
function corsPreflightResponse(req) {
|
|
728
|
+
return new Response(null, {
|
|
729
|
+
status: 204,
|
|
730
|
+
headers: corsHeaders(req)
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
|
|
562
734
|
// src/server/server.ts
|
|
563
735
|
var __moduleDir = import.meta.dir ?? dirname(fileURLToPath(import.meta.url));
|
|
564
736
|
async function startServer(opts) {
|
|
@@ -573,8 +745,10 @@ function buildServerContext(opts) {
|
|
|
573
745
|
apiKey: config.apiKey,
|
|
574
746
|
allowPublic: true
|
|
575
747
|
};
|
|
576
|
-
const
|
|
577
|
-
const
|
|
748
|
+
const meter = new UsageMeter();
|
|
749
|
+
const subs = new SubscriptionManager(pool, permissions ?? null, meter);
|
|
750
|
+
const enableCors = corsEnabledForConfig(config.apiKey);
|
|
751
|
+
const handleHttpInner = async (req) => {
|
|
578
752
|
const url = new URL(req.url);
|
|
579
753
|
const path = url.pathname;
|
|
580
754
|
const auth = await resolveAuth(
|
|
@@ -587,6 +761,7 @@ function buildServerContext(opts) {
|
|
|
587
761
|
pool,
|
|
588
762
|
permissions: permissions ?? null,
|
|
589
763
|
subs,
|
|
764
|
+
meter,
|
|
590
765
|
authConfig,
|
|
591
766
|
config,
|
|
592
767
|
oauthProviders: opts.oauthProviders ?? {}
|
|
@@ -596,9 +771,30 @@ function buildServerContext(opts) {
|
|
|
596
771
|
return json(err.toResponse(), 403);
|
|
597
772
|
}
|
|
598
773
|
const msg = err instanceof Error ? err.message : String(err);
|
|
599
|
-
|
|
774
|
+
if (process.env.TRELLIS_DEBUG) {
|
|
775
|
+
console.error(
|
|
776
|
+
`[trellis] ${req.method} ${path} \u2192 500:`,
|
|
777
|
+
msg
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
return json(
|
|
781
|
+
{
|
|
782
|
+
error: "Internal Server Error",
|
|
783
|
+
message: msg,
|
|
784
|
+
method: req.method,
|
|
785
|
+
path
|
|
786
|
+
},
|
|
787
|
+
500
|
|
788
|
+
);
|
|
600
789
|
}
|
|
601
790
|
};
|
|
791
|
+
const handleHttp = async (req) => {
|
|
792
|
+
if (enableCors && req.method === "OPTIONS") {
|
|
793
|
+
return corsPreflightResponse(req);
|
|
794
|
+
}
|
|
795
|
+
const res = await handleHttpInner(req);
|
|
796
|
+
return enableCors ? withCors(req, res) : res;
|
|
797
|
+
};
|
|
602
798
|
return { port, authConfig, subs, handleHttp };
|
|
603
799
|
}
|
|
604
800
|
async function startServerNode(opts) {
|
|
@@ -638,17 +834,20 @@ async function startServerNode(opts) {
|
|
|
638
834
|
}
|
|
639
835
|
});
|
|
640
836
|
}
|
|
837
|
+
function recordGraphIo(ctx, tenantId) {
|
|
838
|
+
ctx.meter.recordGraphIo(resolveUsageTenantId(tenantId));
|
|
839
|
+
}
|
|
641
840
|
async function route(req, url, path, auth, tenantId, ctx) {
|
|
642
841
|
const method = req.method.toUpperCase();
|
|
643
842
|
if (method === "GET" && path === "/__trellis/inspector.js") {
|
|
644
843
|
const candidates = [
|
|
645
|
-
|
|
844
|
+
join2(__moduleDir, "db", "inspector.js"),
|
|
646
845
|
// chunk lives in dist/, inspector in dist/db/
|
|
647
|
-
|
|
846
|
+
join2(__moduleDir, "inspector.js")
|
|
648
847
|
// chunk lives in dist/db/, inspector alongside
|
|
649
848
|
];
|
|
650
849
|
for (const p of candidates) {
|
|
651
|
-
if (
|
|
850
|
+
if (existsSync2(p)) {
|
|
652
851
|
return new Response(readFileSync(p, "utf-8"), {
|
|
653
852
|
headers: { "Content-Type": "application/javascript; charset=utf-8" }
|
|
654
853
|
});
|
|
@@ -663,11 +862,11 @@ async function route(req, url, path, auth, tenantId, ctx) {
|
|
|
663
862
|
}
|
|
664
863
|
if (method === "GET" && path === "/__trellis/trellis.css") {
|
|
665
864
|
const candidates = [
|
|
666
|
-
|
|
667
|
-
|
|
865
|
+
join2(__moduleDir, "db", "trellis.css"),
|
|
866
|
+
join2(__moduleDir, "trellis.css")
|
|
668
867
|
];
|
|
669
868
|
for (const p of candidates) {
|
|
670
|
-
if (
|
|
869
|
+
if (existsSync2(p)) {
|
|
671
870
|
return new Response(readFileSync(p, "utf-8"), {
|
|
672
871
|
headers: { "Content-Type": "text/css; charset=utf-8" }
|
|
673
872
|
});
|
|
@@ -695,7 +894,7 @@ async function route(req, url, path, auth, tenantId, ctx) {
|
|
|
695
894
|
});
|
|
696
895
|
}
|
|
697
896
|
if (method === "GET" && path === "/health") {
|
|
698
|
-
const kernel = ctx.pool.
|
|
897
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
699
898
|
const ops = kernel.readAllOps().length;
|
|
700
899
|
return json({
|
|
701
900
|
status: "ok",
|
|
@@ -703,6 +902,9 @@ async function route(req, url, path, auth, tenantId, ctx) {
|
|
|
703
902
|
tenants: ctx.pool.activeTenants().length
|
|
704
903
|
});
|
|
705
904
|
}
|
|
905
|
+
if (method === "GET" && path === "/admin/usage") {
|
|
906
|
+
return handleAdminUsage(req, url, ctx);
|
|
907
|
+
}
|
|
706
908
|
if (path === "/entities" || path === "/entities/") {
|
|
707
909
|
if (method === "POST") return handleCreate(req, auth, tenantId, ctx);
|
|
708
910
|
if (method === "GET") return handleList(url, auth, tenantId, ctx);
|
|
@@ -748,7 +950,7 @@ async function handleCreate(req, auth, tenantId, ctx) {
|
|
|
748
950
|
const body = await req.json();
|
|
749
951
|
if (!body.type) return json({ error: "type is required" }, 400);
|
|
750
952
|
ctx.permissions?.assert(auth, body.type, "create");
|
|
751
|
-
const kernel = ctx.pool.
|
|
953
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
752
954
|
const entityId2 = `${body.type.toLowerCase()}:${crypto.randomUUID()}`;
|
|
753
955
|
const attrs = {
|
|
754
956
|
...body.attributes
|
|
@@ -761,32 +963,35 @@ async function handleCreate(req, auth, tenantId, ctx) {
|
|
|
761
963
|
attrs,
|
|
762
964
|
body.links
|
|
763
965
|
);
|
|
966
|
+
recordGraphIo(ctx, tenantId);
|
|
764
967
|
await ctx.subs.notify(tenantId);
|
|
765
968
|
return json({ id: entityId2, op: result.op.hash }, 201);
|
|
766
969
|
}
|
|
767
970
|
async function handleRead(id, auth, tenantId, ctx) {
|
|
768
|
-
const kernel = ctx.pool.
|
|
971
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
769
972
|
const entity = kernel.getEntity(id);
|
|
770
973
|
if (!entity) return json({ error: "Not Found" }, 404);
|
|
771
974
|
ctx.permissions?.assert(auth, entity.type, "read", entity);
|
|
772
975
|
return json(entityToJson(entity));
|
|
773
976
|
}
|
|
774
977
|
async function handleUpdate(req, id, auth, tenantId, ctx) {
|
|
775
|
-
const kernel = ctx.pool.
|
|
978
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
776
979
|
const entity = kernel.getEntity(id);
|
|
777
980
|
if (!entity) return json({ error: "Not Found" }, 404);
|
|
778
981
|
ctx.permissions?.assert(auth, entity.type, "update", entity);
|
|
779
982
|
const updates = await req.json();
|
|
780
983
|
await kernel.updateEntity(id, updates);
|
|
984
|
+
recordGraphIo(ctx, tenantId);
|
|
781
985
|
await ctx.subs.notify(tenantId);
|
|
782
986
|
return json({ id, updated: true });
|
|
783
987
|
}
|
|
784
988
|
async function handleDelete(id, auth, tenantId, ctx) {
|
|
785
|
-
const kernel = ctx.pool.
|
|
989
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
786
990
|
const entity = kernel.getEntity(id);
|
|
787
991
|
if (!entity) return json({ error: "Not Found" }, 404);
|
|
788
992
|
ctx.permissions?.assert(auth, entity.type, "delete", entity);
|
|
789
993
|
await kernel.deleteEntity(id);
|
|
994
|
+
recordGraphIo(ctx, tenantId);
|
|
790
995
|
await ctx.subs.notify(tenantId);
|
|
791
996
|
return json({ id, deleted: true });
|
|
792
997
|
}
|
|
@@ -794,7 +999,7 @@ async function handleList(url, auth, tenantId, ctx) {
|
|
|
794
999
|
const type = url.searchParams.get("type") ?? void 0;
|
|
795
1000
|
const limit = parseInt(url.searchParams.get("limit") ?? "100");
|
|
796
1001
|
const offset = parseInt(url.searchParams.get("offset") ?? "0");
|
|
797
|
-
const kernel = ctx.pool.
|
|
1002
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
798
1003
|
let entities = kernel.listEntities(type);
|
|
799
1004
|
if (ctx.permissions && type) {
|
|
800
1005
|
entities = entities.filter(
|
|
@@ -818,8 +1023,9 @@ async function handleQuery(req, auth, tenantId, ctx) {
|
|
|
818
1023
|
} catch (err) {
|
|
819
1024
|
return json({ error: "Invalid query", message: String(err) }, 400);
|
|
820
1025
|
}
|
|
821
|
-
const kernel = ctx.pool.
|
|
1026
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
822
1027
|
const result = await kernel.query(parsed);
|
|
1028
|
+
recordGraphIo(ctx, tenantId);
|
|
823
1029
|
const bindings = hydrateBindings(
|
|
824
1030
|
kernel,
|
|
825
1031
|
result.bindings
|
|
@@ -829,21 +1035,73 @@ async function handleQuery(req, auth, tenantId, ctx) {
|
|
|
829
1035
|
executionTime: result.executionTime
|
|
830
1036
|
});
|
|
831
1037
|
}
|
|
1038
|
+
async function readJsonObject(req, route2) {
|
|
1039
|
+
const raw = await req.text();
|
|
1040
|
+
if (!raw.trim()) {
|
|
1041
|
+
if (process.env.TRELLIS_DEBUG) {
|
|
1042
|
+
console.warn(`[trellis] ${req.method} ${route2}: empty request body`);
|
|
1043
|
+
}
|
|
1044
|
+
return {
|
|
1045
|
+
ok: false,
|
|
1046
|
+
response: json(
|
|
1047
|
+
{
|
|
1048
|
+
error: "Bad Request",
|
|
1049
|
+
message: "Request body is empty \u2014 client may not have sent JSON (common on iOS HTTP dev)",
|
|
1050
|
+
method: req.method,
|
|
1051
|
+
path: route2,
|
|
1052
|
+
bodyBytes: 0
|
|
1053
|
+
},
|
|
1054
|
+
400
|
|
1055
|
+
)
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
try {
|
|
1059
|
+
const data = JSON.parse(raw);
|
|
1060
|
+
return { ok: true, data };
|
|
1061
|
+
} catch (err) {
|
|
1062
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1063
|
+
if (process.env.TRELLIS_DEBUG) {
|
|
1064
|
+
console.warn(
|
|
1065
|
+
`[trellis] ${req.method} ${route2}: invalid JSON (${raw.length}B):`,
|
|
1066
|
+
msg
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
ok: false,
|
|
1071
|
+
response: json(
|
|
1072
|
+
{
|
|
1073
|
+
error: "Bad Request",
|
|
1074
|
+
message: `Invalid JSON: ${msg}`,
|
|
1075
|
+
method: req.method,
|
|
1076
|
+
path: route2,
|
|
1077
|
+
bodyBytes: raw.length
|
|
1078
|
+
},
|
|
1079
|
+
400
|
|
1080
|
+
)
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
832
1084
|
async function handleCreateOntology(req, auth, tenantId, ctx) {
|
|
833
|
-
const
|
|
1085
|
+
const parsed = await readJsonObject(req, "/ontologies");
|
|
1086
|
+
if (!parsed.ok) return parsed.response;
|
|
1087
|
+
const schema = parsed.data;
|
|
834
1088
|
if (!schema || !schema["@id"] || !Array.isArray(schema.fields)) {
|
|
835
|
-
return json(
|
|
1089
|
+
return json(
|
|
1090
|
+
{ error: "A SchemaDefinition (with @id and fields) is required" },
|
|
1091
|
+
400
|
|
1092
|
+
);
|
|
836
1093
|
}
|
|
837
1094
|
if ((schema.tier ?? "user") === "core") {
|
|
838
1095
|
return json({ error: "Core ontologies are immutable" }, 403);
|
|
839
1096
|
}
|
|
840
|
-
const kernel = ctx.pool.
|
|
1097
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
841
1098
|
const exists = kernel.listOntologies().some((ont) => ont["@id"] === schema["@id"]);
|
|
842
1099
|
if (exists) {
|
|
843
1100
|
return json({ id: schema["@id"], registered: false, existed: true }, 200);
|
|
844
1101
|
}
|
|
845
1102
|
try {
|
|
846
1103
|
kernel.createOntology(schema);
|
|
1104
|
+
recordGraphIo(ctx, tenantId);
|
|
847
1105
|
} catch (err) {
|
|
848
1106
|
const msg = err instanceof Error ? err.message : String(err);
|
|
849
1107
|
if (msg.includes("already exists")) {
|
|
@@ -861,7 +1119,7 @@ async function handleUpload(req, auth, tenantId, ctx) {
|
|
|
861
1119
|
const buffer = new Uint8Array(await req.arrayBuffer());
|
|
862
1120
|
const hashBuf = await crypto.subtle.digest("SHA-256", buffer);
|
|
863
1121
|
const hash = `blob:${Array.from(new Uint8Array(hashBuf)).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
864
|
-
const kernel = ctx.pool.
|
|
1122
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
865
1123
|
const backend = kernel.getBackend();
|
|
866
1124
|
if (!backend.hasBlob(hash)) {
|
|
867
1125
|
backend.putBlob(hash, buffer);
|
|
@@ -869,7 +1127,7 @@ async function handleUpload(req, auth, tenantId, ctx) {
|
|
|
869
1127
|
return json({ hash, size: buffer.length, contentType }, 201);
|
|
870
1128
|
}
|
|
871
1129
|
async function handleFileDownload(hash, ctx, tenantId) {
|
|
872
|
-
const kernel = ctx.pool.
|
|
1130
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
873
1131
|
const backend = kernel.getBackend();
|
|
874
1132
|
const blob = backend.getBlob(hash);
|
|
875
1133
|
if (!blob) return json({ error: "Not Found" }, 404);
|
|
@@ -877,6 +1135,7 @@ async function handleFileDownload(hash, ctx, tenantId) {
|
|
|
877
1135
|
blob.byteOffset,
|
|
878
1136
|
blob.byteOffset + blob.byteLength
|
|
879
1137
|
);
|
|
1138
|
+
ctx.meter.recordEgress(resolveUsageTenantId(tenantId), blob.byteLength);
|
|
880
1139
|
return new Response(cleanBuf, {
|
|
881
1140
|
headers: { "Content-Type": "application/octet-stream" }
|
|
882
1141
|
});
|
|
@@ -889,7 +1148,7 @@ async function handleRegister(req, tenantId, ctx) {
|
|
|
889
1148
|
if (!body.email || !body.password) {
|
|
890
1149
|
return json({ error: "email and password are required" }, 400);
|
|
891
1150
|
}
|
|
892
|
-
const kernel = ctx.pool.
|
|
1151
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
893
1152
|
const existing = kernel.listEntities("User", { email: body.email });
|
|
894
1153
|
if (existing.length > 0) {
|
|
895
1154
|
return json({ error: "Email already registered" }, 409);
|
|
@@ -917,7 +1176,7 @@ async function handleLogin(req, tenantId, ctx) {
|
|
|
917
1176
|
if (!body.email || !body.password) {
|
|
918
1177
|
return json({ error: "email and password are required" }, 400);
|
|
919
1178
|
}
|
|
920
|
-
const kernel = ctx.pool.
|
|
1179
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
921
1180
|
const users = kernel.listEntities("User", { email: body.email });
|
|
922
1181
|
if (users.length === 0) {
|
|
923
1182
|
return json({ error: "Invalid credentials" }, 401);
|
|
@@ -960,7 +1219,7 @@ async function handleOAuthCallback(url, providerName, tenantId, ctx) {
|
|
|
960
1219
|
} catch (err) {
|
|
961
1220
|
return json({ error: "OAuth exchange failed", message: String(err) }, 400);
|
|
962
1221
|
}
|
|
963
|
-
const kernel = ctx.pool.
|
|
1222
|
+
const kernel = await ctx.pool.preload(tenantId);
|
|
964
1223
|
const oauthId = `oauth:${providerName}:${profile.id}`;
|
|
965
1224
|
let users = kernel.listEntities("User", { oauthId });
|
|
966
1225
|
let userId;
|
|
@@ -1046,6 +1305,24 @@ async function verifyPassword(password, stored) {
|
|
|
1046
1305
|
const hash = Array.from(new Uint8Array(bits)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1047
1306
|
return hash === expectedHash;
|
|
1048
1307
|
}
|
|
1308
|
+
function handleAdminUsage(req, url, ctx) {
|
|
1309
|
+
if (!process.env.TURTLEDB_ADMIN_KEY) {
|
|
1310
|
+
return json({ error: "Admin usage not configured" }, 501);
|
|
1311
|
+
}
|
|
1312
|
+
if (!verifyAdminKey(req)) {
|
|
1313
|
+
return json({ error: "Unauthorized" }, 401);
|
|
1314
|
+
}
|
|
1315
|
+
const tenant = url.searchParams.get("tenant");
|
|
1316
|
+
if (!tenant) {
|
|
1317
|
+
return json({ error: "tenant query param is required" }, 400);
|
|
1318
|
+
}
|
|
1319
|
+
const refresh = url.searchParams.get("refresh") === "1";
|
|
1320
|
+
if (refresh) {
|
|
1321
|
+
ctx.meter.sampleStorage(ctx.pool, tenant);
|
|
1322
|
+
}
|
|
1323
|
+
const day = url.searchParams.get("day") ?? void 0;
|
|
1324
|
+
return json(ctx.meter.getUsage(tenant, day));
|
|
1325
|
+
}
|
|
1049
1326
|
function entityToJson(entity) {
|
|
1050
1327
|
return entityRecordToPlain(entity);
|
|
1051
1328
|
}
|
|
@@ -1071,6 +1348,11 @@ export {
|
|
|
1071
1348
|
FULLY_PUBLIC,
|
|
1072
1349
|
OWNER_ONLY,
|
|
1073
1350
|
ADMIN_ONLY,
|
|
1351
|
+
resolveUsageTenantId,
|
|
1352
|
+
dayKey,
|
|
1353
|
+
sampleTenantStorage,
|
|
1354
|
+
verifyAdminKey,
|
|
1355
|
+
UsageMeter,
|
|
1074
1356
|
SubscriptionManager,
|
|
1075
1357
|
startServer,
|
|
1076
1358
|
startServerCrossRuntime
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TrellisVcsEngine,
|
|
3
3
|
init_engine
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-L5N5PR2S.js";
|
|
5
5
|
import {
|
|
6
6
|
IdbOpLog
|
|
7
7
|
} from "./chunk-MPXUVGT3.js";
|
|
8
8
|
import {
|
|
9
9
|
JsonOpLog,
|
|
10
10
|
init_op_log
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-VBYUTRXX.js";
|
|
12
12
|
import {
|
|
13
13
|
PartyKitRoomTransport,
|
|
14
14
|
TrellisVcsSyncPeer
|