@camstack/system 1.2.347 → 1.2.349
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/addon-runner.js +2 -2
- package/dist/addon-runner.mjs +2 -2
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/calendars/calendar-color.d.ts +5 -0
- package/dist/builtins/calendars/calendar-prefs-store.d.ts +13 -0
- package/dist/builtins/calendars/calendars.addon.d.ts +4 -1
- package/dist/builtins/calendars/calendars.addon.js +143 -23
- package/dist/builtins/calendars/calendars.addon.mjs +143 -23
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/block-package.d.ts +12 -1
- package/dist/builtins/core-blocks/block-settings-store.d.ts +25 -0
- package/dist/builtins/core-blocks/block-supervisor.d.ts +6 -1
- package/dist/builtins/core-blocks/compile-block.d.ts +33 -2
- package/dist/builtins/core-blocks/core-block-store.d.ts +5 -0
- package/dist/builtins/core-blocks/core-blocks.addon.d.ts +10 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +363 -20
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +360 -21
- package/dist/builtins/core-blocks/extract-settings-schema.d.ts +6 -0
- package/dist/builtins/core-blocks/index.d.ts +3 -1
- package/dist/builtins/core-blocks/index.js +3 -0
- package/dist/builtins/core-blocks/index.mjs +2 -2
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +3 -3
- package/dist/builtins/local-network/local-network.addon.mjs +3 -3
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +4 -4
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +4 -4
- package/dist/builtins/platform-probe/index.js +3 -3
- package/dist/builtins/platform-probe/index.mjs +2 -2
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +2 -2
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +2 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{child-cap-dispatch-CVOa1BZI.js → child-cap-dispatch-DiDBYNY4.js} +3 -3
- package/dist/{child-cap-dispatch-OLFN-F85.mjs → child-cap-dispatch-Pkx_sEKR.mjs} +3 -3
- package/dist/{composition-sources-pQsmMdpR.mjs → composition-sources-DK-hFG7I.mjs} +1 -1
- package/dist/{composition-sources-CeZ3tyH8.js → composition-sources-w_NIID5d.js} +1 -1
- package/dist/{dist-BUFcHq7H.mjs → dist-C6CPaa8G.mjs} +5646 -5301
- package/dist/{dist-DTgd2gOR.js → dist-DvAczrLl.js} +5669 -5300
- package/dist/index.js +7 -7
- package/dist/index.mjs +6 -6
- package/dist/{retired-settings-keys-Ddb5cCNR.js → retired-settings-keys-BQYjCJWI.js} +1 -1
- package/dist/{retired-settings-keys-ltKefX3N.mjs → retired-settings-keys-tmMQQ9OH.mjs} +1 -1
- package/package.json +1 -1
- package/dist/{resource-monitor-B1v6E07R.mjs → resource-monitor-B2WZ8_q9.mjs} +1 -1
- package/dist/{resource-monitor-DzNn_IZK.js → resource-monitor-BgWGRxN5.js} +1 -1
- package/dist/{tls-DAtaKVUT.mjs → tls-DTlVWwAI.mjs} +1 -1
- package/dist/{tls-DEjOOARt.js → tls-ue_Xefmv.js} +1 -1
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
3
|
-
const require_dist = require("../../dist-
|
|
4
|
-
const require_composition_sources = require("../../composition-sources-
|
|
3
|
+
const require_dist = require("../../dist-DvAczrLl.js");
|
|
4
|
+
const require_composition_sources = require("../../composition-sources-w_NIID5d.js");
|
|
5
5
|
let node_crypto = require("node:crypto");
|
|
6
6
|
let _camstack_types_node = require("@camstack/types/node");
|
|
7
7
|
let node_fs_promises = require("node:fs/promises");
|
|
8
8
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
9
9
|
let node_path = require("node:path");
|
|
10
10
|
node_path = require_chunk.__toESM(node_path);
|
|
11
|
+
let node_os = require("node:os");
|
|
12
|
+
node_os = require_chunk.__toESM(node_os);
|
|
13
|
+
let node_url = require("node:url");
|
|
11
14
|
//#region src/builtins/core-blocks/block-package.ts
|
|
12
15
|
/**
|
|
13
16
|
* Turning a stored block into something the addon runner can fork.
|
|
@@ -133,11 +136,27 @@ function renderBlockManifest(blockId, blockName) {
|
|
|
133
136
|
* rewrite: the author's code is the thing that changes, and a partial update
|
|
134
137
|
* that left a stale `block.js` behind would run yesterday's code while the
|
|
135
138
|
* editor showed today's.
|
|
139
|
+
*
|
|
140
|
+
* Layout:
|
|
141
|
+
* `src/<path>` — author TypeScript when `files` is provided
|
|
142
|
+
* `dist/block.js` — bundled / transpiled entry (what the wrapper imports)
|
|
143
|
+
* `dist/index.js` — generated BaseAddon wrapper
|
|
136
144
|
*/
|
|
137
145
|
async function materializeBlock(input) {
|
|
138
146
|
const addonDir = node_path.join(input.root, input.blockId);
|
|
139
147
|
const distDir = node_path.join(addonDir, "dist");
|
|
148
|
+
const srcDir = node_path.join(addonDir, "src");
|
|
149
|
+
await node_fs_promises.rm(srcDir, {
|
|
150
|
+
recursive: true,
|
|
151
|
+
force: true
|
|
152
|
+
});
|
|
140
153
|
await node_fs_promises.mkdir(distDir, { recursive: true });
|
|
154
|
+
if (input.files !== void 0) for (const [rel, content] of Object.entries(input.files)) {
|
|
155
|
+
const abs = node_path.resolve(srcDir, rel);
|
|
156
|
+
if (!abs.startsWith(srcDir + node_path.sep) && abs !== srcDir) throw new Error(`refusing path outside the block package: ${rel}`);
|
|
157
|
+
await node_fs_promises.mkdir(node_path.dirname(abs), { recursive: true });
|
|
158
|
+
await node_fs_promises.writeFile(abs, content, "utf-8");
|
|
159
|
+
}
|
|
141
160
|
await Promise.all([
|
|
142
161
|
node_fs_promises.writeFile(node_path.join(addonDir, "package.json"), renderBlockManifest(input.blockId, input.blockName), "utf-8"),
|
|
143
162
|
node_fs_promises.writeFile(node_path.join(distDir, "block.js"), input.js, "utf-8"),
|
|
@@ -388,7 +407,12 @@ var BlockSupervisor = class {
|
|
|
388
407
|
* — the author asked for this to run, so they are owed the reason it does
|
|
389
408
|
* not. */
|
|
390
409
|
async launch(block) {
|
|
391
|
-
const
|
|
410
|
+
const { files, entry } = require_dist.resolveCoreBlockFiles(block);
|
|
411
|
+
const compiled = await this.deps.compile({
|
|
412
|
+
code: block.code,
|
|
413
|
+
files,
|
|
414
|
+
entry
|
|
415
|
+
});
|
|
392
416
|
if (!compiled.ok || compiled.js === void 0) {
|
|
393
417
|
await this.report(block.id, "failed", `the block does not compile: ${compiled.error ?? "unknown"}`);
|
|
394
418
|
return;
|
|
@@ -398,7 +422,8 @@ var BlockSupervisor = class {
|
|
|
398
422
|
root: this.deps.root,
|
|
399
423
|
blockId: block.id,
|
|
400
424
|
blockName: block.name,
|
|
401
|
-
js: compiled.js
|
|
425
|
+
js: compiled.js,
|
|
426
|
+
files
|
|
402
427
|
});
|
|
403
428
|
await this.deps.host.spawn({
|
|
404
429
|
runnerId: pkg.addonId,
|
|
@@ -464,6 +489,73 @@ var BlockSupervisor = class {
|
|
|
464
489
|
}
|
|
465
490
|
};
|
|
466
491
|
//#endregion
|
|
492
|
+
//#region src/builtins/core-blocks/block-settings-store.ts
|
|
493
|
+
var CORE_BLOCK_SETTINGS_COLLECTION = "core-blocks:settings";
|
|
494
|
+
var CORE_BLOCK_SETTINGS_COLUMNS = [{
|
|
495
|
+
name: "id",
|
|
496
|
+
type: "TEXT",
|
|
497
|
+
primaryKey: true,
|
|
498
|
+
notNull: true
|
|
499
|
+
}, {
|
|
500
|
+
name: "values",
|
|
501
|
+
type: "JSON",
|
|
502
|
+
notNull: true,
|
|
503
|
+
defaultValue: "{}"
|
|
504
|
+
}];
|
|
505
|
+
var BlockSettingsStore = class {
|
|
506
|
+
store;
|
|
507
|
+
constructor(deps) {
|
|
508
|
+
this.store = deps.store;
|
|
509
|
+
}
|
|
510
|
+
static async declare(store) {
|
|
511
|
+
await store.declareCollection.mutate({
|
|
512
|
+
collection: CORE_BLOCK_SETTINGS_COLLECTION,
|
|
513
|
+
columns: [...CORE_BLOCK_SETTINGS_COLUMNS]
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
async getValues(blockId) {
|
|
517
|
+
const row = await this.store.get.query({
|
|
518
|
+
collection: CORE_BLOCK_SETTINGS_COLLECTION,
|
|
519
|
+
key: blockId
|
|
520
|
+
});
|
|
521
|
+
if (row === null || typeof row !== "object") return {};
|
|
522
|
+
const values = row.values;
|
|
523
|
+
if (values !== null && typeof values === "object" && !Array.isArray(values)) return { ...values };
|
|
524
|
+
if (!("values" in row)) return { ...row };
|
|
525
|
+
return {};
|
|
526
|
+
}
|
|
527
|
+
async mergeValues(blockId, patch) {
|
|
528
|
+
const next = {
|
|
529
|
+
...await this.getValues(blockId),
|
|
530
|
+
...patch
|
|
531
|
+
};
|
|
532
|
+
await this.store.set.mutate({
|
|
533
|
+
collection: CORE_BLOCK_SETTINGS_COLLECTION,
|
|
534
|
+
key: blockId,
|
|
535
|
+
value: { values: next }
|
|
536
|
+
});
|
|
537
|
+
await this.mirrorToBlockAddon(blockId, next);
|
|
538
|
+
return next;
|
|
539
|
+
}
|
|
540
|
+
async delete(blockId) {
|
|
541
|
+
await this.store.delete.mutate({
|
|
542
|
+
collection: CORE_BLOCK_SETTINGS_COLLECTION,
|
|
543
|
+
key: blockId
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
async mirrorToBlockAddon(blockId, values) {
|
|
547
|
+
const namespace = require_dist.coreBlockAddonId(blockId);
|
|
548
|
+
try {
|
|
549
|
+
await this.store.set.mutate({
|
|
550
|
+
namespace,
|
|
551
|
+
collection: "addon-settings",
|
|
552
|
+
key: "root",
|
|
553
|
+
value: values
|
|
554
|
+
});
|
|
555
|
+
} catch {}
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
//#endregion
|
|
467
559
|
//#region src/builtins/core-blocks/block-type-defs.ts
|
|
468
560
|
/**
|
|
469
561
|
* The declaration files a block is authored against.
|
|
@@ -537,6 +629,24 @@ async function walk(root, dir, out) {
|
|
|
537
629
|
}
|
|
538
630
|
//#endregion
|
|
539
631
|
//#region src/builtins/core-blocks/compile-block.ts
|
|
632
|
+
/**
|
|
633
|
+
* Compiling a core block's TypeScript before it is stored or run.
|
|
634
|
+
*
|
|
635
|
+
* Two callers, one implementation on purpose: the editor asks as the author
|
|
636
|
+
* types, and the store asks before it writes. **The verdict has to be the same
|
|
637
|
+
* one**, or the editor green-lights code the server later refuses — the failure
|
|
638
|
+
* shape where a person is told everything is fine by the thing they are looking
|
|
639
|
+
* at.
|
|
640
|
+
*
|
|
641
|
+
* This is a TRANSPILE / BUNDLE, not a typecheck: esbuild strips types and
|
|
642
|
+
* reports syntax errors, which is what stops unrunnable source from reaching
|
|
643
|
+
* disk. Type errors are the editor's job (Monaco runs the real compiler against
|
|
644
|
+
* the real `.d.ts` graph); doing it again here would mean shipping tsc into the
|
|
645
|
+
* hub for an answer the author already has.
|
|
646
|
+
*
|
|
647
|
+
* Single-file blocks use `transform`. Multi-file projects write sources to a
|
|
648
|
+
* temp dir and `build` from `entry` so relative imports resolve.
|
|
649
|
+
*/
|
|
540
650
|
/** An esbuild error carries the position; the shape is narrow enough to read
|
|
541
651
|
* defensively rather than to type against the package. */
|
|
542
652
|
function positionOf(err) {
|
|
@@ -560,11 +670,18 @@ function messageOf(err) {
|
|
|
560
670
|
}
|
|
561
671
|
return err instanceof Error ? err.message : String(err);
|
|
562
672
|
}
|
|
673
|
+
function isFilesInput(source) {
|
|
674
|
+
return typeof source === "object" && source !== null && "files" in source;
|
|
675
|
+
}
|
|
563
676
|
/**
|
|
564
677
|
* Never throws. A compile failure is an ANSWER — the author needs to read it,
|
|
565
678
|
* and a thrown error at this layer becomes a 500 with the useful part buried.
|
|
566
679
|
*/
|
|
567
|
-
async function compileBlock(transpiler,
|
|
680
|
+
async function compileBlock(transpiler, source) {
|
|
681
|
+
if (isFilesInput(source)) return compileFiles(transpiler, source.files, source.entry);
|
|
682
|
+
return compileSingle(transpiler, source);
|
|
683
|
+
}
|
|
684
|
+
async function compileSingle(transpiler, code) {
|
|
568
685
|
if (code.trim().length === 0) return {
|
|
569
686
|
ok: false,
|
|
570
687
|
error: "the block is empty — it must export a default function"
|
|
@@ -586,6 +703,79 @@ async function compileBlock(transpiler, code) {
|
|
|
586
703
|
};
|
|
587
704
|
}
|
|
588
705
|
}
|
|
706
|
+
async function compileFiles(transpiler, files, entryPath) {
|
|
707
|
+
const entry = require_dist.resolveCoreBlockEntry(entryPath);
|
|
708
|
+
const entrySource = files[entry];
|
|
709
|
+
if (entrySource === void 0) return {
|
|
710
|
+
ok: false,
|
|
711
|
+
error: `files must include the entry "${entry}"`
|
|
712
|
+
};
|
|
713
|
+
if (entrySource.trim().length === 0 && Object.keys(files).length === 1) return {
|
|
714
|
+
ok: false,
|
|
715
|
+
error: "the block is empty — it must export a default function"
|
|
716
|
+
};
|
|
717
|
+
if (Object.keys(files).length === 1 && !/\bfrom\s+['"]\.\.?\//.test(entrySource)) return compileSingle(transpiler, entrySource);
|
|
718
|
+
if (typeof transpiler.build !== "function") return {
|
|
719
|
+
ok: false,
|
|
720
|
+
error: "the multi-file bundler is unavailable on this node"
|
|
721
|
+
};
|
|
722
|
+
const work = await node_fs_promises.mkdtemp(node_path.join(node_os.tmpdir(), "core-block-compile-"));
|
|
723
|
+
try {
|
|
724
|
+
for (const [rel, content] of Object.entries(files)) {
|
|
725
|
+
const abs = node_path.resolve(work, rel);
|
|
726
|
+
if (!abs.startsWith(work + node_path.sep) && abs !== work) return {
|
|
727
|
+
ok: false,
|
|
728
|
+
error: `refusing path outside the block package: ${rel}`
|
|
729
|
+
};
|
|
730
|
+
await node_fs_promises.mkdir(node_path.dirname(abs), { recursive: true });
|
|
731
|
+
await node_fs_promises.writeFile(abs, content, "utf-8");
|
|
732
|
+
}
|
|
733
|
+
const outfile = node_path.join(work, ".bundle", "block.js");
|
|
734
|
+
await node_fs_promises.mkdir(node_path.dirname(outfile), { recursive: true });
|
|
735
|
+
const result = await transpiler.build({
|
|
736
|
+
absWorkingDir: work,
|
|
737
|
+
entryPoints: [entry],
|
|
738
|
+
outfile,
|
|
739
|
+
bundle: true,
|
|
740
|
+
format: "esm",
|
|
741
|
+
platform: "node",
|
|
742
|
+
target: "node22",
|
|
743
|
+
write: true,
|
|
744
|
+
logLevel: "silent"
|
|
745
|
+
});
|
|
746
|
+
if (result.errors.length > 0) {
|
|
747
|
+
const first = result.errors[0];
|
|
748
|
+
return {
|
|
749
|
+
ok: false,
|
|
750
|
+
error: first.text,
|
|
751
|
+
...first.location ? {
|
|
752
|
+
line: first.location.line,
|
|
753
|
+
column: first.location.column
|
|
754
|
+
} : {}
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
const js = await node_fs_promises.readFile(outfile, "utf-8");
|
|
758
|
+
if (js.trim().length === 0) return {
|
|
759
|
+
ok: false,
|
|
760
|
+
error: "the block is empty — it must export a default function"
|
|
761
|
+
};
|
|
762
|
+
return {
|
|
763
|
+
ok: true,
|
|
764
|
+
js
|
|
765
|
+
};
|
|
766
|
+
} catch (err) {
|
|
767
|
+
return {
|
|
768
|
+
ok: false,
|
|
769
|
+
error: messageOf(err),
|
|
770
|
+
...positionOf(err)
|
|
771
|
+
};
|
|
772
|
+
} finally {
|
|
773
|
+
await node_fs_promises.rm(work, {
|
|
774
|
+
recursive: true,
|
|
775
|
+
force: true
|
|
776
|
+
}).catch(() => void 0);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
589
779
|
//#endregion
|
|
590
780
|
//#region src/builtins/core-blocks/core-block-store.ts
|
|
591
781
|
/**
|
|
@@ -781,8 +971,10 @@ var CoreBlockStore = class {
|
|
|
781
971
|
async create(input, createdBy) {
|
|
782
972
|
this.requireLoaded();
|
|
783
973
|
const now = this.now();
|
|
974
|
+
const normalized = require_dist.normalizeCoreBlockWrite(input);
|
|
784
975
|
const block = require_dist.CoreBlockSchema.parse({
|
|
785
976
|
...input,
|
|
977
|
+
...normalized,
|
|
786
978
|
id: this.newId(),
|
|
787
979
|
createdBy,
|
|
788
980
|
createdAt: now,
|
|
@@ -798,11 +990,23 @@ var CoreBlockStore = class {
|
|
|
798
990
|
async update(blockId, patch) {
|
|
799
991
|
const existing = this.byId.get(blockId);
|
|
800
992
|
if (!existing) throw new Error(`core block not found: ${blockId}`);
|
|
801
|
-
|
|
993
|
+
const sourcePatch = this.normalizeSourcePatch(existing, patch);
|
|
994
|
+
const nextCode = sourcePatch?.code ?? existing.code;
|
|
995
|
+
const nextFiles = sourcePatch !== null ? sourcePatch.files : existing.files;
|
|
996
|
+
const nextEntry = sourcePatch !== null ? sourcePatch.entry : existing.entry;
|
|
997
|
+
const codeChanged = nextCode !== existing.code;
|
|
998
|
+
const filesChanged = JSON.stringify(nextFiles ?? null) !== JSON.stringify(existing.files ?? null);
|
|
999
|
+
const entryChanged = (nextEntry ?? void 0) !== (existing.entry ?? void 0);
|
|
1000
|
+
if ((codeChanged || filesChanged || entryChanged || patch.placement !== void 0 && patch.placement !== existing.placement || patch.integrationId !== void 0 && patch.integrationId !== existing.integrationId) && require_dist.coreBlockSourceKind(existing) !== "code") throw new Error(`core block "${existing.name}" is a composition — its code, placement and integration are fixed; edit it with updateComposition`);
|
|
802
1001
|
if (patch.name !== void 0 && patch.name !== existing.name && require_dist.coreBlockSourceKind(existing) !== "code") throw new Error(`core block "${existing.name}" is a composition — rename it with updateComposition, which checks expectedUpdatedAt`);
|
|
803
1002
|
const updated = require_dist.CoreBlockSchema.parse({
|
|
804
1003
|
...existing,
|
|
805
1004
|
...patch,
|
|
1005
|
+
...sourcePatch !== null ? {
|
|
1006
|
+
code: nextCode,
|
|
1007
|
+
files: nextFiles,
|
|
1008
|
+
entry: nextEntry
|
|
1009
|
+
} : {},
|
|
806
1010
|
id: existing.id,
|
|
807
1011
|
createdBy: existing.createdBy,
|
|
808
1012
|
createdAt: existing.createdAt,
|
|
@@ -907,6 +1111,32 @@ var CoreBlockStore = class {
|
|
|
907
1111
|
}
|
|
908
1112
|
});
|
|
909
1113
|
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Resolve a source-affecting patch into the normalized `{ code, files?, entry? }`
|
|
1116
|
+
* that will be stored. `null` when the patch does not touch source.
|
|
1117
|
+
*/
|
|
1118
|
+
normalizeSourcePatch(existing, patch) {
|
|
1119
|
+
if (patch.files !== void 0) return require_dist.normalizeCoreBlockWrite({
|
|
1120
|
+
code: patch.code,
|
|
1121
|
+
files: patch.files,
|
|
1122
|
+
entry: patch.entry ?? existing.entry
|
|
1123
|
+
});
|
|
1124
|
+
if (patch.code === void 0 && patch.entry === void 0) return null;
|
|
1125
|
+
if (existing.files !== void 0) {
|
|
1126
|
+
const entry = require_dist.resolveCoreBlockEntry(patch.entry ?? existing.entry);
|
|
1127
|
+
return require_dist.normalizeCoreBlockWrite({
|
|
1128
|
+
files: {
|
|
1129
|
+
...existing.files,
|
|
1130
|
+
[entry]: patch.code ?? existing.files[entry] ?? existing.code
|
|
1131
|
+
},
|
|
1132
|
+
entry
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
return require_dist.normalizeCoreBlockWrite({
|
|
1136
|
+
code: patch.code ?? existing.code,
|
|
1137
|
+
entry: patch.entry
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
910
1140
|
};
|
|
911
1141
|
//#endregion
|
|
912
1142
|
//#region src/builtins/core-blocks/blocks-integration.ts
|
|
@@ -1412,6 +1642,47 @@ function buildCompositionApi(deps) {
|
|
|
1412
1642
|
};
|
|
1413
1643
|
}
|
|
1414
1644
|
//#endregion
|
|
1645
|
+
//#region src/builtins/core-blocks/extract-settings-schema.ts
|
|
1646
|
+
/**
|
|
1647
|
+
* Read an optional `settingsSchema` named export from a compiled block bundle.
|
|
1648
|
+
*
|
|
1649
|
+
* The author declares the form next to their default export:
|
|
1650
|
+
*
|
|
1651
|
+
* export const settingsSchema = { sections: [...] }
|
|
1652
|
+
* export default async function (ctx) { … }
|
|
1653
|
+
*
|
|
1654
|
+
* Until the first successful extract, `getBlockSettings` returns null. A
|
|
1655
|
+
* failed import is NOT a compile failure — the block can still run; the
|
|
1656
|
+
* settings UI simply stays absent.
|
|
1657
|
+
*/
|
|
1658
|
+
function looksLikeSchema(value) {
|
|
1659
|
+
if (value === null || typeof value !== "object") return false;
|
|
1660
|
+
const sections = value.sections;
|
|
1661
|
+
return Array.isArray(sections);
|
|
1662
|
+
}
|
|
1663
|
+
/**
|
|
1664
|
+
* Import the bundled module and return its `settingsSchema` export, or null.
|
|
1665
|
+
* Never throws.
|
|
1666
|
+
*/
|
|
1667
|
+
async function extractSettingsSchema(js) {
|
|
1668
|
+
const dir = await node_fs_promises.mkdtemp(node_path.join(node_os.tmpdir(), "core-block-schema-"));
|
|
1669
|
+
const file = node_path.join(dir, "block.mjs");
|
|
1670
|
+
try {
|
|
1671
|
+
await node_fs_promises.writeFile(file, js, "utf-8");
|
|
1672
|
+
const mod = await import((0, node_url.pathToFileURL)(file).href);
|
|
1673
|
+
if (mod === null || typeof mod !== "object") return null;
|
|
1674
|
+
const schema = mod.settingsSchema;
|
|
1675
|
+
return looksLikeSchema(schema) ? schema : null;
|
|
1676
|
+
} catch {
|
|
1677
|
+
return null;
|
|
1678
|
+
} finally {
|
|
1679
|
+
await node_fs_promises.rm(dir, {
|
|
1680
|
+
recursive: true,
|
|
1681
|
+
force: true
|
|
1682
|
+
}).catch(() => void 0);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
//#endregion
|
|
1415
1686
|
//#region src/builtins/core-blocks/core-blocks.addon.ts
|
|
1416
1687
|
/**
|
|
1417
1688
|
* The `core-blocks` provider — CRUD over user-authored TypeScript, with the
|
|
@@ -1452,6 +1723,7 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
1452
1723
|
super({});
|
|
1453
1724
|
}
|
|
1454
1725
|
store = null;
|
|
1726
|
+
prefs = null;
|
|
1455
1727
|
transpiler = null;
|
|
1456
1728
|
typeDefs = null;
|
|
1457
1729
|
supervisor = null;
|
|
@@ -1461,10 +1733,12 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
1461
1733
|
const settingsStore = this.ctx.api?.settingsStore;
|
|
1462
1734
|
if (!settingsStore) throw new Error("core-blocks: settings-store API not available — refusing to register the cap");
|
|
1463
1735
|
await CoreBlockStore.declare(settingsStore);
|
|
1736
|
+
await BlockSettingsStore.declare(settingsStore);
|
|
1464
1737
|
this.store = new CoreBlockStore({
|
|
1465
1738
|
store: settingsStore,
|
|
1466
1739
|
logger: this.ctx.logger.child("store")
|
|
1467
1740
|
});
|
|
1741
|
+
this.prefs = new BlockSettingsStore({ store: settingsStore });
|
|
1468
1742
|
await this.store.load();
|
|
1469
1743
|
this.transpiler = await loadTranspiler(this.ctx.logger);
|
|
1470
1744
|
armBlocksIntegration({
|
|
@@ -1491,6 +1765,7 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
1491
1765
|
this.supervisor?.stop();
|
|
1492
1766
|
this.supervisor = null;
|
|
1493
1767
|
this.store = null;
|
|
1768
|
+
this.prefs = null;
|
|
1494
1769
|
this.transpiler = null;
|
|
1495
1770
|
this.typeDefs = null;
|
|
1496
1771
|
}
|
|
@@ -1527,12 +1802,16 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
1527
1802
|
setStatus: (blockId, status, error) => store.setStatus(blockId, status, error)
|
|
1528
1803
|
},
|
|
1529
1804
|
host: createBrokerProcessHost(broker),
|
|
1530
|
-
compile: async (
|
|
1805
|
+
compile: async (source) => {
|
|
1531
1806
|
if (this.transpiler === null) return {
|
|
1532
1807
|
ok: false,
|
|
1533
1808
|
error: "the compiler is unavailable on this node"
|
|
1534
1809
|
};
|
|
1535
|
-
|
|
1810
|
+
const input = source.files !== void 0 ? {
|
|
1811
|
+
files: { ...source.files },
|
|
1812
|
+
entry: source.entry
|
|
1813
|
+
} : source.code;
|
|
1814
|
+
return compileBlock(this.transpiler, input);
|
|
1536
1815
|
},
|
|
1537
1816
|
logger: this.ctx.logger.child("supervisor"),
|
|
1538
1817
|
composer: { apply: async (input) => {
|
|
@@ -1594,27 +1873,51 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
1594
1873
|
return this.store;
|
|
1595
1874
|
}
|
|
1596
1875
|
/**
|
|
1597
|
-
* Compile, or explain why not.
|
|
1876
|
+
* Compile, or explain why not. Returns the emitted JS so a successful gate
|
|
1877
|
+
* can also extract `settingsSchema` without compiling twice.
|
|
1598
1878
|
*
|
|
1599
1879
|
* A missing transpiler REFUSES the write rather than waving it through: code
|
|
1600
1880
|
* that reached disk uncompiled is code the runner will fail on, far from the
|
|
1601
1881
|
* person who wrote it.
|
|
1602
1882
|
*/
|
|
1603
|
-
async gate(
|
|
1883
|
+
async gate(input) {
|
|
1604
1884
|
if (this.transpiler === null) throw new Error("core-blocks: the compiler is unavailable — refusing to store unchecked code");
|
|
1605
|
-
const
|
|
1606
|
-
|
|
1885
|
+
const normalized = require_dist.normalizeCoreBlockWrite(input);
|
|
1886
|
+
const source = normalized.files !== void 0 ? {
|
|
1887
|
+
files: normalized.files,
|
|
1888
|
+
entry: normalized.entry
|
|
1889
|
+
} : normalized.code;
|
|
1890
|
+
const result = await compileBlock(this.transpiler, source);
|
|
1891
|
+
if (!result.ok || result.js === void 0) {
|
|
1607
1892
|
const where = result.line !== void 0 ? ` (line ${result.line})` : "";
|
|
1608
1893
|
throw new Error(`core-blocks: the code does not compile${where}: ${result.error ?? "unknown"}`);
|
|
1609
1894
|
}
|
|
1895
|
+
return result.js;
|
|
1896
|
+
}
|
|
1897
|
+
requirePrefs() {
|
|
1898
|
+
if (this.prefs === null) throw new Error("core-blocks: not initialized");
|
|
1899
|
+
return this.prefs;
|
|
1900
|
+
}
|
|
1901
|
+
/**
|
|
1902
|
+
* After a successful compile, cache the entry's `settingsSchema` export on
|
|
1903
|
+
* the block when the author did not set one by hand. Never overwrites an
|
|
1904
|
+
* explicit schema the editor already stored.
|
|
1905
|
+
*/
|
|
1906
|
+
async maybeCacheSettingsSchema(blockId, js, existingSchema) {
|
|
1907
|
+
if (existingSchema !== void 0) return null;
|
|
1908
|
+
const schema = await extractSettingsSchema(js);
|
|
1909
|
+
if (schema === null) return null;
|
|
1910
|
+
return this.requireStore().update(blockId, { settingsSchema: schema });
|
|
1610
1911
|
}
|
|
1611
1912
|
buildProvider() {
|
|
1612
1913
|
return {
|
|
1613
1914
|
list: async () => ({ blocks: [...this.requireStore().list()] }),
|
|
1614
1915
|
get: async ({ blockId }) => ({ block: this.requireStore().get(blockId) }),
|
|
1615
1916
|
create: async ({ block, caller }) => {
|
|
1616
|
-
await this.gate(block
|
|
1617
|
-
|
|
1917
|
+
const js = await this.gate(block);
|
|
1918
|
+
let created = await this.requireStore().create(block, caller.userId);
|
|
1919
|
+
const withSchema = await this.maybeCacheSettingsSchema(created.id, js, created.settingsSchema);
|
|
1920
|
+
if (withSchema !== null) created = withSchema;
|
|
1618
1921
|
this.ctx.logger.info("core block created", { meta: {
|
|
1619
1922
|
blockId: created.id,
|
|
1620
1923
|
name: created.name,
|
|
@@ -1624,8 +1927,21 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
1624
1927
|
return { block: created };
|
|
1625
1928
|
},
|
|
1626
1929
|
update: async ({ blockId, block, caller }) => {
|
|
1627
|
-
|
|
1628
|
-
|
|
1930
|
+
const sourceChanged = block.code !== void 0 || block.files !== void 0 || block.entry !== void 0;
|
|
1931
|
+
let js = null;
|
|
1932
|
+
if (sourceChanged) {
|
|
1933
|
+
const existing = this.requireStore().get(blockId);
|
|
1934
|
+
js = await this.gate({
|
|
1935
|
+
code: block.code ?? existing?.code,
|
|
1936
|
+
files: block.files ?? existing?.files,
|
|
1937
|
+
entry: block.entry ?? existing?.entry
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1940
|
+
let updated = await this.requireStore().update(blockId, block);
|
|
1941
|
+
if (js !== null && block.settingsSchema === void 0) {
|
|
1942
|
+
const withSchema = await this.maybeCacheSettingsSchema(blockId, js, void 0);
|
|
1943
|
+
if (withSchema !== null) updated = withSchema;
|
|
1944
|
+
}
|
|
1629
1945
|
this.ctx.logger.info("core block updated", { meta: {
|
|
1630
1946
|
blockId,
|
|
1631
1947
|
by: caller.userId
|
|
@@ -1635,6 +1951,7 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
1635
1951
|
},
|
|
1636
1952
|
delete: async ({ blockId }) => {
|
|
1637
1953
|
await this.requireStore().delete(blockId);
|
|
1954
|
+
await this.requirePrefs().delete(blockId);
|
|
1638
1955
|
this.convergeSoon();
|
|
1639
1956
|
return { success: true };
|
|
1640
1957
|
},
|
|
@@ -1664,14 +1981,30 @@ var CoreBlocksAddon = class extends require_dist.BaseAddon {
|
|
|
1664
1981
|
await this.supervisor.restart(blockId);
|
|
1665
1982
|
return { block: store.get(blockId) ?? block };
|
|
1666
1983
|
},
|
|
1667
|
-
compile: async (
|
|
1984
|
+
compile: async (input) => {
|
|
1668
1985
|
if (this.transpiler === null) return {
|
|
1669
1986
|
ok: false,
|
|
1670
1987
|
error: "the compiler is unavailable on this node"
|
|
1671
1988
|
};
|
|
1672
|
-
const
|
|
1989
|
+
const source = input.files !== void 0 ? {
|
|
1990
|
+
files: input.files,
|
|
1991
|
+
entry: input.entry
|
|
1992
|
+
} : input.code ?? "";
|
|
1993
|
+
const { js: _js, ...verdict } = await compileBlock(this.transpiler, source);
|
|
1673
1994
|
return verdict;
|
|
1674
1995
|
},
|
|
1996
|
+
getBlockSettings: async ({ blockId }) => {
|
|
1997
|
+
const block = this.requireStore().get(blockId);
|
|
1998
|
+
if (block === null) return null;
|
|
1999
|
+
const schema = block.settingsSchema;
|
|
2000
|
+
if (schema === void 0) return null;
|
|
2001
|
+
return require_dist.hydrateSchema(schema, await this.requirePrefs().getValues(blockId));
|
|
2002
|
+
},
|
|
2003
|
+
updateBlockSettings: async ({ blockId, patch }) => {
|
|
2004
|
+
if (this.requireStore().get(blockId) === null) throw new Error(`core-blocks: no block "${blockId}"`);
|
|
2005
|
+
await this.requirePrefs().mergeValues(blockId, patch);
|
|
2006
|
+
return { success: true };
|
|
2007
|
+
},
|
|
1675
2008
|
getTypeDefs: async () => {
|
|
1676
2009
|
this.typeDefs ??= await loadBlockTypeDefs(this.ctx.logger);
|
|
1677
2010
|
return { libs: this.typeDefs.map((l) => ({
|
|
@@ -1758,9 +2091,16 @@ function createBrokerProcessHost(broker) {
|
|
|
1758
2091
|
*/
|
|
1759
2092
|
async function loadTranspiler(logger) {
|
|
1760
2093
|
try {
|
|
1761
|
-
const
|
|
2094
|
+
const mod = await import("esbuild");
|
|
2095
|
+
const transform = mod.transform;
|
|
2096
|
+
const build = mod.build;
|
|
1762
2097
|
if (typeof transform !== "function") return null;
|
|
1763
|
-
const transpiler = {
|
|
2098
|
+
const transpiler = {
|
|
2099
|
+
transform,
|
|
2100
|
+
...typeof build === "function" ? { build: async (options) => {
|
|
2101
|
+
return { errors: (await build(options)).errors };
|
|
2102
|
+
} } : {}
|
|
2103
|
+
};
|
|
1764
2104
|
await transpiler.transform("export default 0", {
|
|
1765
2105
|
loader: "ts",
|
|
1766
2106
|
format: "esm",
|
|
@@ -1774,13 +2114,16 @@ async function loadTranspiler(logger) {
|
|
|
1774
2114
|
}
|
|
1775
2115
|
//#endregion
|
|
1776
2116
|
exports.BLOCK_ADDON_PREFIX = BLOCK_ADDON_PREFIX;
|
|
2117
|
+
exports.BlockSettingsStore = BlockSettingsStore;
|
|
1777
2118
|
exports.BlockSupervisor = BlockSupervisor;
|
|
1778
2119
|
exports.CORE_BLOCKS_COLLECTION = CORE_BLOCKS_COLLECTION;
|
|
2120
|
+
exports.CORE_BLOCK_SETTINGS_COLLECTION = CORE_BLOCK_SETTINGS_COLLECTION;
|
|
1779
2121
|
exports.CoreBlockStore = CoreBlockStore;
|
|
1780
2122
|
exports.CoreBlocksAddon = CoreBlocksAddon;
|
|
1781
2123
|
exports.blockAddonId = blockAddonId;
|
|
1782
2124
|
exports.blockIdFromAddonId = blockIdFromAddonId;
|
|
1783
2125
|
exports.compileBlock = compileBlock;
|
|
2126
|
+
exports.extractSettingsSchema = extractSettingsSchema;
|
|
1784
2127
|
exports.loadBlockTypeDefs = loadBlockTypeDefs;
|
|
1785
2128
|
exports.materializeBlock = materializeBlock;
|
|
1786
2129
|
exports.removeBlockPackage = removeBlockPackage;
|