@lantharos/pult 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -14
- package/cli.mjs +363 -124
- package/index.d.mts +138 -97
- package/index.mjs +171 -77
- package/package.json +22 -3
- package/{schema-CzG8J_9_.mjs → schema-DuTVNptF.mjs} +65 -42
- package/cli.d.mts +0 -1
- package/stub.d.mts +0 -11
package/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as mapBlocks,
|
|
1
|
+
import { A as mapBlocks, D as sign, E as NonceWindow, F as HOME, I as actionId, L as findActionDef, M as valuesIn, N as DEFAULT_STATES, O as verify, S as kindOf, T as refKey, a as collect, b as captureOrigin, d as Transport, f as b, g as isPendingAttachment, h as hasPendingAttachments, i as validate, k as eachBlock, m as fieldValues, n as reviveDates, o as findAction, p as bindActions, s as flag, t as ValidationError, u as PultError, v as view, w as HEADER, y as KIND } from "./schema-DuTVNptF.mjs";
|
|
2
2
|
//#region ../protocol/src/flags.ts
|
|
3
3
|
function rampAt(ramp, now = Date.now()) {
|
|
4
4
|
if (now >= ramp.end) return ramp.to;
|
|
@@ -15,7 +15,7 @@ function currentValue(state, now = Date.now()) {
|
|
|
15
15
|
}
|
|
16
16
|
function resolveFlag(name, state, context = {}, now = Date.now()) {
|
|
17
17
|
const { key, attributes = {} } = context;
|
|
18
|
-
if (key !== void 0 &&
|
|
18
|
+
if (key !== void 0 && Object.hasOwn(state.targets, key)) return state.targets[key];
|
|
19
19
|
const rule = state.rules.find((candidate) => candidate.conditions.every((condition) => holds(condition, attributes[condition.attribute])));
|
|
20
20
|
if (rule) return rule.rollout === null ? rule.value : share(name, key, rule.rollout);
|
|
21
21
|
const rollout = currentRollout(state, now);
|
|
@@ -63,10 +63,11 @@ var Batcher = class {
|
|
|
63
63
|
}
|
|
64
64
|
send(item) {
|
|
65
65
|
return new Promise((resolve, reject) => {
|
|
66
|
-
const
|
|
66
|
+
const json = JSON.stringify(item);
|
|
67
|
+
const size = utf8Length(json);
|
|
67
68
|
if (this.#bytes + size > MAX_BYTES) this.#flush();
|
|
68
69
|
this.#queue.push({
|
|
69
|
-
|
|
70
|
+
json,
|
|
70
71
|
size,
|
|
71
72
|
resolve,
|
|
72
73
|
reject
|
|
@@ -89,15 +90,15 @@ var Batcher = class {
|
|
|
89
90
|
if (batch.length) this.#post(batch);
|
|
90
91
|
}
|
|
91
92
|
async #post(batch) {
|
|
92
|
-
const body = {
|
|
93
|
+
const body = `{"items":[${batch.map((entry) => entry.json).join(",")}]}`;
|
|
93
94
|
try {
|
|
94
95
|
let response;
|
|
95
96
|
try {
|
|
96
|
-
response = await this.transport.
|
|
97
|
+
response = await this.transport.json("POST", "/v1/items", body);
|
|
97
98
|
} catch (error) {
|
|
98
99
|
if (!(error instanceof PultError && error.code === "manifest_required")) throw error;
|
|
99
100
|
await this.sync();
|
|
100
|
-
response = await this.transport.
|
|
101
|
+
response = await this.transport.json("POST", "/v1/items", body);
|
|
101
102
|
}
|
|
102
103
|
response.results.forEach((outcome, index) => {
|
|
103
104
|
const entry = batch[index];
|
|
@@ -109,8 +110,16 @@ var Batcher = class {
|
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
};
|
|
113
|
+
function utf8Length(text) {
|
|
114
|
+
let bytes = text.length;
|
|
115
|
+
for (let index = 0; index < text.length; index++) {
|
|
116
|
+
const code = text.charCodeAt(index);
|
|
117
|
+
if (code >= 128) bytes += code < 2048 || code >= 55296 && code <= 57343 ? 1 : 2;
|
|
118
|
+
}
|
|
119
|
+
return bytes;
|
|
120
|
+
}
|
|
112
121
|
//#endregion
|
|
113
|
-
//#region src/define/inbox.ts
|
|
122
|
+
//#region src/define/inbox/inbox.ts
|
|
114
123
|
function inbox(name, options) {
|
|
115
124
|
const states = options.states ?? DEFAULT_STATES;
|
|
116
125
|
const closed = options.closed ?? (options.states ? states.slice(1) : ["handled"]);
|
|
@@ -138,7 +147,7 @@ function liveView(title, data, record) {
|
|
|
138
147
|
};
|
|
139
148
|
}
|
|
140
149
|
//#endregion
|
|
141
|
-
//#region src/define/triage.ts
|
|
150
|
+
//#region src/define/inbox/triage.ts
|
|
142
151
|
function noul(prompt, criteria) {
|
|
143
152
|
return {
|
|
144
153
|
type: "noul",
|
|
@@ -204,14 +213,14 @@ function action(name, options) {
|
|
|
204
213
|
const identity = (value) => value;
|
|
205
214
|
function resource(name, options) {
|
|
206
215
|
const origin = captureOrigin();
|
|
207
|
-
const actions = { "*": { id:
|
|
216
|
+
const actions = { "*": { id: actionId(name, "*") } };
|
|
208
217
|
for (const [key, action] of Object.entries(options.actions?.(identity) ?? {})) actions[key] = {
|
|
209
218
|
[KIND]: "action",
|
|
210
219
|
origin,
|
|
211
220
|
options: action,
|
|
212
221
|
resource: name,
|
|
213
222
|
name: key,
|
|
214
|
-
id:
|
|
223
|
+
id: actionId(name, key)
|
|
215
224
|
};
|
|
216
225
|
return {
|
|
217
226
|
[KIND]: "resource",
|
|
@@ -319,28 +328,35 @@ async function titles(definitions, request) {
|
|
|
319
328
|
return Object.fromEntries(resolved.filter((entry) => entry !== null));
|
|
320
329
|
}
|
|
321
330
|
async function available(definitions, request) {
|
|
322
|
-
const
|
|
323
|
-
for (const ref of request.refs) {
|
|
331
|
+
const entries = await Promise.all(request.refs.map(async (ref) => {
|
|
324
332
|
const resource = definitions.resources.get(ref.resource);
|
|
325
333
|
const record = resource && await resource.options.get(ref.id);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
334
|
+
return resource && record ? [[refKey(ref), actionsFor(resource, record)]] : [];
|
|
335
|
+
}));
|
|
336
|
+
return Object.fromEntries(entries.flat());
|
|
337
|
+
}
|
|
338
|
+
function actionsFor(resource, record) {
|
|
339
|
+
const actions = {};
|
|
340
|
+
for (const [name, action] of Object.entries(resource.actions)) {
|
|
341
|
+
if (kindOf(action) !== "action") continue;
|
|
342
|
+
const { when, defaults } = action.options;
|
|
343
|
+
if (when && !when(record)) continue;
|
|
344
|
+
actions[name] = defaults ? JSON.parse(JSON.stringify(defaults(record))) : null;
|
|
335
345
|
}
|
|
336
|
-
return
|
|
346
|
+
return actions;
|
|
337
347
|
}
|
|
338
348
|
async function settle(definitions, blocks, scope) {
|
|
339
349
|
const bound = scope ? bindActions(blocks, scope.resource, recordId(scope.resource, scope.record)) : blocks;
|
|
340
350
|
const loaded = /* @__PURE__ */ new Map();
|
|
341
|
-
if (scope) loaded.set(
|
|
351
|
+
if (scope) loaded.set(refKey({
|
|
352
|
+
resource: scope.resource.name,
|
|
353
|
+
id: recordId(scope.resource, scope.record)
|
|
354
|
+
}), Promise.resolve(scope.record));
|
|
342
355
|
const load = (resource, id) => {
|
|
343
|
-
const key =
|
|
356
|
+
const key = refKey({
|
|
357
|
+
resource: resource.name,
|
|
358
|
+
id
|
|
359
|
+
});
|
|
344
360
|
if (!loaded.has(key)) loaded.set(key, Promise.resolve(resource.options.get(id)));
|
|
345
361
|
return loaded.get(key);
|
|
346
362
|
};
|
|
@@ -361,15 +377,10 @@ async function settle(definitions, blocks, scope) {
|
|
|
361
377
|
const visit = (target) => {
|
|
362
378
|
if (!targets.has(keyOf(target))) targets.set(keyOf(target), verdict(target));
|
|
363
379
|
};
|
|
364
|
-
const editsIn = (value) => {
|
|
365
|
-
if (value && typeof value === "object" && "edit" in value) visit(value.edit);
|
|
366
|
-
};
|
|
367
380
|
eachBlock(bound, (block) => {
|
|
368
381
|
if (block.type === "actions") for (const button of block.actions) visit(button);
|
|
369
382
|
if (block.type === "form") visit(block.form);
|
|
370
|
-
|
|
371
|
-
if (block.type === "stats") for (const stat of block.stats) editsIn(stat.value);
|
|
372
|
-
if (block.type === "table") for (const row of block.rows) for (const value of row) editsIn(value);
|
|
383
|
+
for (const value of valuesIn(block)) if (value && typeof value === "object" && "edit" in value) visit(value.edit);
|
|
373
384
|
});
|
|
374
385
|
if (!targets.size) return bound;
|
|
375
386
|
const verdicts = new Map(await Promise.all([...targets].map(async ([key, pending]) => [key, await pending])));
|
|
@@ -482,7 +493,10 @@ var Dispatcher = class {
|
|
|
482
493
|
this.report = report;
|
|
483
494
|
}
|
|
484
495
|
definitions() {
|
|
485
|
-
this.#definitions ??= Promise.all(Object.values(this.project.modules).map((load) => load())).then(collect)
|
|
496
|
+
this.#definitions ??= Promise.all(Object.values(this.project.modules).map((load) => load())).then(collect).catch((error) => {
|
|
497
|
+
this.#definitions = null;
|
|
498
|
+
throw error;
|
|
499
|
+
});
|
|
486
500
|
return this.#definitions;
|
|
487
501
|
}
|
|
488
502
|
async handle(envelope, defer = () => {}) {
|
|
@@ -572,7 +586,7 @@ async function renderItem(inbox, item, upload) {
|
|
|
572
586
|
return {
|
|
573
587
|
title,
|
|
574
588
|
record: item.record ?? void 0,
|
|
575
|
-
data
|
|
589
|
+
data,
|
|
576
590
|
blocks: bindActions(await upload(blocks), inbox.options.resource ?? null, item.record ?? null),
|
|
577
591
|
replyTo: inbox.options.reply?.to(view)
|
|
578
592
|
};
|
|
@@ -591,6 +605,7 @@ function defaultBlocks(data) {
|
|
|
591
605
|
//#endregion
|
|
592
606
|
//#region src/client/flags.ts
|
|
593
607
|
const FRESH_MS = 1e4;
|
|
608
|
+
const MAX_PARSED = 256;
|
|
594
609
|
const EMPTY = {
|
|
595
610
|
version: -1,
|
|
596
611
|
flags: {}
|
|
@@ -615,6 +630,7 @@ var Flags = class {
|
|
|
615
630
|
const state = (await this.#current()).flags[flag.name];
|
|
616
631
|
const raw = state === void 0 ? void 0 : resolveFlag(flag.name, state, contextOf(context));
|
|
617
632
|
if (raw === void 0 || raw === null) return flag.options.default;
|
|
633
|
+
if (!flag.options.value) return typeof raw === "boolean" ? raw : flag.options.default;
|
|
618
634
|
return this.#validated(flag, raw);
|
|
619
635
|
}
|
|
620
636
|
takeReads() {
|
|
@@ -624,7 +640,7 @@ var Flags = class {
|
|
|
624
640
|
return reads;
|
|
625
641
|
}
|
|
626
642
|
#store(snapshot) {
|
|
627
|
-
if (snapshot
|
|
643
|
+
if (snapshot !== this.#snapshot) this.#parsed.clear();
|
|
628
644
|
this.#snapshot = snapshot;
|
|
629
645
|
this.#checkedAt = Date.now();
|
|
630
646
|
}
|
|
@@ -651,12 +667,16 @@ var Flags = class {
|
|
|
651
667
|
return this.#snapshot ?? EMPTY;
|
|
652
668
|
}
|
|
653
669
|
#validated(flag, raw) {
|
|
654
|
-
|
|
655
|
-
|
|
670
|
+
let values = this.#parsed.get(flag.name);
|
|
671
|
+
if (!values) {
|
|
672
|
+
values = /* @__PURE__ */ new Map();
|
|
673
|
+
this.#parsed.set(flag.name, values);
|
|
674
|
+
}
|
|
675
|
+
let parsed = values.get(raw);
|
|
656
676
|
if (!parsed) {
|
|
657
|
-
|
|
658
|
-
parsed =
|
|
659
|
-
|
|
677
|
+
if (values.size >= MAX_PARSED) values.clear();
|
|
678
|
+
parsed = validate(flag.options.value, raw).catch(() => flag.options.default);
|
|
679
|
+
values.set(raw, parsed);
|
|
660
680
|
}
|
|
661
681
|
return parsed;
|
|
662
682
|
}
|
|
@@ -672,11 +692,12 @@ function contextOf(context) {
|
|
|
672
692
|
//#endregion
|
|
673
693
|
//#region src/client/socket.ts
|
|
674
694
|
const HEARTBEAT_MS = 25e3;
|
|
695
|
+
const SILENCE_MS = 2 * HEARTBEAT_MS;
|
|
675
696
|
const MAX_BACKOFF_MS = 3e4;
|
|
676
|
-
function connect({ transport, version, onRequest, onSyncManifest, onFlags, reads, onStatus }) {
|
|
677
|
-
const nonces = new NonceWindow();
|
|
697
|
+
function connect({ transport, nonces, version, onRequest, onSyncManifest, onFlags, reads, onStatus }) {
|
|
678
698
|
let socket = null;
|
|
679
699
|
let heartbeat;
|
|
700
|
+
let retry;
|
|
680
701
|
let attempt = 0;
|
|
681
702
|
let closed = false;
|
|
682
703
|
const send = (message) => socket?.send(JSON.stringify(message));
|
|
@@ -716,20 +737,44 @@ function connect({ transport, version, onRequest, onSyncManifest, onFlags, reads
|
|
|
716
737
|
});
|
|
717
738
|
}
|
|
718
739
|
};
|
|
740
|
+
const stopHeartbeat = () => {
|
|
741
|
+
if (heartbeat) clearInterval(heartbeat);
|
|
742
|
+
};
|
|
743
|
+
const reconnect = () => {
|
|
744
|
+
stopHeartbeat();
|
|
745
|
+
onFlags(null);
|
|
746
|
+
onStatus?.("disconnected");
|
|
747
|
+
if (closed) return;
|
|
748
|
+
const delay = Math.min(MAX_BACKOFF_MS, 500 * 2 ** attempt++) * (.5 + Math.random() / 2);
|
|
749
|
+
retry = setTimeout(open, delay);
|
|
750
|
+
};
|
|
719
751
|
const open = async () => {
|
|
720
752
|
const signature = await sign(transport.key.secret, "connect", version);
|
|
753
|
+
if (closed) return;
|
|
721
754
|
const params = new URLSearchParams({
|
|
722
755
|
environment: transport.key.environment,
|
|
723
756
|
version,
|
|
724
757
|
...signature
|
|
725
758
|
});
|
|
726
|
-
|
|
727
|
-
|
|
759
|
+
const current = new WebSocket(`${transport.url.replace(/^http/, "ws")}/v1/connect?${params}`);
|
|
760
|
+
let heardAt = Date.now();
|
|
761
|
+
let lost = false;
|
|
762
|
+
const lose = () => {
|
|
763
|
+
if (lost) return;
|
|
764
|
+
lost = true;
|
|
765
|
+
current.close();
|
|
766
|
+
reconnect();
|
|
767
|
+
};
|
|
768
|
+
socket = current;
|
|
769
|
+
current.addEventListener("message", (event) => {
|
|
770
|
+
heardAt = Date.now();
|
|
728
771
|
if (event.data !== "pong") handle(JSON.parse(String(event.data)));
|
|
729
772
|
});
|
|
730
|
-
|
|
773
|
+
current.addEventListener("open", () => {
|
|
774
|
+
heardAt = Date.now();
|
|
731
775
|
heartbeat = setInterval(() => {
|
|
732
|
-
|
|
776
|
+
if (Date.now() - heardAt > SILENCE_MS) return lose();
|
|
777
|
+
current.send("ping");
|
|
733
778
|
const counted = reads();
|
|
734
779
|
if (counted) send({
|
|
735
780
|
type: "reads",
|
|
@@ -737,38 +782,52 @@ function connect({ transport, version, onRequest, onSyncManifest, onFlags, reads
|
|
|
737
782
|
});
|
|
738
783
|
}, HEARTBEAT_MS);
|
|
739
784
|
});
|
|
740
|
-
|
|
741
|
-
if (heartbeat) clearInterval(heartbeat);
|
|
742
|
-
onFlags(null);
|
|
743
|
-
onStatus?.("disconnected");
|
|
744
|
-
if (closed) return;
|
|
745
|
-
const delay = Math.min(MAX_BACKOFF_MS, 500 * 2 ** attempt++) * (.5 + Math.random() / 2);
|
|
746
|
-
setTimeout(open, delay);
|
|
747
|
-
});
|
|
785
|
+
current.addEventListener("close", lose);
|
|
748
786
|
};
|
|
749
787
|
open();
|
|
750
788
|
return { close() {
|
|
751
789
|
closed = true;
|
|
790
|
+
if (retry) clearTimeout(retry);
|
|
791
|
+
stopHeartbeat();
|
|
752
792
|
socket?.close();
|
|
753
793
|
} };
|
|
754
794
|
}
|
|
755
795
|
//#endregion
|
|
756
|
-
//#region src/client/
|
|
757
|
-
function
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
if (!isPendingAttachment(block)) return block;
|
|
762
|
-
const data = block.data instanceof Blob ? block.data : new Uint8Array(block.data);
|
|
763
|
-
const { key } = await transport.upload(block.name, block.contentType, data);
|
|
796
|
+
//#region src/client/upload.ts
|
|
797
|
+
function uploader(transport) {
|
|
798
|
+
const attach = async ({ name, contentType, data }) => {
|
|
799
|
+
const bytes = await bytesOf(data);
|
|
800
|
+
const { key } = await transport.upload(name, contentType, bytes);
|
|
764
801
|
return {
|
|
765
802
|
type: "attachment",
|
|
766
|
-
name
|
|
803
|
+
name,
|
|
767
804
|
key,
|
|
768
|
-
contentType
|
|
769
|
-
size: byteLength
|
|
805
|
+
contentType,
|
|
806
|
+
size: bytes.byteLength
|
|
807
|
+
};
|
|
808
|
+
};
|
|
809
|
+
const walk = (blocks) => Promise.all(blocks.map(async (block) => {
|
|
810
|
+
if (isPendingAttachment(block)) return attach(block);
|
|
811
|
+
if (block.type === "columns") return {
|
|
812
|
+
type: "columns",
|
|
813
|
+
columns: await Promise.all(block.columns.map(walk))
|
|
770
814
|
};
|
|
815
|
+
return block;
|
|
771
816
|
}));
|
|
817
|
+
return async (blocks) => hasPendingAttachments(blocks) ? walk(blocks) : blocks;
|
|
818
|
+
}
|
|
819
|
+
async function bytesOf(data) {
|
|
820
|
+
if (data instanceof Blob) return new Uint8Array(await data.arrayBuffer());
|
|
821
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
822
|
+
return data;
|
|
823
|
+
}
|
|
824
|
+
//#endregion
|
|
825
|
+
//#region src/client/pult.ts
|
|
826
|
+
function createPult({ key = env("PULT_KEY"), project, url = env("PULT_URL") ?? "https://app.pult.sh", fetch = globalThis.fetch }) {
|
|
827
|
+
if (!key) throw new Error("Pult needs a key: pass `key` or set PULT_KEY");
|
|
828
|
+
const transport = new Transport(key, url, (input, init) => fetch(input, init));
|
|
829
|
+
const upload = uploader(transport);
|
|
830
|
+
const nonces = new NonceWindow();
|
|
772
831
|
const report = async (job, update) => {
|
|
773
832
|
await transport.request("POST", `/v1/jobs/${job}`, update);
|
|
774
833
|
};
|
|
@@ -812,6 +871,7 @@ function createPult({ key = env("PULT_KEY"), project, url = env("PULT_URL") ?? "
|
|
|
812
871
|
function listen(options = {}) {
|
|
813
872
|
return connect({
|
|
814
873
|
transport,
|
|
874
|
+
nonces,
|
|
815
875
|
version: manifest.version,
|
|
816
876
|
onRequest: (envelope) => dispatcher.handle(envelope),
|
|
817
877
|
onSyncManifest: (environment) => environment === manifest.sync ? {
|
|
@@ -824,7 +884,6 @@ function createPult({ key = env("PULT_KEY"), project, url = env("PULT_URL") ?? "
|
|
|
824
884
|
});
|
|
825
885
|
}
|
|
826
886
|
function handler() {
|
|
827
|
-
const nonces = new NonceWindow();
|
|
828
887
|
return async (request, context) => {
|
|
829
888
|
const body = await request.text();
|
|
830
889
|
const signature = signedHeaders(request.headers);
|
|
@@ -887,9 +946,6 @@ function signedHeaders(headers) {
|
|
|
887
946
|
signature
|
|
888
947
|
} : null;
|
|
889
948
|
}
|
|
890
|
-
function byteLength(data) {
|
|
891
|
-
return data instanceof Blob ? data.size : data.byteLength;
|
|
892
|
-
}
|
|
893
949
|
function env(name) {
|
|
894
950
|
return globalThis.process?.env[name];
|
|
895
951
|
}
|
|
@@ -915,20 +971,29 @@ function defineConfig(options) {
|
|
|
915
971
|
};
|
|
916
972
|
}
|
|
917
973
|
//#endregion
|
|
918
|
-
//#region src/define/
|
|
919
|
-
function
|
|
920
|
-
return { channel: channel.replace(/^#/, "") };
|
|
921
|
-
}
|
|
922
|
-
function notify(name, options) {
|
|
974
|
+
//#region src/define/console/page.ts
|
|
975
|
+
function page(name, options) {
|
|
923
976
|
return {
|
|
924
|
-
[KIND]: "
|
|
977
|
+
[KIND]: "page",
|
|
925
978
|
origin: captureOrigin(),
|
|
926
979
|
name,
|
|
927
980
|
options
|
|
928
981
|
};
|
|
929
982
|
}
|
|
983
|
+
function home(options) {
|
|
984
|
+
const resolved = Array.isArray(options) || typeof options === "function" ? { render: options } : options;
|
|
985
|
+
return {
|
|
986
|
+
[KIND]: "page",
|
|
987
|
+
origin: captureOrigin(),
|
|
988
|
+
name: HOME,
|
|
989
|
+
options: {
|
|
990
|
+
label: "Home",
|
|
991
|
+
...resolved
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
}
|
|
930
995
|
//#endregion
|
|
931
|
-
//#region src/define/role.ts
|
|
996
|
+
//#region src/define/console/role.ts
|
|
932
997
|
function role(name, options) {
|
|
933
998
|
return {
|
|
934
999
|
[KIND]: "role",
|
|
@@ -938,7 +1003,23 @@ function role(name, options) {
|
|
|
938
1003
|
};
|
|
939
1004
|
}
|
|
940
1005
|
//#endregion
|
|
941
|
-
//#region src/define/
|
|
1006
|
+
//#region src/define/console/space.ts
|
|
1007
|
+
function space(name, options) {
|
|
1008
|
+
const { home } = options;
|
|
1009
|
+
return {
|
|
1010
|
+
[KIND]: "space",
|
|
1011
|
+
origin: captureOrigin(),
|
|
1012
|
+
name,
|
|
1013
|
+
options,
|
|
1014
|
+
home: home === void 0 ? null : kindOf(home) === "page" ? home : page(name, {
|
|
1015
|
+
label: options.label,
|
|
1016
|
+
icon: options.icon,
|
|
1017
|
+
render: home
|
|
1018
|
+
})
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
//#endregion
|
|
1022
|
+
//#region src/define/controls/status.ts
|
|
942
1023
|
function status(options) {
|
|
943
1024
|
return {
|
|
944
1025
|
[KIND]: "status",
|
|
@@ -947,4 +1028,17 @@ function status(options) {
|
|
|
947
1028
|
};
|
|
948
1029
|
}
|
|
949
1030
|
//#endregion
|
|
950
|
-
|
|
1031
|
+
//#region src/define/inbox/notify.ts
|
|
1032
|
+
function slack(channel) {
|
|
1033
|
+
return { channel: channel.replace(/^#/, "") };
|
|
1034
|
+
}
|
|
1035
|
+
function notify(name, options) {
|
|
1036
|
+
return {
|
|
1037
|
+
[KIND]: "notify",
|
|
1038
|
+
origin: captureOrigin(),
|
|
1039
|
+
name,
|
|
1040
|
+
options
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
//#endregion
|
|
1044
|
+
export { PultError, ValidationError, action, b, choice, createPult, defineConfig, flag, home, inbox, notify, noul, page, resource, role, run, score, setState, slack, space, status, tag, triage, view };
|
package/package.json
CHANGED
|
@@ -1,18 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lantharos/pult",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The other side of your app",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"back office",
|
|
8
|
+
"admin panel",
|
|
9
|
+
"internal tools",
|
|
10
|
+
"console",
|
|
11
|
+
"feature flags",
|
|
12
|
+
"status page"
|
|
13
|
+
],
|
|
6
14
|
"homepage": "https://pult.sh",
|
|
15
|
+
"bugs": "https://github.com/Lantharos/Pult/issues",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/Lantharos/Pult.git",
|
|
19
|
+
"directory": "packages/pult"
|
|
20
|
+
},
|
|
7
21
|
"type": "module",
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22.17.0"
|
|
25
|
+
},
|
|
8
26
|
"exports": {
|
|
9
27
|
".": {
|
|
10
28
|
"types": "./index.d.mts",
|
|
11
29
|
"default": "./index.mjs"
|
|
12
|
-
}
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
13
32
|
},
|
|
14
33
|
"bin": {
|
|
15
|
-
"pult": "
|
|
34
|
+
"pult": "cli.mjs"
|
|
16
35
|
},
|
|
17
36
|
"publishConfig": {
|
|
18
37
|
"access": "public"
|