@samva/cli 0.20.0 → 0.22.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/AGENTS.md +11 -3
- package/dist/bin.mjs +775 -234
- package/package.json +8 -8
package/dist/bin.mjs
CHANGED
|
@@ -14278,7 +14278,7 @@ var layer12 = /* @__PURE__ */ layer.pipe(/* @__PURE__ */ provideMerge(/* @__PURE
|
|
|
14278
14278
|
// package.json
|
|
14279
14279
|
var package_default = {
|
|
14280
14280
|
name: "@samva/cli",
|
|
14281
|
-
version: "0.
|
|
14281
|
+
version: "0.22.0",
|
|
14282
14282
|
description: "Samva CLI \u2014 email and platform operations from your terminal",
|
|
14283
14283
|
keywords: [
|
|
14284
14284
|
"cli",
|
|
@@ -14321,7 +14321,7 @@ var package_default = {
|
|
|
14321
14321
|
"build:release-artifacts": "bun run scripts/build-release-artifacts.ts",
|
|
14322
14322
|
test: "vitest run --root ../.. --project cli",
|
|
14323
14323
|
"test:package": "vitest run --root ../.. --project cli packages/cli/tests/package-install.e2e.test.ts",
|
|
14324
|
-
typecheck: "tsc --noEmit && tsc --noEmit -p tests/consumer/tsconfig.json"
|
|
14324
|
+
typecheck: "tsc --noEmit && tsc --noEmit -p tests/consumer/tsconfig.json && tsc --noEmit -p tests/consumer/tsconfig.default.json"
|
|
14325
14325
|
},
|
|
14326
14326
|
devDependencies: {
|
|
14327
14327
|
"@effect/platform-bun": "catalog:effect",
|
|
@@ -14334,16 +14334,16 @@ var package_default = {
|
|
|
14334
14334
|
"@types/node": "catalog:",
|
|
14335
14335
|
"better-auth": "catalog:",
|
|
14336
14336
|
effect: "catalog:effect",
|
|
14337
|
-
samva: "workspace:0.
|
|
14337
|
+
samva: "workspace:0.23.0",
|
|
14338
14338
|
typescript: "catalog:",
|
|
14339
14339
|
vite: "~8.3.0",
|
|
14340
14340
|
vitest: "catalog:"
|
|
14341
14341
|
},
|
|
14342
14342
|
optionalDependencies: {
|
|
14343
|
-
"@samva/cli-darwin-arm64": "workspace:0.
|
|
14344
|
-
"@samva/cli-darwin-x64": "workspace:0.
|
|
14345
|
-
"@samva/cli-linux-arm64": "workspace:0.
|
|
14346
|
-
"@samva/cli-linux-x64": "workspace:0.
|
|
14343
|
+
"@samva/cli-darwin-arm64": "workspace:0.22.0",
|
|
14344
|
+
"@samva/cli-darwin-x64": "workspace:0.22.0",
|
|
14345
|
+
"@samva/cli-linux-arm64": "workspace:0.22.0",
|
|
14346
|
+
"@samva/cli-linux-x64": "workspace:0.22.0"
|
|
14347
14347
|
},
|
|
14348
14348
|
engines: {
|
|
14349
14349
|
node: ">=18"
|
|
@@ -25566,7 +25566,7 @@ var __exportAll = (all, no_symbols) => {
|
|
|
25566
25566
|
};
|
|
25567
25567
|
|
|
25568
25568
|
// ../sdk/dist/package.js
|
|
25569
|
-
var version = "0.
|
|
25569
|
+
var version = "0.23.0";
|
|
25570
25570
|
|
|
25571
25571
|
// ../sdk/dist/client-attribution.js
|
|
25572
25572
|
var SDK_VERSION = version;
|
|
@@ -25909,7 +25909,7 @@ var commandTree = {
|
|
|
25909
25909
|
update: {},
|
|
25910
25910
|
remove: {}
|
|
25911
25911
|
},
|
|
25912
|
-
brands: { list: {}, get: {}, pull: {}, push: {} },
|
|
25912
|
+
brands: { list: {}, get: {}, pull: {}, push: {}, default: {}, remove: {} },
|
|
25913
25913
|
mailboxes: {
|
|
25914
25914
|
events: {},
|
|
25915
25915
|
list: {},
|
|
@@ -54599,6 +54599,8 @@ var make41 = /* @__PURE__ */ forGroup(BrandsGroup);
|
|
|
54599
54599
|
var list3 = /* @__PURE__ */ make41("brandsList");
|
|
54600
54600
|
var get9 = /* @__PURE__ */ make41("brandsGet");
|
|
54601
54601
|
var update4 = /* @__PURE__ */ make41("brandsUpdate");
|
|
54602
|
+
var remove4 = /* @__PURE__ */ make41("brandsRemove");
|
|
54603
|
+
var setDefault = /* @__PURE__ */ make41("brandsSetDefault");
|
|
54602
54604
|
|
|
54603
54605
|
// src/commands/brands.ts
|
|
54604
54606
|
var SNAPSHOT_DIR = [".samva", "brands"];
|
|
@@ -54755,11 +54757,62 @@ var push = make29("push", {
|
|
|
54755
54757
|
yield* log(`Updated brand ${updated.slug} from ${file}.`);
|
|
54756
54758
|
yield* logInfo("Published templates keep the brand they were built against until they are republished.");
|
|
54757
54759
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
54758
|
-
var
|
|
54760
|
+
var requiredSlugArgument = String10("slug").pipe(withDescription4("Brand slug"));
|
|
54761
|
+
var dryRunFlag2 = Boolean6("dry-run").pipe(withDescription2("Print the request without sending it"), withDefault5(false));
|
|
54762
|
+
var yesFlag2 = Boolean6("yes").pipe(withDescription2("Confirm without prompting (required outside a terminal)"), withDefault5(false));
|
|
54763
|
+
var makeDefault = make29("default", {
|
|
54764
|
+
slug: requiredSlugArgument,
|
|
54765
|
+
dryRun: dryRunFlag2,
|
|
54766
|
+
json: jsonFlag
|
|
54767
|
+
}).pipe(withDescription3("Make a brand the organization's default: bare samva:brand and domains without a brand resolve to it"), withExamples([
|
|
54768
|
+
{ command: "samva brands default acme" },
|
|
54769
|
+
{ command: "samva brands default acme --dry-run --json" }
|
|
54770
|
+
]), withHandler(({ slug, dryRun, json }) => gen2(function* () {
|
|
54771
|
+
if (dryRun)
|
|
54772
|
+
return yield* json ? printJson({ dryRun: true, action: "brands.default", slug }) : log(`[dry-run] Would make brand ${slug} the default.`);
|
|
54773
|
+
const client = yield* getClientProvider;
|
|
54774
|
+
const brand = yield* setDefault({ slug }).pipe(client.provide, mapError2(apiFailure(`Could not make brand ${slug} the default`)));
|
|
54775
|
+
const result = {
|
|
54776
|
+
action: "brands.default",
|
|
54777
|
+
slug: brand.slug,
|
|
54778
|
+
name: brand.name,
|
|
54779
|
+
isDefault: brand.isDefault
|
|
54780
|
+
};
|
|
54781
|
+
if (json)
|
|
54782
|
+
return yield* printJson(result);
|
|
54783
|
+
yield* log(`Brand ${brand.slug} (${brand.name}) is now the default.`);
|
|
54784
|
+
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
54785
|
+
var remove5 = make29("remove", {
|
|
54786
|
+
slug: requiredSlugArgument,
|
|
54787
|
+
dryRun: dryRunFlag2,
|
|
54788
|
+
yes: yesFlag2,
|
|
54789
|
+
json: jsonFlag
|
|
54790
|
+
}).pipe(withDescription3("Permanently delete a brand. The default brand cannot be deleted; make another brand the default first. Domains that used it fall back to the default."), withExamples([
|
|
54791
|
+
{ command: "samva brands remove promo --dry-run" },
|
|
54792
|
+
{ command: "samva brands remove promo --yes" }
|
|
54793
|
+
]), withHandler(({ slug, dryRun, yes, json }) => gen2(function* () {
|
|
54794
|
+
if (dryRun)
|
|
54795
|
+
return yield* json ? printJson({ dryRun: true, action: "brands.remove", slug }) : log(`[dry-run] Would permanently remove brand ${slug}.`);
|
|
54796
|
+
yield* confirmDestructive({
|
|
54797
|
+
yes,
|
|
54798
|
+
json,
|
|
54799
|
+
message: `Permanently remove brand ${slug}?`,
|
|
54800
|
+
nonInteractiveMessage: "Permanent brand deletion requires --yes in non-interactive mode. Preview with --dry-run."
|
|
54801
|
+
});
|
|
54802
|
+
const client = yield* getClientProvider;
|
|
54803
|
+
yield* remove4({ slug }).pipe(client.provide, mapError2(apiFailure(`Could not remove brand ${slug}`)));
|
|
54804
|
+
const result = { action: "brands.remove", slug, removed: true };
|
|
54805
|
+
if (json)
|
|
54806
|
+
return yield* printJson(result);
|
|
54807
|
+
yield* log(`Removed brand ${slug}.`);
|
|
54808
|
+
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
54809
|
+
var brandsCommand = make29("brands").pipe(withDescription3("List, snapshot, update, and delete the organization's brands (what samva:brand resolves to)"), withExamples([
|
|
54759
54810
|
{ command: "samva brands list" },
|
|
54760
54811
|
{ command: "samva brands pull", description: "Snapshot the default brand for offline builds" },
|
|
54761
|
-
{ command: "samva brands push brand.css --brand acme" }
|
|
54762
|
-
|
|
54812
|
+
{ command: "samva brands push brand.css --brand acme" },
|
|
54813
|
+
{ command: "samva brands default acme", description: "Make acme the default brand" },
|
|
54814
|
+
{ command: "samva brands remove promo --yes" }
|
|
54815
|
+
]), withSubcommands([list4, get10, pull, push, makeDefault, remove5]));
|
|
54763
54816
|
|
|
54764
54817
|
// ../sdk/dist/effect/generated/campaigns.js
|
|
54765
54818
|
var CampaignId2 = /* @__PURE__ */ String4.check(isPattern2(/* @__PURE__ */ new RegExp("^camp_[0-9a-hjkmnp-tv-z]{16,24}$", "u")).annotate({
|
|
@@ -55387,7 +55440,7 @@ var excludeTagsFlag = String9("exclude-tags").pipe(withDescription2("Contact tag
|
|
|
55387
55440
|
var contactIdsFlag = String9("contact-ids").pipe(withDescription2("Explicit contact ids to target (comma-separated or repeated)"), atLeast2(0));
|
|
55388
55441
|
var unsubscribeGroupIdFlag = String9("unsubscribe-group-id").pipe(withDescription2("Unsubscribe group id applied to every send; overrides the organization's default group"), optional4);
|
|
55389
55442
|
var pageSizeFlag = Int5("page-size").pipe(withDescription2("Recipients dispatched per batch"), optional4);
|
|
55390
|
-
var
|
|
55443
|
+
var dryRunFlag3 = Boolean6("dry-run").pipe(withDescription2("Validate inputs and print the request payload without calling the API"), withDefault5(false));
|
|
55391
55444
|
var trackOpensFlag = Literals3("track-opens", ["on", "off"]).pipe(withDescription2("Override open tracking for campaign sends; recipient opt-out wins"), optional4);
|
|
55392
55445
|
var trackClicksFlag = Literals3("track-clicks", ["on", "off"]).pipe(withDescription2("Override click tracking for campaign sends; recipient opt-out wins"), optional4);
|
|
55393
55446
|
var atFlag = String9("at").pipe(withDescription2("Absolute run start instant as ISO 8601 (defaults to now)"), optional4);
|
|
@@ -55415,7 +55468,7 @@ var create4 = make29("create", {
|
|
|
55415
55468
|
pageSize: pageSizeFlag,
|
|
55416
55469
|
trackOpens: trackOpensFlag,
|
|
55417
55470
|
trackClicks: trackClicksFlag,
|
|
55418
|
-
dryRun:
|
|
55471
|
+
dryRun: dryRunFlag3,
|
|
55419
55472
|
json: jsonFlag
|
|
55420
55473
|
}).pipe(withDescription3("Create an email campaign targeting tags or explicit contacts"), withExamples([
|
|
55421
55474
|
{
|
|
@@ -55794,7 +55847,7 @@ var runCreate = make29("create", {
|
|
|
55794
55847
|
campaignId: String10("campaignId"),
|
|
55795
55848
|
at: atFlag,
|
|
55796
55849
|
idempotencyKey: idempotencyKeyFlag,
|
|
55797
|
-
dryRun:
|
|
55850
|
+
dryRun: dryRunFlag3,
|
|
55798
55851
|
json: jsonFlag
|
|
55799
55852
|
}).pipe(withDescription3("Create a run for a campaign (starts immediately without --at)"), withExamples([
|
|
55800
55853
|
{ command: "samva campaigns runs create camp_abc123", description: "Start now" },
|
|
@@ -55907,7 +55960,7 @@ var runGet = make29("get", {
|
|
|
55907
55960
|
var runPause = make29("pause", {
|
|
55908
55961
|
campaignId: String10("campaignId"),
|
|
55909
55962
|
runId: String10("runId"),
|
|
55910
|
-
dryRun:
|
|
55963
|
+
dryRun: dryRunFlag3,
|
|
55911
55964
|
json: jsonFlag
|
|
55912
55965
|
}).pipe(withDescription3("Pause a running campaign run"), withExamples([{ command: "samva campaigns runs pause camp_abc123 crun_def456" }]), withHandler(({ campaignId, runId, dryRun, json }) => gen2(function* () {
|
|
55913
55966
|
if (dryRun)
|
|
@@ -55923,7 +55976,7 @@ var runPause = make29("pause", {
|
|
|
55923
55976
|
var runResume = make29("resume", {
|
|
55924
55977
|
campaignId: String10("campaignId"),
|
|
55925
55978
|
runId: String10("runId"),
|
|
55926
|
-
dryRun:
|
|
55979
|
+
dryRun: dryRunFlag3,
|
|
55927
55980
|
json: jsonFlag
|
|
55928
55981
|
}).pipe(withDescription3("Resume a paused campaign run"), withExamples([{ command: "samva campaigns runs resume camp_abc123 crun_def456" }]), withHandler(({ campaignId, runId, dryRun, json }) => gen2(function* () {
|
|
55929
55982
|
if (dryRun)
|
|
@@ -61003,7 +61056,7 @@ var rotateDkim = make29("rotate-dkim", {
|
|
|
61003
61056
|
yield* log("The minimum retention date does not authorize deletion. Retirement requires separate approval and verification that at least two actual former-record TTLs have elapsed.");
|
|
61004
61057
|
yield* log(`After DNS publication, advance verification: samva email domains check ${id}`);
|
|
61005
61058
|
})));
|
|
61006
|
-
var
|
|
61059
|
+
var remove6 = make29("remove", {
|
|
61007
61060
|
id: String10("id").pipe(withDescription4("Domain id to permanently remove")),
|
|
61008
61061
|
dryRun: Boolean6("dry-run").pipe(withDescription2("Print the deletion plan without calling the API"), withDefault5(false)),
|
|
61009
61062
|
yes: Boolean6("yes").pipe(withDescription2("Confirm permanent deletion (required for non-interactive use)"), withDefault5(false)),
|
|
@@ -61026,7 +61079,7 @@ var remove4 = make29("remove", {
|
|
|
61026
61079
|
return yield* printJson(data);
|
|
61027
61080
|
yield* log(`Removed domain ${id}.`);
|
|
61028
61081
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
61029
|
-
var
|
|
61082
|
+
var setDefault2 = make29("set-default", {
|
|
61030
61083
|
id: String10("id").pipe(withDescription4("Domain id to make the default")),
|
|
61031
61084
|
dryRun: Boolean6("dry-run").pipe(withDescription2("Print the planned change without calling the API"), withDefault5(false)),
|
|
61032
61085
|
json: jsonFlag
|
|
@@ -61144,7 +61197,7 @@ var customDisable = make29("disable", {
|
|
|
61144
61197
|
var customTracking = make29("custom-tracking").pipe(withDescription3("Manage a domain's custom tracking (custom open/click subdomain)"), withExamples([{ command: "samva email domains custom-tracking enable dom_abc123" }]), withSubcommands([customEnable, customStatus, customRecheck, customDisable]));
|
|
61145
61198
|
var domainsCommand = make29("domains").pipe(withDescription3("Manage email sending domains"), withExamples([
|
|
61146
61199
|
{ command: "samva email domains list", description: "List configured domains" }
|
|
61147
|
-
]), withSubcommands([list9, add2, check2, rotateDkim,
|
|
61200
|
+
]), withSubcommands([list9, add2, check2, rotateDkim, setDefault2, remove6, customTracking]));
|
|
61148
61201
|
|
|
61149
61202
|
// src/commands/email/receiving.ts
|
|
61150
61203
|
var destinationLabel = (destination) => {
|
|
@@ -61683,7 +61736,7 @@ var idempotencyKeyFlag2 = String9("idempotency-key").pipe(withDescription2("Key
|
|
|
61683
61736
|
var trackOpensFlag2 = Literals3("track-opens", ["on", "off"]).pipe(withDescription2("Override open tracking for this send; recipient opt-out still wins"), optional4);
|
|
61684
61737
|
var trackClicksFlag2 = Literals3("track-clicks", ["on", "off"]).pipe(withDescription2("Override click tracking for this send; recipient opt-out still wins"), optional4);
|
|
61685
61738
|
var attachFlag = String9("attach").pipe(withDescription2("File to attach (repeatable); small files travel inline, larger ones upload through media first"), atLeast2(0));
|
|
61686
|
-
var
|
|
61739
|
+
var dryRunFlag4 = Boolean6("dry-run").pipe(withDescription2("Validate inputs and print the request payload without calling the API"), withDefault5(false));
|
|
61687
61740
|
var bodySourceName = (input) => {
|
|
61688
61741
|
if (input.templateRefValue)
|
|
61689
61742
|
return "template";
|
|
@@ -61720,7 +61773,7 @@ var send3 = make29("send", {
|
|
|
61720
61773
|
trackOpens: trackOpensFlag2,
|
|
61721
61774
|
trackClicks: trackClicksFlag2,
|
|
61722
61775
|
attach: attachFlag,
|
|
61723
|
-
dryRun:
|
|
61776
|
+
dryRun: dryRunFlag4,
|
|
61724
61777
|
wait: Boolean6("wait").pipe(withDescription2("Wait for delivered/read or a terminal delivery failure"), withDefault5(false)),
|
|
61725
61778
|
timeout: timeoutFlag,
|
|
61726
61779
|
json: jsonFlag
|
|
@@ -62130,7 +62183,7 @@ var check3 = make29("check", {
|
|
|
62130
62183
|
["Verified at", data.verifiedAt ?? null]
|
|
62131
62184
|
]);
|
|
62132
62185
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
62133
|
-
var
|
|
62186
|
+
var setDefault3 = make29("set-default", {
|
|
62134
62187
|
id: String10("id").pipe(withDescription4("Sender id to make the default")),
|
|
62135
62188
|
dryRun: Boolean6("dry-run").pipe(withDescription2("Print the planned change without calling the API"), withDefault5(false)),
|
|
62136
62189
|
json: jsonFlag
|
|
@@ -62146,7 +62199,7 @@ var setDefault2 = make29("set-default", {
|
|
|
62146
62199
|
return yield* printJson(data);
|
|
62147
62200
|
yield* log(`Sender ${id} is now the default sender.`);
|
|
62148
62201
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
62149
|
-
var
|
|
62202
|
+
var remove7 = make29("remove", {
|
|
62150
62203
|
id: String10("id").pipe(withDescription4("Sender id to permanently remove")),
|
|
62151
62204
|
dryRun: Boolean6("dry-run").pipe(withDescription2("Print the deletion plan without calling the API"), withDefault5(false)),
|
|
62152
62205
|
yes: Boolean6("yes").pipe(withDescription2("Confirm permanent deletion (required for non-interactive use)"), withDefault5(false)),
|
|
@@ -62171,7 +62224,7 @@ var remove5 = make29("remove", {
|
|
|
62171
62224
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
62172
62225
|
var sendersCommand = make29("senders").pipe(withDescription3("Manage sender addresses"), withExamples([
|
|
62173
62226
|
{ command: "samva email senders list", description: "List sender addresses" }
|
|
62174
|
-
]), withSubcommands([list12, add3, check3,
|
|
62227
|
+
]), withSubcommands([list12, add3, check3, setDefault3, remove7]));
|
|
62175
62228
|
|
|
62176
62229
|
// src/commands/email/tracking.ts
|
|
62177
62230
|
var toggle = (name, description) => Literals3(name, ["on", "off"]).pipe(withDescription2(description), optional4);
|
|
@@ -64012,7 +64065,7 @@ __export(exports_mailboxes, {
|
|
|
64012
64065
|
mailboxes_exports: () => mailboxes_exports2,
|
|
64013
64066
|
pause: () => pause,
|
|
64014
64067
|
releaseMessage: () => releaseMessage,
|
|
64015
|
-
remove: () =>
|
|
64068
|
+
remove: () => remove8,
|
|
64016
64069
|
removeEndpoint: () => removeEndpoint,
|
|
64017
64070
|
removeThreadLabels: () => removeThreadLabels,
|
|
64018
64071
|
reply: () => reply,
|
|
@@ -67061,7 +67114,7 @@ var mailboxes_exports2 = /* @__PURE__ */ __exportAll({
|
|
|
67061
67114
|
listThreads: () => listThreads,
|
|
67062
67115
|
pause: () => pause,
|
|
67063
67116
|
releaseMessage: () => releaseMessage,
|
|
67064
|
-
remove: () =>
|
|
67117
|
+
remove: () => remove8,
|
|
67065
67118
|
removeEndpoint: () => removeEndpoint,
|
|
67066
67119
|
removeThreadLabels: () => removeThreadLabels,
|
|
67067
67120
|
reply: () => reply,
|
|
@@ -67085,7 +67138,7 @@ var list16 = /* @__PURE__ */ make50("mailboxesList");
|
|
|
67085
67138
|
var create6 = /* @__PURE__ */ make50("mailboxesCreate");
|
|
67086
67139
|
var get19 = /* @__PURE__ */ make50("mailboxesGet");
|
|
67087
67140
|
var update8 = /* @__PURE__ */ make50("mailboxesUpdate");
|
|
67088
|
-
var
|
|
67141
|
+
var remove8 = /* @__PURE__ */ make50("mailboxesRemove");
|
|
67089
67142
|
var createEndpoint = /* @__PURE__ */ make50("mailboxesCreateEndpoint");
|
|
67090
67143
|
var updateEndpoint = /* @__PURE__ */ make50("mailboxesUpdateEndpoint");
|
|
67091
67144
|
var removeEndpoint = /* @__PURE__ */ make50("mailboxesRemoveEndpoint");
|
|
@@ -68747,7 +68800,7 @@ var list17 = /* @__PURE__ */ make51("journeysList");
|
|
|
68747
68800
|
var create7 = /* @__PURE__ */ make51("journeysCreate");
|
|
68748
68801
|
var get20 = /* @__PURE__ */ make51("journeysGet");
|
|
68749
68802
|
var update9 = /* @__PURE__ */ make51("journeysUpdate");
|
|
68750
|
-
var
|
|
68803
|
+
var remove9 = /* @__PURE__ */ make51("journeysRemove");
|
|
68751
68804
|
var replaceDraft = /* @__PURE__ */ make51("journeysReplaceDraft");
|
|
68752
68805
|
var publish3 = /* @__PURE__ */ make51("journeysPublish");
|
|
68753
68806
|
var pause2 = /* @__PURE__ */ make51("journeysPause");
|
|
@@ -68974,7 +69027,7 @@ var destructive = (name, description, warning, run, failure) => make29(name, {
|
|
|
68974
69027
|
]);
|
|
68975
69028
|
}).pipe(quietWhenJson(json))));
|
|
68976
69029
|
var archive4 = destructive("archive", "Archive a journey and exit its active runs", "Archive and exit every active run of", (id) => archive3({ id }), "Could not archive journey");
|
|
68977
|
-
var
|
|
69030
|
+
var remove10 = destructive("delete", "Delete a never-published or archived journey with its versions and runs", "Permanently delete", (id) => remove9({ id }), "Could not delete journey");
|
|
68978
69031
|
var getVersion3 = make29("version", {
|
|
68979
69032
|
id: idArgument2,
|
|
68980
69033
|
version: Int6("version").pipe(withDescription4("Published version number")),
|
|
@@ -69101,7 +69154,7 @@ var journeysCommand = make29("journeys").pipe(withDescription3("Create, publish,
|
|
|
69101
69154
|
pause3,
|
|
69102
69155
|
resume3,
|
|
69103
69156
|
archive4,
|
|
69104
|
-
|
|
69157
|
+
remove10,
|
|
69105
69158
|
getVersion3,
|
|
69106
69159
|
stats2,
|
|
69107
69160
|
runs2
|
|
@@ -72743,7 +72796,7 @@ var actionDecision = (verb) => make29(verb, {
|
|
|
72743
72796
|
})).pipe(client.provide, mapError2((e) => mailboxApiError(`Could not ${verb} action`, e, { personOnly: verb })));
|
|
72744
72797
|
yield* json ? printJson(result) : printAction(result);
|
|
72745
72798
|
})));
|
|
72746
|
-
var
|
|
72799
|
+
var remove11 = make29("remove", {
|
|
72747
72800
|
id: String10("mailbox-id").pipe(withSchema3(MailboxId)),
|
|
72748
72801
|
dryRun: Boolean6("dry-run").pipe(withDefault5(false)),
|
|
72749
72802
|
yes: Boolean6("yes").pipe(withDefault5(false)),
|
|
@@ -72761,7 +72814,7 @@ var remove9 = make29("remove", {
|
|
|
72761
72814
|
nonInteractiveMessage: "Permanent mailbox deletion requires --yes in non-interactive mode. Preview with --dry-run."
|
|
72762
72815
|
});
|
|
72763
72816
|
const client = yield* getClientProvider;
|
|
72764
|
-
const result = yield*
|
|
72817
|
+
const result = yield* remove8({ id }).pipe(client.provide, mapError2((e) => mailboxApiError("Could not remove mailbox", e)));
|
|
72765
72818
|
if (json)
|
|
72766
72819
|
return yield* printJson(result);
|
|
72767
72820
|
yield* log(`Removed mailbox ${id}. The messages it received stay with the organization.`);
|
|
@@ -73052,7 +73105,7 @@ var mailboxesCommand = make29("mailboxes").pipe(withDescription3("Mailbox readin
|
|
|
73052
73105
|
actionCancel,
|
|
73053
73106
|
actionRetry
|
|
73054
73107
|
])),
|
|
73055
|
-
|
|
73108
|
+
remove11,
|
|
73056
73109
|
threads,
|
|
73057
73110
|
read2,
|
|
73058
73111
|
send7,
|
|
@@ -73283,7 +73336,7 @@ var list20 = /* @__PURE__ */ make52("namespacesList");
|
|
|
73283
73336
|
var create10 = /* @__PURE__ */ make52("namespacesCreate");
|
|
73284
73337
|
var get23 = /* @__PURE__ */ make52("namespacesGet");
|
|
73285
73338
|
var update11 = /* @__PURE__ */ make52("namespacesUpdate");
|
|
73286
|
-
var
|
|
73339
|
+
var remove12 = /* @__PURE__ */ make52("namespacesRemove");
|
|
73287
73340
|
var assignResource = /* @__PURE__ */ make52("namespacesAssignResource");
|
|
73288
73341
|
var removeResource = /* @__PURE__ */ make52("namespacesRemoveResource");
|
|
73289
73342
|
var getUsage2 = /* @__PURE__ */ make52("namespacesGetUsage");
|
|
@@ -73291,7 +73344,7 @@ var getUsage2 = /* @__PURE__ */ make52("namespacesGetUsage");
|
|
|
73291
73344
|
// src/commands/namespaces.ts
|
|
73292
73345
|
var idArgument3 = String10("id").pipe(withDescription4("Namespace id (ns_...)"));
|
|
73293
73346
|
var optionalString2 = (name, description) => String9(name).pipe(withDescription2(description), optional4);
|
|
73294
|
-
var
|
|
73347
|
+
var dryRunFlag5 = Boolean6("dry-run").pipe(withDescription2("Print the planned change without calling the API"), withDefault5(false));
|
|
73295
73348
|
var RESOURCE_FLAGS = ["domain", "sender", "contact", "template"];
|
|
73296
73349
|
var resourceFlags = {
|
|
73297
73350
|
domain: optionalString2("domain", "Domain id (dom_...)"),
|
|
@@ -73381,7 +73434,7 @@ var list21 = make29("list", {
|
|
|
73381
73434
|
var create11 = make29("create", {
|
|
73382
73435
|
name: String10("name").pipe(withDescription4("Namespace name")),
|
|
73383
73436
|
metadata: String9("metadata").pipe(withDescription2("Your own label, key=value (repeatable); Samva stores and never reads it"), atLeast2(0)),
|
|
73384
|
-
dryRun:
|
|
73437
|
+
dryRun: dryRunFlag5,
|
|
73385
73438
|
json: jsonFlag
|
|
73386
73439
|
}).pipe(withDescription3("Create a namespace, a sub-tenant for one of your customers"), withExamples([
|
|
73387
73440
|
{ command: "samva namespaces create Acme --metadata customerId=cus_123" },
|
|
@@ -73420,7 +73473,7 @@ var update12 = make29("update", {
|
|
|
73420
73473
|
name: optionalString2("name", "New name"),
|
|
73421
73474
|
metadata: String9("metadata").pipe(withDescription2("Set a metadata label, key=value (repeatable); other keys are kept"), atLeast2(0)),
|
|
73422
73475
|
unsetMetadata: String9("unset-metadata").pipe(withDescription2("Delete a metadata key (repeatable)"), atLeast2(0)),
|
|
73423
|
-
dryRun:
|
|
73476
|
+
dryRun: dryRunFlag5,
|
|
73424
73477
|
json: jsonFlag
|
|
73425
73478
|
}).pipe(withDescription3("Rename a namespace or change its metadata"), withExamples([
|
|
73426
73479
|
{ command: "samva namespaces update ns_7q2xk9mvt4znw8rh --name Acme --metadata plan=pro" },
|
|
@@ -73467,9 +73520,9 @@ var update12 = make29("update", {
|
|
|
73467
73520
|
["Updated", updated.updatedAt]
|
|
73468
73521
|
]);
|
|
73469
73522
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
73470
|
-
var
|
|
73523
|
+
var remove13 = make29("delete", {
|
|
73471
73524
|
id: idArgument3,
|
|
73472
|
-
dryRun:
|
|
73525
|
+
dryRun: dryRunFlag5,
|
|
73473
73526
|
yes: Boolean6("yes").pipe(withDefault5(false)),
|
|
73474
73527
|
json: jsonFlag
|
|
73475
73528
|
}).pipe(withDescription3("Delete an empty namespace; one that still holds anything is refused with a count of what remains"), withExamples([
|
|
@@ -73485,7 +73538,7 @@ var remove11 = make29("delete", {
|
|
|
73485
73538
|
nonInteractiveMessage: "Namespace deletion requires --yes in non-interactive mode. Preview with --dry-run."
|
|
73486
73539
|
});
|
|
73487
73540
|
const client = yield* getClientProvider;
|
|
73488
|
-
const result = yield*
|
|
73541
|
+
const result = yield* remove12({ id }).pipe(client.provide, mapError2((error) => toCliApiError("Could not delete namespace", error)));
|
|
73489
73542
|
if (json)
|
|
73490
73543
|
return yield* printJson(result);
|
|
73491
73544
|
yield* log(`Deleted namespace ${id}.`);
|
|
@@ -73493,7 +73546,7 @@ var remove11 = make29("delete", {
|
|
|
73493
73546
|
var assign2 = make29("assign", {
|
|
73494
73547
|
id: idArgument3,
|
|
73495
73548
|
...resourceFlags,
|
|
73496
|
-
dryRun:
|
|
73549
|
+
dryRun: dryRunFlag5,
|
|
73497
73550
|
json: jsonFlag
|
|
73498
73551
|
}).pipe(withDescription3("Move a domain, sender, contact, or template into a namespace; pass exactly one resource flag"), withExamples([
|
|
73499
73552
|
{ command: "samva namespaces assign ns_7q2xk9mvt4znw8rh --domain dom_xyz789" },
|
|
@@ -73523,7 +73576,7 @@ var assign2 = make29("assign", {
|
|
|
73523
73576
|
var unassign = make29("unassign", {
|
|
73524
73577
|
id: idArgument3,
|
|
73525
73578
|
...resourceFlags,
|
|
73526
|
-
dryRun:
|
|
73579
|
+
dryRun: dryRunFlag5,
|
|
73527
73580
|
json: jsonFlag
|
|
73528
73581
|
}).pipe(withDescription3("Return a domain, sender, contact, or template to organization level; pass exactly one resource flag"), withExamples([
|
|
73529
73582
|
{ command: "samva namespaces unassign ns_7q2xk9mvt4znw8rh --domain dom_xyz789" }
|
|
@@ -73571,7 +73624,7 @@ var usage3 = make29("usage", {
|
|
|
73571
73624
|
["Total", data.totalMessages]
|
|
73572
73625
|
]);
|
|
73573
73626
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
73574
|
-
var namespacesCommand = make29("namespaces").pipe(withDescription3("Manage namespaces, the sub-tenants of your organization"), withExamples([{ command: "samva namespaces list --json" }]), withSubcommands([list21, create11, get24, update12,
|
|
73627
|
+
var namespacesCommand = make29("namespaces").pipe(withDescription3("Manage namespaces, the sub-tenants of your organization"), withExamples([{ command: "samva namespaces list --json" }]), withSubcommands([list21, create11, get24, update12, remove13, assign2, unassign, usage3]));
|
|
73575
73628
|
|
|
73576
73629
|
// ../sdk/dist/effect/generated/whoami.js
|
|
73577
73630
|
var WhoamiUser = /* @__PURE__ */ Struct({
|
|
@@ -73912,7 +73965,7 @@ var use2 = make29("use", { name: String10("name") }).pipe(withDescription3("Sele
|
|
|
73912
73965
|
yield* writeConfig({ ...config, activeProfile: name });
|
|
73913
73966
|
yield* printResult({ action: "profile.use", name }, `Active profile set to ${name}.`);
|
|
73914
73967
|
})));
|
|
73915
|
-
var
|
|
73968
|
+
var remove14 = make29("delete", {
|
|
73916
73969
|
name: String10("name"),
|
|
73917
73970
|
yes: Boolean6("yes").pipe(withDefault5(false))
|
|
73918
73971
|
}).pipe(withDescription3("Delete a profile and its OS-keyring credential"), withHandler(fnUntraced2(function* ({ name, yes }) {
|
|
@@ -73937,7 +73990,7 @@ var remove12 = make29("delete", {
|
|
|
73937
73990
|
yield* (yield* Service4).clear(name);
|
|
73938
73991
|
yield* printResult({ action: "profile.delete", name }, `Deleted profile ${name}.`);
|
|
73939
73992
|
})));
|
|
73940
|
-
var profileCommand = make29("profile").pipe(withDescription3("Manage user-level credential identity and organization contexts"), withSubcommands([list23, show, create12, use2,
|
|
73993
|
+
var profileCommand = make29("profile").pipe(withDescription3("Manage user-level credential identity and organization contexts"), withSubcommands([list23, show, create12, use2, remove14]));
|
|
73941
73994
|
|
|
73942
73995
|
// ../sdk/dist/effect/generated/scheduled-messages.js
|
|
73943
73996
|
var ScheduledMessageId2 = /* @__PURE__ */ String4.check(isPattern2(/* @__PURE__ */ new RegExp("^sched_[0-9a-hjkmnp-tv-z]{16,24}$", "u")).annotate({
|
|
@@ -74194,7 +74247,7 @@ var atFlag2 = String9("at").pipe(withDescription2("Absolute send instant as an I
|
|
|
74194
74247
|
var timezoneFlag = String9("timezone").pipe(withDescription2("IANA timezone for the schedule, e.g. America/New_York"), optional4);
|
|
74195
74248
|
var idempotencyKeyFlag3 = String9("idempotency-key").pipe(withDescription2("Idempotency key so retries do not schedule duplicates"), optional4);
|
|
74196
74249
|
var referenceIdFlag = String9("reference-id").pipe(withDescription2("Your own reference id to correlate this schedule"), optional4);
|
|
74197
|
-
var
|
|
74250
|
+
var dryRunFlag6 = Boolean6("dry-run").pipe(withDescription2("Validate inputs and print the request payload without calling the API"), withDefault5(false));
|
|
74198
74251
|
var trackOpensFlag3 = Literals3("track-opens", ["on", "off"]).pipe(withDescription2("Override open tracking for this scheduled send; recipient opt-out wins"), optional4);
|
|
74199
74252
|
var trackClicksFlag3 = Literals3("track-clicks", ["on", "off"]).pipe(withDescription2("Override click tracking for this scheduled send; recipient opt-out wins"), optional4);
|
|
74200
74253
|
var statusFlag2 = Literals3("status", SCHEDULED_STATUSES).pipe(withDescription2("Filter by status"), optional4);
|
|
@@ -74219,7 +74272,7 @@ var create14 = make29("create", {
|
|
|
74219
74272
|
referenceId: referenceIdFlag,
|
|
74220
74273
|
trackOpens: trackOpensFlag3,
|
|
74221
74274
|
trackClicks: trackClicksFlag3,
|
|
74222
|
-
dryRun:
|
|
74275
|
+
dryRun: dryRunFlag6,
|
|
74223
74276
|
json: jsonFlag
|
|
74224
74277
|
}).pipe(withDescription3("Schedule an email to send at a future time"), withExamples([
|
|
74225
74278
|
{
|
|
@@ -74598,7 +74651,7 @@ var subscriptionsCommand = make29("subscriptions").pipe(withDescription3("Reques
|
|
|
74598
74651
|
// src/commands/templates.ts
|
|
74599
74652
|
import { constants as constants2 } from "fs";
|
|
74600
74653
|
import { access as access3, stat as stat5 } from "fs/promises";
|
|
74601
|
-
import { dirname as dirname5, resolve as
|
|
74654
|
+
import { basename as basename3, dirname as dirname5, resolve as resolve17 } from "path";
|
|
74602
74655
|
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
74603
74656
|
|
|
74604
74657
|
// ../sdk/dist/effect/generated/templates.js
|
|
@@ -76862,7 +76915,7 @@ var create15 = /* @__PURE__ */ make54("templatesCreate");
|
|
|
76862
76915
|
var createFromWebsite = /* @__PURE__ */ make54("templatesCreateFromWebsite");
|
|
76863
76916
|
var addEntry = /* @__PURE__ */ make54("templatesAddEntry");
|
|
76864
76917
|
var getById = /* @__PURE__ */ make54("templatesGetById");
|
|
76865
|
-
var
|
|
76918
|
+
var remove15 = /* @__PURE__ */ make54("templatesRemove");
|
|
76866
76919
|
var update13 = /* @__PURE__ */ make54("templatesUpdate");
|
|
76867
76920
|
var openWorkspace = /* @__PURE__ */ make54("templatesOpenWorkspace");
|
|
76868
76921
|
var getGitRepository = /* @__PURE__ */ make54("templatesGetGitRepository");
|
|
@@ -76886,6 +76939,146 @@ var offlineFlag = Boolean6("offline").pipe(withDescription2("Use the cached bran
|
|
|
76886
76939
|
|
|
76887
76940
|
// src/commands/templates/toolchain.ts
|
|
76888
76941
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
76942
|
+
// ../../node_modules/.bun/@samva+markup@0.17.3+a19bcd7db259aaf7/node_modules/@samva/markup/package.json
|
|
76943
|
+
var package_default2 = {
|
|
76944
|
+
name: "@samva/markup",
|
|
76945
|
+
version: "0.17.3",
|
|
76946
|
+
description: "Type-safe authoring and compilation primitives for Samva templates",
|
|
76947
|
+
keywords: [
|
|
76948
|
+
"email",
|
|
76949
|
+
"jsx",
|
|
76950
|
+
"samva",
|
|
76951
|
+
"sml",
|
|
76952
|
+
"sms",
|
|
76953
|
+
"templates",
|
|
76954
|
+
"tsx",
|
|
76955
|
+
"whatsapp"
|
|
76956
|
+
],
|
|
76957
|
+
homepage: "https://samva.dev",
|
|
76958
|
+
bugs: {
|
|
76959
|
+
url: "https://github.com/SamvaHQ/SML/issues"
|
|
76960
|
+
},
|
|
76961
|
+
license: "MIT",
|
|
76962
|
+
author: "Arya Labs, Inc.",
|
|
76963
|
+
repository: {
|
|
76964
|
+
type: "git",
|
|
76965
|
+
url: "https://github.com/SamvaHQ/SML.git",
|
|
76966
|
+
directory: "packages/markup"
|
|
76967
|
+
},
|
|
76968
|
+
files: [
|
|
76969
|
+
"dist",
|
|
76970
|
+
"samva-brand.d.ts",
|
|
76971
|
+
"generated",
|
|
76972
|
+
"skills",
|
|
76973
|
+
"package.json",
|
|
76974
|
+
"README.md",
|
|
76975
|
+
"CHANGELOG.md",
|
|
76976
|
+
"AGENTS.md",
|
|
76977
|
+
"LICENSE"
|
|
76978
|
+
],
|
|
76979
|
+
type: "module",
|
|
76980
|
+
sideEffects: false,
|
|
76981
|
+
exports: {
|
|
76982
|
+
".": {
|
|
76983
|
+
types: "./dist/index.d.ts",
|
|
76984
|
+
import: "./dist/index.js"
|
|
76985
|
+
},
|
|
76986
|
+
"./email": {
|
|
76987
|
+
types: "./dist/email.d.ts",
|
|
76988
|
+
import: "./dist/email.js"
|
|
76989
|
+
},
|
|
76990
|
+
"./email/jsx-runtime": {
|
|
76991
|
+
types: "./dist/email/jsx-runtime.d.ts",
|
|
76992
|
+
import: "./dist/email/jsx-runtime.js"
|
|
76993
|
+
},
|
|
76994
|
+
"./email/jsx-dev-runtime": {
|
|
76995
|
+
types: "./dist/email/jsx-dev-runtime.d.ts",
|
|
76996
|
+
import: "./dist/email/jsx-dev-runtime.js"
|
|
76997
|
+
},
|
|
76998
|
+
"./fmt": {
|
|
76999
|
+
types: "./dist/fmt.d.ts",
|
|
77000
|
+
import: "./dist/fmt.js"
|
|
77001
|
+
},
|
|
77002
|
+
"./sms": {
|
|
77003
|
+
types: "./dist/sms.d.ts",
|
|
77004
|
+
import: "./dist/sms.js"
|
|
77005
|
+
},
|
|
77006
|
+
"./whatsapp": {
|
|
77007
|
+
types: "./dist/whatsapp.d.ts",
|
|
77008
|
+
import: "./dist/whatsapp.js"
|
|
77009
|
+
},
|
|
77010
|
+
"./input-schema": {
|
|
77011
|
+
types: "./dist/input-schema.d.ts",
|
|
77012
|
+
import: "./dist/input-schema.js"
|
|
77013
|
+
},
|
|
77014
|
+
"./compiler": {
|
|
77015
|
+
types: "./dist/compiler.d.ts",
|
|
77016
|
+
import: "./dist/compiler.js"
|
|
77017
|
+
},
|
|
77018
|
+
"./compatibility": {
|
|
77019
|
+
types: "./dist/compatibility.d.ts",
|
|
77020
|
+
import: "./dist/compatibility.js"
|
|
77021
|
+
},
|
|
77022
|
+
"./diagnostics": {
|
|
77023
|
+
types: "./dist/diagnostics.d.ts",
|
|
77024
|
+
import: "./dist/diagnostics.js"
|
|
77025
|
+
},
|
|
77026
|
+
"./render": {
|
|
77027
|
+
types: "./dist/render.d.ts",
|
|
77028
|
+
import: "./dist/render.js"
|
|
77029
|
+
},
|
|
77030
|
+
"./edit": {
|
|
77031
|
+
types: "./dist/edit.d.ts",
|
|
77032
|
+
import: "./dist/edit.js"
|
|
77033
|
+
},
|
|
77034
|
+
"./brand": {
|
|
77035
|
+
types: "./dist/brand.d.ts",
|
|
77036
|
+
import: "./dist/brand.js"
|
|
77037
|
+
},
|
|
77038
|
+
"./samva-brand": {
|
|
77039
|
+
types: "./samva-brand.d.ts"
|
|
77040
|
+
},
|
|
77041
|
+
"./contract.json": "./generated/contract.json",
|
|
77042
|
+
"./reference.md": "./generated/reference.md",
|
|
77043
|
+
"./package.json": "./package.json"
|
|
77044
|
+
},
|
|
77045
|
+
publishConfig: {
|
|
77046
|
+
access: "public"
|
|
77047
|
+
},
|
|
77048
|
+
scripts: {
|
|
77049
|
+
build: "tsdown",
|
|
77050
|
+
prepack: "bun run build",
|
|
77051
|
+
"corpus:render": "bun run scripts/render-compatibility-corpus.ts",
|
|
77052
|
+
"codegen:tailwind": "bun run scripts/codegen-tailwind.ts && oxfmt src/email/tailwind-stylesheets.gen.ts",
|
|
77053
|
+
"codegen:contract": "bun run scripts/generate-contract.ts",
|
|
77054
|
+
test: "vitest run",
|
|
77055
|
+
typecheck: "tsc --noEmit && tsc --noEmit -p tests/consumer/tsconfig.json"
|
|
77056
|
+
},
|
|
77057
|
+
dependencies: {
|
|
77058
|
+
"@babel/parser": "^8.0.4",
|
|
77059
|
+
"@cfworker/json-schema": "4.1.1",
|
|
77060
|
+
"@standard-schema/spec": "1.1.0",
|
|
77061
|
+
"better-result": "3.0.1",
|
|
77062
|
+
caniemail: "2.0.2",
|
|
77063
|
+
"css-tree": "3.2.1",
|
|
77064
|
+
tailwindcss: "^4.3.3"
|
|
77065
|
+
},
|
|
77066
|
+
devDependencies: {
|
|
77067
|
+
"@css-inline/css-inline-wasm": "0.15.0",
|
|
77068
|
+
"@effect/vitest": "4.0.0",
|
|
77069
|
+
"@types/css-tree": "3.2.0",
|
|
77070
|
+
"@types/node": "^26.6.2",
|
|
77071
|
+
effect: "4.0.0",
|
|
77072
|
+
tsdown: "^0.22.13",
|
|
77073
|
+
typescript: "^7.0.2",
|
|
77074
|
+
vitest: "^5.0.3",
|
|
77075
|
+
zod: "4.6.5"
|
|
77076
|
+
}
|
|
77077
|
+
};
|
|
77078
|
+
|
|
77079
|
+
// src/lib/authoring-release.ts
|
|
77080
|
+
var minorOf = (version) => version.split(".").slice(0, 2).join(".");
|
|
77081
|
+
var AUTHORING_MINOR = minorOf(package_default2.version);
|
|
76889
77082
|
|
|
76890
77083
|
// src/commands/templates/brand-resolver.ts
|
|
76891
77084
|
var brand_resolver_default = `import { execFile } from "node:child_process";
|
|
@@ -77316,6 +77509,30 @@ export const createBrandResolver = (options: {
|
|
|
77316
77509
|
|
|
77317
77510
|
// src/commands/templates/toolchain.ts
|
|
77318
77511
|
var TOOLCHAIN_INSTALL = "npm install --save-dev @samva/markup @samva/vite vite";
|
|
77512
|
+
var AUTHORING_PACKAGES = ["@samva/markup", "@samva/vite"];
|
|
77513
|
+
var toolchainSkew = (installed, action) => {
|
|
77514
|
+
for (const name of AUTHORING_PACKAGES) {
|
|
77515
|
+
const version = installed[name];
|
|
77516
|
+
if (version === undefined || minorOf(version) === AUTHORING_MINOR)
|
|
77517
|
+
continue;
|
|
77518
|
+
const behind = Number(minorOf(version).split(".")[1]) < Number(AUTHORING_MINOR.split(".")[1]);
|
|
77519
|
+
return behind ? `${action}: this project has ${name} ${version}, but this CLI drives ${AUTHORING_MINOR}.x. Update the project with \`npm install --save-dev @samva/markup@~${AUTHORING_MINOR}.0 @samva/vite@~${AUTHORING_MINOR}.0\`.` : `${action}: this project has ${name} ${version}, which is newer than the ${AUTHORING_MINOR}.x this CLI drives. Update the CLI with \`npm install -g @samva/cli@latest\`.`;
|
|
77520
|
+
}
|
|
77521
|
+
return;
|
|
77522
|
+
};
|
|
77523
|
+
var installedAuthoring = async (root) => Object.fromEntries(await Promise.all(AUTHORING_PACKAGES.map(async (name) => {
|
|
77524
|
+
const manifest = await Promise.resolve().then(async () => await Bun.file(Bun.resolveSync(`${name}/package.json`, root)).json()).catch(() => {
|
|
77525
|
+
return;
|
|
77526
|
+
});
|
|
77527
|
+
return [name, manifest?.version];
|
|
77528
|
+
})));
|
|
77529
|
+
var requireCompatibleToolchain = (action) => tryPromise2({
|
|
77530
|
+
try: () => installedAuthoring(process.cwd()),
|
|
77531
|
+
catch: () => new SamvaCliError({ message: `${action}: could not read the project's installed packages.` })
|
|
77532
|
+
}).pipe(flatMap3((installed) => {
|
|
77533
|
+
const skew = toolchainSkew(installed, action);
|
|
77534
|
+
return skew === undefined ? void_3 : fail6(new SamvaCliError({ message: skew }));
|
|
77535
|
+
}));
|
|
77319
77536
|
var MISSING_MODULE = /Cannot find (?:package|module) '([^']+)'/;
|
|
77320
77537
|
var toolchainFailure = (stderr, action) => {
|
|
77321
77538
|
const missing = MISSING_MODULE.exec(stderr)?.[1];
|
|
@@ -77327,28 +77544,42 @@ var toolchainFailure = (stderr, action) => {
|
|
|
77327
77544
|
}
|
|
77328
77545
|
return `${action}: ${stderr.trim() || "the toolchain process failed."}`;
|
|
77329
77546
|
};
|
|
77547
|
+
var invocationEnv = gen2(function* () {
|
|
77548
|
+
const profile = getOrUndefined(yield* Profile);
|
|
77549
|
+
const org = getOrUndefined(yield* Org);
|
|
77550
|
+
const apiUrl = getOrUndefined(yield* ApiUrl);
|
|
77551
|
+
return {
|
|
77552
|
+
...profile === undefined ? {} : { SAMVA_PROFILE: profile },
|
|
77553
|
+
...org === undefined ? {} : { SAMVA_ORG: org },
|
|
77554
|
+
...apiUrl === undefined ? {} : { SAMVA_API_URL: apiUrl }
|
|
77555
|
+
};
|
|
77556
|
+
});
|
|
77330
77557
|
var NODE_MISSING = "Install Node.js 22+ to run template authoring commands.";
|
|
77331
|
-
var runToolchain = (input) =>
|
|
77332
|
-
|
|
77333
|
-
|
|
77334
|
-
|
|
77335
|
-
|
|
77336
|
-
|
|
77337
|
-
|
|
77338
|
-
|
|
77339
|
-
|
|
77340
|
-
|
|
77341
|
-
|
|
77342
|
-
|
|
77343
|
-
|
|
77344
|
-
|
|
77345
|
-
|
|
77346
|
-
|
|
77347
|
-
|
|
77348
|
-
|
|
77349
|
-
|
|
77350
|
-
|
|
77351
|
-
|
|
77558
|
+
var runToolchain = (input) => gen2(function* () {
|
|
77559
|
+
yield* requireCompatibleToolchain(input.action);
|
|
77560
|
+
const selection = yield* invocationEnv;
|
|
77561
|
+
return yield* tryPromise2({
|
|
77562
|
+
try: async () => {
|
|
77563
|
+
const child = Bun.spawn(["node", "--input-type=module", "--eval", input.script], {
|
|
77564
|
+
cwd: process.cwd(),
|
|
77565
|
+
env: { ...Bun.env, ...selection, SAMVA_TOOLCHAIN_INPUT: JSON.stringify(input.options) },
|
|
77566
|
+
stdout: "pipe",
|
|
77567
|
+
stderr: "pipe"
|
|
77568
|
+
});
|
|
77569
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
77570
|
+
new Response(child.stdout).text(),
|
|
77571
|
+
new Response(child.stderr).text(),
|
|
77572
|
+
child.exited
|
|
77573
|
+
]);
|
|
77574
|
+
if (exitCode !== 0) {
|
|
77575
|
+
return Promise.reject(new SamvaCliError({ message: toolchainFailure(stderr, input.action) }));
|
|
77576
|
+
}
|
|
77577
|
+
return JSON.parse(stdout);
|
|
77578
|
+
},
|
|
77579
|
+
catch: (cause) => cause instanceof SamvaCliError ? cause : new SamvaCliError({
|
|
77580
|
+
message: `${input.action}: ${NODE_MISSING} ${String(cause)}`
|
|
77581
|
+
})
|
|
77582
|
+
});
|
|
77352
77583
|
});
|
|
77353
77584
|
var OPTIONS_PRELUDE = "const options = JSON.parse(process.env.SAMVA_TOOLCHAIN_INPUT);";
|
|
77354
77585
|
var brandResolverPrelude = () => `${new Bun.Transpiler({ loader: "ts" }).transformSync(brand_resolver_default)}
|
|
@@ -77539,8 +77770,24 @@ var buildDir = (dir, assetBase) => runToolchain({
|
|
|
77539
77770
|
${brandResolverPrelude()} process.stdout.write(JSON.stringify(await buildTemplates(options)));`
|
|
77540
77771
|
});
|
|
77541
77772
|
|
|
77542
|
-
// src/commands/templates/
|
|
77773
|
+
// src/commands/templates/local-export.ts
|
|
77543
77774
|
import { resolve as resolve10 } from "path";
|
|
77775
|
+
var exportProject = (input) => runToolchain({
|
|
77776
|
+
action: `Could not export templates${input.dir === undefined ? "" : ` in ${input.dir}`}`,
|
|
77777
|
+
options: {
|
|
77778
|
+
root: process.cwd(),
|
|
77779
|
+
out: resolve10(input.out),
|
|
77780
|
+
...input.dir === undefined ? {} : { dir: resolve10(input.dir) },
|
|
77781
|
+
...input.assetBase === undefined ? {} : { assetBase: input.assetBase },
|
|
77782
|
+
...input.offline === true ? { offline: true } : {}
|
|
77783
|
+
},
|
|
77784
|
+
script: `import { exportProject } from "@samva/vite/project"; ${OPTIONS_PRELUDE}
|
|
77785
|
+
${brandResolverPrelude()}
|
|
77786
|
+
process.stdout.write(JSON.stringify(await exportProject(options)));`
|
|
77787
|
+
});
|
|
77788
|
+
|
|
77789
|
+
// src/commands/templates/project.ts
|
|
77790
|
+
import { resolve as resolve11 } from "path";
|
|
77544
77791
|
var templateId = String10("id").pipe(withDescription4("Template id"));
|
|
77545
77792
|
var projectOrTemplateId = String10("id").pipe(withDescription4("Template project id (tproj_...) or the id of any template in it"));
|
|
77546
77793
|
var runGit = (args, options = {}) => tryPromise2({
|
|
@@ -77627,7 +77874,7 @@ var cloneProject = fn2("Templates.cloneProject")(function* (input) {
|
|
|
77627
77874
|
getById({ id: cloneTemplateId }).pipe(client.provide),
|
|
77628
77875
|
getGitRepository({ id: cloneTemplateId }).pipe(client.provide)
|
|
77629
77876
|
], { concurrency: 2 }).pipe(mapError2((error) => toCliApiError("Could not resolve template project", error)));
|
|
77630
|
-
const root =
|
|
77877
|
+
const root = resolve11(input.dir);
|
|
77631
77878
|
const helper = yield* helperCommand(template.id, "read");
|
|
77632
77879
|
yield* runGit([
|
|
77633
77880
|
"-c",
|
|
@@ -77725,7 +77972,7 @@ var init2 = make29("init", {
|
|
|
77725
77972
|
description: "Create deterministically for CI or a coding agent"
|
|
77726
77973
|
}
|
|
77727
77974
|
]), withHandler(({ name, projectName, slug, dir, starter, idempotencyKey, dryRun, json }) => gen2(function* () {
|
|
77728
|
-
const root =
|
|
77975
|
+
const root = resolve11(getOrElse(dir, () => projectDirectory(name)));
|
|
77729
77976
|
const key = getOrUndefined(idempotencyKey);
|
|
77730
77977
|
const request = {
|
|
77731
77978
|
name,
|
|
@@ -78080,10 +78327,12 @@ ${lines.join(`
|
|
|
78080
78327
|
|
|
78081
78328
|
// src/commands/templates/render-command.ts
|
|
78082
78329
|
import { mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
|
|
78083
|
-
import { dirname as dirname3, resolve as
|
|
78330
|
+
import { dirname as dirname3, resolve as resolve13 } from "path";
|
|
78084
78331
|
|
|
78085
78332
|
// src/commands/templates/local-render.ts
|
|
78086
|
-
import {
|
|
78333
|
+
import { mkdtemp as mkdtemp2, readFile as readFile5, rm as rm2 } from "fs/promises";
|
|
78334
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
78335
|
+
import { join as join4, resolve as resolve12 } from "path";
|
|
78087
78336
|
var renderLocal = (input) => runToolchain({
|
|
78088
78337
|
action: `Could not render ${input.template}`,
|
|
78089
78338
|
options: {
|
|
@@ -78091,7 +78340,7 @@ var renderLocal = (input) => runToolchain({
|
|
|
78091
78340
|
template: input.template,
|
|
78092
78341
|
fixture: input.fixture,
|
|
78093
78342
|
channel: input.channel,
|
|
78094
|
-
...input.dir === undefined ? {} : { dir:
|
|
78343
|
+
...input.dir === undefined ? {} : { dir: resolve12(input.dir) },
|
|
78095
78344
|
...input.locale === undefined ? {} : { locale: input.locale },
|
|
78096
78345
|
...input.timeZone === undefined ? {} : { timeZone: input.timeZone },
|
|
78097
78346
|
...input.assetBase === undefined ? {} : { assetBase: input.assetBase },
|
|
@@ -78100,6 +78349,55 @@ var renderLocal = (input) => runToolchain({
|
|
|
78100
78349
|
script: `import { renderChannel, renderTemplate } from "@samva/vite/render"; ${OPTIONS_PRELUDE}
|
|
78101
78350
|
${brandResolverPrelude()} const { channel, ...rest } = options; const result = channel === "email" ? await renderTemplate(rest) : await renderChannel({ ...rest, channel }); process.stdout.write(JSON.stringify(result));`
|
|
78102
78351
|
});
|
|
78352
|
+
var finding = (code, message) => ({
|
|
78353
|
+
code,
|
|
78354
|
+
severity: "error",
|
|
78355
|
+
message,
|
|
78356
|
+
origins: []
|
|
78357
|
+
});
|
|
78358
|
+
var renderWithProjectAssets = (input) => gen2(function* () {
|
|
78359
|
+
const scratch = yield* acquireRelease2(tryPromise2({
|
|
78360
|
+
try: () => mkdtemp2(join4(tmpdir2(), "samva-snapshot-export-")),
|
|
78361
|
+
catch: (cause) => new SamvaCliError({ message: `Could not create a scratch directory: ${String(cause)}` })
|
|
78362
|
+
}), (path) => promise2(() => rm2(path, { recursive: true, force: true })));
|
|
78363
|
+
const receipt = yield* exportProject({
|
|
78364
|
+
dir: input.dir,
|
|
78365
|
+
out: scratch,
|
|
78366
|
+
assetBase: join4(scratch, "assets"),
|
|
78367
|
+
offline: input.offline
|
|
78368
|
+
});
|
|
78369
|
+
const entry = input.template.replace(/^\.\//, "");
|
|
78370
|
+
const template = receipt.templates.find((candidate) => candidate.id === entry || candidate.entryPath === entry);
|
|
78371
|
+
const others = receipt.templates.filter((candidate) => candidate !== template).map((candidate) => candidate.entryPath);
|
|
78372
|
+
const diagnostics = receipt.diagnostics.filter((diagnostic) => {
|
|
78373
|
+
const file = diagnostic.origins[0]?.fileName ?? "";
|
|
78374
|
+
return !others.some((path) => file === path || file.endsWith(`/${path}`));
|
|
78375
|
+
});
|
|
78376
|
+
if (template === undefined)
|
|
78377
|
+
return {
|
|
78378
|
+
ok: false,
|
|
78379
|
+
diagnostics: [
|
|
78380
|
+
...diagnostics,
|
|
78381
|
+
finding("template-not-found", `No template ${JSON.stringify(input.template)} in the project. Known templates: ${receipt.templates.map((candidate) => candidate.id).join(", ") || "none"}.`)
|
|
78382
|
+
]
|
|
78383
|
+
};
|
|
78384
|
+
if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
|
|
78385
|
+
return { ok: false, diagnostics };
|
|
78386
|
+
const page = template.fixtures.find((candidate) => candidate.fixture === input.fixture)?.html;
|
|
78387
|
+
if (page === undefined)
|
|
78388
|
+
return {
|
|
78389
|
+
ok: false,
|
|
78390
|
+
diagnostics: [
|
|
78391
|
+
...diagnostics,
|
|
78392
|
+
finding("unknown-fixture", `Template ${template.id} has no email fixture ${JSON.stringify(input.fixture)}. Known fixtures: ${template.fixtures.map((candidate) => candidate.fixture).join(", ") || "none"}.`)
|
|
78393
|
+
]
|
|
78394
|
+
};
|
|
78395
|
+
const html = yield* tryPromise2({
|
|
78396
|
+
try: () => readFile5(join4(scratch, page), "utf8"),
|
|
78397
|
+
catch: (cause) => new SamvaCliError({ message: `Could not read the exported page: ${String(cause)}` })
|
|
78398
|
+
});
|
|
78399
|
+
return { ok: true, template: template.id, html, diagnostics };
|
|
78400
|
+
});
|
|
78103
78401
|
|
|
78104
78402
|
// src/commands/templates/render-command.ts
|
|
78105
78403
|
var renderPayload = (result, out) => ({
|
|
@@ -78175,7 +78473,7 @@ var renderCommand = make29("render", {
|
|
|
78175
78473
|
json
|
|
78176
78474
|
}) => gen2(function* () {
|
|
78177
78475
|
const machine = json || format === "json";
|
|
78178
|
-
const outPath = map(out, (value) =>
|
|
78476
|
+
const outPath = map(out, (value) => resolve13(value)).pipe(getOrUndefined);
|
|
78179
78477
|
const result = yield* renderLocal({
|
|
78180
78478
|
template,
|
|
78181
78479
|
fixture,
|
|
@@ -78225,13 +78523,13 @@ var renderCommand = make29("render", {
|
|
|
78225
78523
|
}).pipe(json || format === "json" ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
78226
78524
|
|
|
78227
78525
|
// src/commands/templates/snapshot-command.ts
|
|
78228
|
-
import { resolve as
|
|
78526
|
+
import { resolve as resolve14 } from "path";
|
|
78229
78527
|
|
|
78230
78528
|
// src/commands/templates/snapshot-browser.ts
|
|
78231
78529
|
import { existsSync } from "fs";
|
|
78232
|
-
import { copyFile as copyFile3, mkdir as mkdir4, mkdtemp as
|
|
78233
|
-
import { tmpdir as
|
|
78234
|
-
import { join as
|
|
78530
|
+
import { copyFile as copyFile3, mkdir as mkdir4, mkdtemp as mkdtemp3, readFile as readFile6, rm as rm3, stat as stat4, writeFile as writeFile5 } from "fs/promises";
|
|
78531
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
78532
|
+
import { join as join5 } from "path";
|
|
78235
78533
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
78236
78534
|
var VIEWPORTS = {
|
|
78237
78535
|
desktop: { width: 1280, height: 800 },
|
|
@@ -78242,8 +78540,8 @@ var BROWSER_REMEDY = "Install a browser to screenshot with: add `playwright` to
|
|
|
78242
78540
|
var snapshotFileName = (template, fixture, viewport, scheme) => `${template}-${fixture}-${viewport}-${scheme}.png`;
|
|
78243
78541
|
var takeSnapshots = async (input) => {
|
|
78244
78542
|
await mkdir4(input.outDir, { recursive: true });
|
|
78245
|
-
const scratch = await
|
|
78246
|
-
const htmlPath =
|
|
78543
|
+
const scratch = await mkdtemp3(join5(tmpdir3(), "samva-snapshot-"));
|
|
78544
|
+
const htmlPath = join5(scratch, "page.html");
|
|
78247
78545
|
await writeFile5(htmlPath, input.html);
|
|
78248
78546
|
const requests = input.viewports.flatMap((viewport) => input.schemes.map((scheme) => ({
|
|
78249
78547
|
htmlPath,
|
|
@@ -78251,7 +78549,7 @@ var takeSnapshots = async (input) => {
|
|
|
78251
78549
|
width: VIEWPORTS[viewport].width,
|
|
78252
78550
|
height: VIEWPORTS[viewport].height,
|
|
78253
78551
|
scheme,
|
|
78254
|
-
outFile:
|
|
78552
|
+
outFile: join5(input.outDir, snapshotFileName(input.template, input.fixture, viewport, scheme))
|
|
78255
78553
|
})));
|
|
78256
78554
|
const reasons = [];
|
|
78257
78555
|
try {
|
|
@@ -78272,7 +78570,7 @@ var takeSnapshots = async (input) => {
|
|
|
78272
78570
|
}
|
|
78273
78571
|
return { ok: false, reasons };
|
|
78274
78572
|
} finally {
|
|
78275
|
-
await
|
|
78573
|
+
await rm3(scratch, { recursive: true, force: true });
|
|
78276
78574
|
}
|
|
78277
78575
|
};
|
|
78278
78576
|
var CHROME_PATHS = [
|
|
@@ -78366,10 +78664,10 @@ var chromeLauncher = (binary, run = runProcess) => ({
|
|
|
78366
78664
|
status: "unavailable",
|
|
78367
78665
|
reason: "no Chrome or Chromium found in the usual locations and SAMVA_CHROME is not set"
|
|
78368
78666
|
};
|
|
78369
|
-
const profile = await
|
|
78667
|
+
const profile = await mkdtemp3(join5(tmpdir3(), "samva-chrome-"));
|
|
78370
78668
|
try {
|
|
78371
78669
|
for (const request of requests) {
|
|
78372
|
-
const source = await
|
|
78670
|
+
const source = await readFile6(request.htmlPath, "utf8");
|
|
78373
78671
|
const measured = request.htmlPath.replace(/\.html$/, `.${request.viewport}.${request.scheme}.html`);
|
|
78374
78672
|
await writeFile5(measured, withMeasurement(source));
|
|
78375
78673
|
const measure = await run(binary, chromeMeasureArgs({
|
|
@@ -78380,7 +78678,7 @@ var chromeLauncher = (binary, run = runProcess) => ({
|
|
|
78380
78678
|
url: pathToFileURL4(measured).href
|
|
78381
78679
|
}), { stdoutIncludes: "</html>" });
|
|
78382
78680
|
const height = Math.max(request.height, parseMeasuredHeight(measure.stdout) ?? request.height);
|
|
78383
|
-
const staged =
|
|
78681
|
+
const staged = join5(profile, `shot-${request.viewport}-${request.scheme}.png`);
|
|
78384
78682
|
const shot = await run(binary, chromeScreenshotArgs({
|
|
78385
78683
|
profile,
|
|
78386
78684
|
width: request.width,
|
|
@@ -78399,7 +78697,7 @@ var chromeLauncher = (binary, run = runProcess) => ({
|
|
|
78399
78697
|
}
|
|
78400
78698
|
return { status: "done" };
|
|
78401
78699
|
} finally {
|
|
78402
|
-
await
|
|
78700
|
+
await rm3(profile, { recursive: true, force: true });
|
|
78403
78701
|
}
|
|
78404
78702
|
}
|
|
78405
78703
|
});
|
|
@@ -78491,7 +78789,7 @@ var snapshotCommand = make29("snapshot", {
|
|
|
78491
78789
|
out: Directory2("out").pipe(withDescription2("Directory to write the PNGs into"), withDefault5(".samva/snapshots")),
|
|
78492
78790
|
viewport: String9("viewport").pipe(withDescription2(`Comma-separated viewports: ${Object.entries(VIEWPORTS).map(([name, size]) => `${name} (${size.width}px)`).join(", ")}`), withDefault5("desktop,mobile")),
|
|
78493
78791
|
scheme: String9("scheme").pipe(withDescription2("Comma-separated color schemes: light, dark"), withDefault5("light,dark")),
|
|
78494
|
-
assetBase:
|
|
78792
|
+
assetBase: String9("asset-base").pipe(withDescription2("HTTPS origin the template's imported assets are served from; omit to use the project's own asset files"), optional4),
|
|
78495
78793
|
offline: offlineFlag,
|
|
78496
78794
|
json: jsonFlag
|
|
78497
78795
|
}).pipe(withDescription3("Screenshot one fixture in a headless browser at desktop and mobile widths, light and dark"), withExamples([
|
|
@@ -78503,17 +78801,18 @@ var snapshotCommand = make29("snapshot", {
|
|
|
78503
78801
|
command: "samva templates snapshot welcome --fixture default --viewport mobile --scheme dark --out shots",
|
|
78504
78802
|
description: "One screenshot: mobile, dark"
|
|
78505
78803
|
}
|
|
78506
|
-
]), withHandler(({ template, fixture, dir, out, viewport, scheme, assetBase, offline, json }) => gen2(function* () {
|
|
78804
|
+
]), withHandler(({ template, fixture, dir, out, viewport, scheme, assetBase, offline, json }) => scoped2(gen2(function* () {
|
|
78507
78805
|
const viewports = yield* parseChoices("viewport", viewport, Object.keys(VIEWPORTS));
|
|
78508
78806
|
const schemes = yield* parseChoices("scheme", scheme, SCHEMES);
|
|
78509
|
-
const
|
|
78510
|
-
|
|
78511
|
-
|
|
78512
|
-
|
|
78513
|
-
|
|
78514
|
-
|
|
78515
|
-
|
|
78516
|
-
}
|
|
78807
|
+
const base = getOrUndefined(assetBase);
|
|
78808
|
+
if (base !== undefined && !/^https:\/\//i.test(base)) {
|
|
78809
|
+
return yield* new CliUsageError({
|
|
78810
|
+
code: "invalid_asset_base",
|
|
78811
|
+
message: `--asset-base must be an HTTPS origin; got ${base}. Omit it to screenshot with the project's own asset files.`
|
|
78812
|
+
});
|
|
78813
|
+
}
|
|
78814
|
+
const input = { template, fixture, dir: getOrUndefined(dir) };
|
|
78815
|
+
const rendered = base === undefined ? yield* renderWithProjectAssets({ ...input, channel: "email", offline }) : yield* renderLocal({ ...input, channel: "email", assetBase: base, offline });
|
|
78517
78816
|
if (!rendered.ok || !("html" in rendered)) {
|
|
78518
78817
|
const message = `Could not render ${template} (${fixture}) to screenshot it.`;
|
|
78519
78818
|
const diagnostics = rendered.diagnostics.map((diagnostic) => reportDiagnostic(diagnostic, { file: "." }));
|
|
@@ -78530,7 +78829,7 @@ var snapshotCommand = make29("snapshot", {
|
|
|
78530
78829
|
}
|
|
78531
78830
|
return yield* new SamvaCliError({ message });
|
|
78532
78831
|
}
|
|
78533
|
-
const outDir =
|
|
78832
|
+
const outDir = resolve14(out);
|
|
78534
78833
|
const shots = yield* promise2(() => takeSnapshots({
|
|
78535
78834
|
html: rendered.html,
|
|
78536
78835
|
template: rendered.template,
|
|
@@ -78558,10 +78857,10 @@ var snapshotCommand = make29("snapshot", {
|
|
|
78558
78857
|
return yield* printJson(result);
|
|
78559
78858
|
for (const file of shots.files)
|
|
78560
78859
|
yield* log(file.path);
|
|
78561
|
-
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
78860
|
+
})).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
78562
78861
|
|
|
78563
78862
|
// src/commands/templates/types-command.ts
|
|
78564
|
-
import { dirname as dirname4, resolve as
|
|
78863
|
+
import { dirname as dirname4, resolve as resolve15 } from "path";
|
|
78565
78864
|
|
|
78566
78865
|
// src/commands/templates/schema-types.ts
|
|
78567
78866
|
var RESERVED = new Set([
|
|
@@ -78609,6 +78908,93 @@ var pascalCase = (value, fallback) => {
|
|
|
78609
78908
|
const joined = parts.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("").replace(/^[0-9]+/, "");
|
|
78610
78909
|
return joined.length === 0 || RESERVED.has(joined.toLowerCase()) ? fallback : joined;
|
|
78611
78910
|
};
|
|
78911
|
+
var text2 = (value) => ({ kind: "text", text: value });
|
|
78912
|
+
var NEVER = text2("never");
|
|
78913
|
+
var union2 = (members) => members.length === 1 ? members[0] ?? NEVER : { kind: "union", members: members.flatMap((m) => m.kind === "union" ? m.members : [m]) };
|
|
78914
|
+
var PRINT_WIDTH = 100;
|
|
78915
|
+
var pad2 = (indent) => " ".repeat(indent);
|
|
78916
|
+
var isFlat = (doc) => {
|
|
78917
|
+
switch (doc.kind) {
|
|
78918
|
+
case "text":
|
|
78919
|
+
return true;
|
|
78920
|
+
case "object":
|
|
78921
|
+
return false;
|
|
78922
|
+
case "union":
|
|
78923
|
+
case "intersection":
|
|
78924
|
+
return doc.members.every(isFlat);
|
|
78925
|
+
case "array":
|
|
78926
|
+
return isFlat(doc.element);
|
|
78927
|
+
case "tuple":
|
|
78928
|
+
return doc.members.every(isFlat) && (doc.rest === undefined || isFlat(doc.rest));
|
|
78929
|
+
case "record":
|
|
78930
|
+
return isFlat(doc.value);
|
|
78931
|
+
}
|
|
78932
|
+
};
|
|
78933
|
+
var flat = (doc) => {
|
|
78934
|
+
switch (doc.kind) {
|
|
78935
|
+
case "text":
|
|
78936
|
+
return doc.text;
|
|
78937
|
+
case "object":
|
|
78938
|
+
return `{ ${doc.members.map(({ name, optional, type }) => `readonly ${name}${optional ? "?" : ""}: ${flat(type)}`).join("; ")} }`;
|
|
78939
|
+
case "union":
|
|
78940
|
+
return doc.members.map(flat).join(" | ");
|
|
78941
|
+
case "intersection":
|
|
78942
|
+
return doc.members.map(operand).join(" & ");
|
|
78943
|
+
case "array":
|
|
78944
|
+
return `readonly ${wrapped(doc.element)}[]`;
|
|
78945
|
+
case "tuple":
|
|
78946
|
+
return `readonly [${[...doc.members.map(flat), ...doc.rest === undefined ? [] : [`...${flat(doc.rest)}[]`]].join(", ")}]`;
|
|
78947
|
+
case "record":
|
|
78948
|
+
return `Record<string, ${flat(doc.value)}>`;
|
|
78949
|
+
}
|
|
78950
|
+
};
|
|
78951
|
+
var needsParentheses = (doc) => doc.kind === "union" || doc.kind === "intersection" || doc.kind === "array" || doc.kind === "tuple";
|
|
78952
|
+
var operand = (doc) => doc.kind === "union" ? `(${flat(doc)})` : flat(doc);
|
|
78953
|
+
var wrapped = (doc) => needsParentheses(doc) ? `(${flat(doc)})` : flat(doc);
|
|
78954
|
+
var printType = (doc, indent, column, suffix = 1) => {
|
|
78955
|
+
switch (doc.kind) {
|
|
78956
|
+
case "object":
|
|
78957
|
+
return `{
|
|
78958
|
+
${doc.members.map(({ name, optional, type }) => {
|
|
78959
|
+
const head = `${pad2(indent + 2)}readonly ${name}${optional ? "?" : ""}:`;
|
|
78960
|
+
const body = printType(type, indent + 2, head.length + 1);
|
|
78961
|
+
return `${head}${body.startsWith(`
|
|
78962
|
+
`) ? "" : " "}${body};`;
|
|
78963
|
+
}).join(`
|
|
78964
|
+
`)}
|
|
78965
|
+
${pad2(indent)}}`;
|
|
78966
|
+
case "union": {
|
|
78967
|
+
if (isFlat(doc) && column + flat(doc).length + suffix <= PRINT_WIDTH)
|
|
78968
|
+
return flat(doc);
|
|
78969
|
+
return doc.members.map((member) => `
|
|
78970
|
+
${pad2(indent + 2)}| ${printType(member, indent + 4, indent + 4, 0)}`).join("");
|
|
78971
|
+
}
|
|
78972
|
+
case "intersection":
|
|
78973
|
+
return doc.members.map((member) => {
|
|
78974
|
+
const body = printType(member, indent, column, suffix);
|
|
78975
|
+
if (member.kind !== "union")
|
|
78976
|
+
return body;
|
|
78977
|
+
return body.startsWith(`
|
|
78978
|
+
`) ? `(${body}
|
|
78979
|
+
${pad2(indent)})` : `(${body})`;
|
|
78980
|
+
}).join(" & ");
|
|
78981
|
+
case "array": {
|
|
78982
|
+
const element = doc.element;
|
|
78983
|
+
if (isFlat(doc) && column + flat(doc).length + suffix <= PRINT_WIDTH)
|
|
78984
|
+
return flat(doc);
|
|
78985
|
+
if (element.kind === "object")
|
|
78986
|
+
return `readonly ${printType(element, indent, column + 9, 0)}[]`;
|
|
78987
|
+
if (!needsParentheses(element))
|
|
78988
|
+
return flat(doc);
|
|
78989
|
+
const body = printType(element, indent, column + 10, 0);
|
|
78990
|
+
return body.startsWith(`
|
|
78991
|
+
`) ? `readonly (${body}
|
|
78992
|
+
${pad2(indent)})[]` : `readonly (${body})[]`;
|
|
78993
|
+
}
|
|
78994
|
+
default:
|
|
78995
|
+
return flat(doc);
|
|
78996
|
+
}
|
|
78997
|
+
};
|
|
78612
78998
|
var UNSUPPORTED_KEYWORDS = [
|
|
78613
78999
|
"not",
|
|
78614
79000
|
"if",
|
|
@@ -78625,31 +79011,31 @@ var UNSUPPORTED_KEYWORDS = [
|
|
|
78625
79011
|
];
|
|
78626
79012
|
var literal = (value, pointer, state) => {
|
|
78627
79013
|
if (value === null)
|
|
78628
|
-
return "null";
|
|
79014
|
+
return text2("null");
|
|
78629
79015
|
if (typeof value === "string")
|
|
78630
|
-
return JSON.stringify(value);
|
|
79016
|
+
return text2(JSON.stringify(value));
|
|
78631
79017
|
if (typeof value === "number" || typeof value === "boolean")
|
|
78632
|
-
return String(value);
|
|
79018
|
+
return text2(String(value));
|
|
78633
79019
|
state.problems.push({
|
|
78634
79020
|
pointer,
|
|
78635
79021
|
message: "Only string, number, boolean and null literals become generated types."
|
|
78636
79022
|
});
|
|
78637
|
-
return
|
|
79023
|
+
return NEVER;
|
|
78638
79024
|
};
|
|
78639
79025
|
var scalar = (type, pointer, state) => {
|
|
78640
79026
|
switch (type) {
|
|
78641
79027
|
case "string":
|
|
78642
|
-
return "string";
|
|
79028
|
+
return text2("string");
|
|
78643
79029
|
case "number":
|
|
78644
79030
|
case "integer":
|
|
78645
|
-
return "number";
|
|
79031
|
+
return text2("number");
|
|
78646
79032
|
case "boolean":
|
|
78647
|
-
return "boolean";
|
|
79033
|
+
return text2("boolean");
|
|
78648
79034
|
case "null":
|
|
78649
|
-
return "null";
|
|
79035
|
+
return text2("null");
|
|
78650
79036
|
default:
|
|
78651
79037
|
state.problems.push({ pointer, message: `Unsupported JSON Schema type ${type}.` });
|
|
78652
|
-
return
|
|
79038
|
+
return NEVER;
|
|
78653
79039
|
}
|
|
78654
79040
|
};
|
|
78655
79041
|
var definitionName = (state, key, index, pointer) => {
|
|
@@ -78671,13 +79057,13 @@ var emit = (schema, pointer, root, state) => {
|
|
|
78671
79057
|
pointer,
|
|
78672
79058
|
message: "An unconstrained schema cannot produce a type that checks anything."
|
|
78673
79059
|
});
|
|
78674
|
-
return
|
|
79060
|
+
return NEVER;
|
|
78675
79061
|
}
|
|
78676
79062
|
if (schema === false)
|
|
78677
|
-
return
|
|
79063
|
+
return NEVER;
|
|
78678
79064
|
if (!isObject2(schema)) {
|
|
78679
79065
|
state.problems.push({ pointer, message: "Expected a JSON Schema object." });
|
|
78680
|
-
return
|
|
79066
|
+
return NEVER;
|
|
78681
79067
|
}
|
|
78682
79068
|
for (const keyword of UNSUPPORTED_KEYWORDS) {
|
|
78683
79069
|
if (schema[keyword] !== undefined) {
|
|
@@ -78685,7 +79071,7 @@ var emit = (schema, pointer, root, state) => {
|
|
|
78685
79071
|
pointer,
|
|
78686
79072
|
message: `Generated types do not support the ${keyword} keyword.`
|
|
78687
79073
|
});
|
|
78688
|
-
return
|
|
79074
|
+
return NEVER;
|
|
78689
79075
|
}
|
|
78690
79076
|
}
|
|
78691
79077
|
const reference = schema.$ref;
|
|
@@ -78697,48 +79083,51 @@ var emit = (schema, pointer, root, state) => {
|
|
|
78697
79083
|
pointer,
|
|
78698
79084
|
message: `Only local #/$defs references are generated; found ${reference}.`
|
|
78699
79085
|
});
|
|
78700
|
-
return
|
|
79086
|
+
return NEVER;
|
|
78701
79087
|
}
|
|
78702
79088
|
const name = definitionName(state, key, Object.keys(defs).indexOf(key), pointer);
|
|
78703
79089
|
if (name === undefined)
|
|
78704
|
-
return
|
|
79090
|
+
return NEVER;
|
|
78705
79091
|
if (!state.defs.has(name) && !state.emitting.has(name)) {
|
|
78706
79092
|
state.emitting.add(name);
|
|
78707
79093
|
state.defs.set(name, emit(defs[key], `#/$defs/${key}`, root, state));
|
|
78708
79094
|
}
|
|
78709
|
-
return name;
|
|
79095
|
+
return text2(name);
|
|
78710
79096
|
}
|
|
78711
79097
|
if (schema.const !== undefined)
|
|
78712
79098
|
return literal(schema.const, pointer, state);
|
|
78713
79099
|
if (Array.isArray(schema.enum)) {
|
|
78714
|
-
return schema.enum.length === 0 ?
|
|
79100
|
+
return schema.enum.length === 0 ? NEVER : union2(schema.enum.map((value) => literal(value, pointer, state)));
|
|
78715
79101
|
}
|
|
78716
79102
|
if (Array.isArray(schema.allOf)) {
|
|
78717
|
-
return
|
|
79103
|
+
return {
|
|
79104
|
+
kind: "intersection",
|
|
79105
|
+
members: schema.allOf.map((member, index) => emit(member, `${pointer}/allOf/${index}`, root, state))
|
|
79106
|
+
};
|
|
78718
79107
|
}
|
|
78719
79108
|
for (const key of ["anyOf", "oneOf"]) {
|
|
78720
79109
|
const members = schema[key];
|
|
78721
79110
|
if (!Array.isArray(members))
|
|
78722
79111
|
continue;
|
|
78723
|
-
return members.length === 0 ?
|
|
79112
|
+
return members.length === 0 ? NEVER : union2(members.map((member, index) => emit(member, `${pointer}/${key}/${index}`, root, state)));
|
|
78724
79113
|
}
|
|
78725
79114
|
const type = schema.type;
|
|
78726
79115
|
if (Array.isArray(type)) {
|
|
78727
|
-
return type.map((member) => scalarOrStructured(schema, member, pointer, root, state))
|
|
79116
|
+
return union2(type.map((member) => scalarOrStructured(schema, member, pointer, root, state)));
|
|
78728
79117
|
}
|
|
78729
79118
|
if (typeof type !== "string") {
|
|
78730
79119
|
state.problems.push({
|
|
78731
79120
|
pointer,
|
|
78732
79121
|
message: "A generated type needs an explicit type, enum, const, $ref or composition."
|
|
78733
79122
|
});
|
|
78734
|
-
return
|
|
79123
|
+
return NEVER;
|
|
78735
79124
|
}
|
|
78736
79125
|
return scalarOrStructured(schema, type, pointer, root, state);
|
|
78737
79126
|
};
|
|
78738
79127
|
var scalarOrStructured = (schema, type, pointer, root, state) => {
|
|
78739
79128
|
if (typeof type !== "string") {
|
|
78740
79129
|
state.problems.push({ pointer, message: "Expected a JSON Schema type name." });
|
|
78741
|
-
return
|
|
79130
|
+
return NEVER;
|
|
78742
79131
|
}
|
|
78743
79132
|
if (type === "object") {
|
|
78744
79133
|
const properties = isObject2(schema.properties) ? schema.properties : {};
|
|
@@ -78751,40 +79140,52 @@ var scalarOrStructured = (schema, type, pointer, root, state) => {
|
|
|
78751
79140
|
pointer,
|
|
78752
79141
|
message: "An object with no declared properties cannot produce a type that checks input."
|
|
78753
79142
|
});
|
|
78754
|
-
return
|
|
79143
|
+
return NEVER;
|
|
78755
79144
|
}
|
|
78756
|
-
return additional === false ? "
|
|
79145
|
+
return additional === false ? { kind: "record", value: NEVER } : {
|
|
79146
|
+
kind: "record",
|
|
79147
|
+
value: emit(additional, `${pointer}/additionalProperties`, root, state)
|
|
79148
|
+
};
|
|
78757
79149
|
}
|
|
78758
79150
|
const declared = keys.map((key) => ({
|
|
78759
79151
|
name: SAFE_PROPERTY.test(key) ? key : JSON.stringify(key),
|
|
78760
|
-
optional: required.has(key)
|
|
79152
|
+
optional: !required.has(key),
|
|
78761
79153
|
type: emit(properties[key], `${pointer}/properties/${key}`, root, state)
|
|
78762
79154
|
}));
|
|
78763
|
-
const shape =
|
|
78764
|
-
${declared.map(({ name, optional, type: member }) => ` readonly ${name}${optional}: ${member};`).join(`
|
|
78765
|
-
`)}
|
|
78766
|
-
}`;
|
|
79155
|
+
const shape = { kind: "object", members: declared };
|
|
78767
79156
|
if (additional === undefined || additional === false || additional === true)
|
|
78768
79157
|
return shape;
|
|
78769
79158
|
const extra = emit(additional, `${pointer}/additionalProperties`, root, state);
|
|
78770
|
-
const
|
|
78771
|
-
|
|
79159
|
+
const seen = new Set;
|
|
79160
|
+
const open = [...declared.map((member) => member.type), extra].filter((member) => {
|
|
79161
|
+
const key = flat(member);
|
|
79162
|
+
if (key === "never" || seen.has(key))
|
|
79163
|
+
return false;
|
|
79164
|
+
seen.add(key);
|
|
79165
|
+
return true;
|
|
79166
|
+
});
|
|
79167
|
+
return {
|
|
79168
|
+
kind: "intersection",
|
|
79169
|
+
members: [shape, { kind: "record", value: open.length === 0 ? NEVER : union2(open) }]
|
|
79170
|
+
};
|
|
78772
79171
|
}
|
|
78773
79172
|
if (type === "array") {
|
|
78774
79173
|
if (Array.isArray(schema.prefixItems)) {
|
|
78775
79174
|
const tuple = schema.prefixItems.map((member, index) => emit(member, `${pointer}/prefixItems/${index}`, root, state));
|
|
78776
|
-
|
|
78777
|
-
|
|
79175
|
+
return {
|
|
79176
|
+
kind: "tuple",
|
|
79177
|
+
members: tuple,
|
|
79178
|
+
...schema.items === undefined || schema.items === false ? {} : { rest: emit(schema.items, `${pointer}/items`, root, state) }
|
|
79179
|
+
};
|
|
78778
79180
|
}
|
|
78779
79181
|
if (schema.items === undefined) {
|
|
78780
79182
|
state.problems.push({
|
|
78781
79183
|
pointer,
|
|
78782
79184
|
message: "An array without declared items cannot produce a type that checks input."
|
|
78783
79185
|
});
|
|
78784
|
-
return
|
|
79186
|
+
return NEVER;
|
|
78785
79187
|
}
|
|
78786
|
-
|
|
78787
|
-
return SAFE_PROPERTY.test(member) ? `readonly ${member}[]` : `readonly (${member})[]`;
|
|
79188
|
+
return { kind: "array", element: emit(schema.items, `${pointer}/items`, root, state) };
|
|
78788
79189
|
}
|
|
78789
79190
|
return scalar(type, pointer, state);
|
|
78790
79191
|
};
|
|
@@ -78808,31 +79209,54 @@ var schemaToTypeScript = (schema, prefix) => {
|
|
|
78808
79209
|
var TEMPLATE_TYPES_MANIFEST_PREFIX = "// samva:catalog ";
|
|
78809
79210
|
var ManifestSchema = Struct({
|
|
78810
79211
|
version: Literal2(1),
|
|
78811
|
-
|
|
79212
|
+
by: optionalKey2(Literals(["id", "slug"])),
|
|
79213
|
+
reference: optionalKey2(Literals(["exact", "contract-latest"])),
|
|
78812
79214
|
templates: ArraySchema(Struct({
|
|
78813
79215
|
key: String4,
|
|
78814
79216
|
templateId: String4,
|
|
78815
|
-
reference: String4
|
|
79217
|
+
reference: optionalKey2(String4),
|
|
79218
|
+
inputContractId: optionalKey2(String4)
|
|
78816
79219
|
}))
|
|
78817
79220
|
});
|
|
78818
79221
|
var decodeManifest = decodeUnknownOption2(fromJsonString2(ManifestSchema));
|
|
79222
|
+
var withKeying = (manifest) => ({ ...manifest, by: manifest.by ?? "id" });
|
|
78819
79223
|
var readTemplateTypesManifest = (source) => {
|
|
78820
79224
|
const line = source.split(`
|
|
78821
79225
|
`).find((candidate) => candidate.startsWith(TEMPLATE_TYPES_MANIFEST_PREFIX));
|
|
78822
|
-
return line === undefined ? undefined : getOrUndefined(decodeManifest(line.slice(TEMPLATE_TYPES_MANIFEST_PREFIX.length)));
|
|
79226
|
+
return line === undefined ? undefined : getOrUndefined(map(decodeManifest(line.slice(TEMPLATE_TYPES_MANIFEST_PREFIX.length)), withKeying));
|
|
79227
|
+
};
|
|
79228
|
+
var MODULE_TYPE_NAMES = [
|
|
79229
|
+
"SamvaTemplateInputs",
|
|
79230
|
+
"TemplateContent",
|
|
79231
|
+
"TemplateSlug",
|
|
79232
|
+
"TemplateValue",
|
|
79233
|
+
"TemplateValues"
|
|
79234
|
+
];
|
|
79235
|
+
var memberKey = (value) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value) ? value : JSON.stringify(value);
|
|
79236
|
+
var declaration = (head, type) => {
|
|
79237
|
+
const body = printType(type, 0, head.length + 1);
|
|
79238
|
+
return `${head}${body.startsWith(`
|
|
79239
|
+
`) ? "" : " "}${body};`;
|
|
79240
|
+
};
|
|
79241
|
+
var mapEntry = (key, fields) => {
|
|
79242
|
+
const flat = ` ${key}: { ${fields.map(([name, value]) => `${name}: ${value}`).join(", ")} },`;
|
|
79243
|
+
return flat.length <= PRINT_WIDTH ? flat : [` ${key}: {`, ...fields.map(([name, value]) => ` ${name}: ${value},`), " },"].join(`
|
|
79244
|
+
`);
|
|
78823
79245
|
};
|
|
78824
79246
|
var renderTemplateTypes = (input) => {
|
|
79247
|
+
const bySlug = input.by === "slug";
|
|
79248
|
+
const referenceKind = bySlug ? "contract-latest" : input.reference;
|
|
78825
79249
|
const skipped = [];
|
|
78826
79250
|
const problems = [];
|
|
78827
79251
|
const entries = [...input.entries].sort((left, right) => left.key < right.key ? -1 : left.key > right.key ? 1 : 0);
|
|
78828
79252
|
const generated = [];
|
|
78829
|
-
const
|
|
79253
|
+
const declared = new Set(MODULE_TYPE_NAMES);
|
|
78830
79254
|
for (const [index, entry] of entries.entries()) {
|
|
78831
|
-
const reference =
|
|
79255
|
+
const reference = referenceKind === "exact" ? entry.publicationId : entry.inputContractId;
|
|
78832
79256
|
if (reference === undefined) {
|
|
78833
79257
|
skipped.push({
|
|
78834
79258
|
key: entry.key,
|
|
78835
|
-
reason:
|
|
79259
|
+
reason: referenceKind === "exact" ? "no publication yet; publish the template before generating an exact reference" : bySlug ? "no input contract yet; publish the template before generating types by slug" : "no input contract yet; publish the template before adopting its contract"
|
|
78836
79260
|
});
|
|
78837
79261
|
continue;
|
|
78838
79262
|
}
|
|
@@ -78841,10 +79265,17 @@ var renderTemplateTypes = (input) => {
|
|
|
78841
79265
|
continue;
|
|
78842
79266
|
}
|
|
78843
79267
|
let name = pascalCase(entry.key, `Template${index + 1}`);
|
|
78844
|
-
|
|
79268
|
+
let rendered = schemaToTypeScript(entry.inputSchema, name);
|
|
79269
|
+
const typeNames = () => [
|
|
79270
|
+
`${name}Input`,
|
|
79271
|
+
...rendered.definitions.map((definition) => definition.name)
|
|
79272
|
+
];
|
|
79273
|
+
while (typeNames().some((typeName) => declared.has(typeName))) {
|
|
78845
79274
|
name = `${name}_`;
|
|
78846
|
-
|
|
78847
|
-
|
|
79275
|
+
rendered = schemaToTypeScript(entry.inputSchema, name);
|
|
79276
|
+
}
|
|
79277
|
+
for (const typeName of typeNames())
|
|
79278
|
+
declared.add(typeName);
|
|
78848
79279
|
for (const problem of rendered.problems)
|
|
78849
79280
|
problems.push({ ...problem, key: entry.key });
|
|
78850
79281
|
generated.push({
|
|
@@ -78857,19 +79288,60 @@ var renderTemplateTypes = (input) => {
|
|
|
78857
79288
|
}
|
|
78858
79289
|
const manifest = {
|
|
78859
79290
|
version: 1,
|
|
78860
|
-
|
|
79291
|
+
by: input.by,
|
|
79292
|
+
...bySlug ? {} : { reference: referenceKind },
|
|
78861
79293
|
templates: generated.map(({ entry, reference }) => ({
|
|
78862
79294
|
key: entry.key,
|
|
78863
79295
|
templateId: entry.templateId,
|
|
78864
|
-
reference
|
|
79296
|
+
...bySlug ? { inputContractId: reference } : { reference }
|
|
78865
79297
|
}))
|
|
78866
79298
|
};
|
|
78867
|
-
const referenceField =
|
|
78868
|
-
const referenceNote = input.
|
|
78869
|
-
const definitions = generated.flatMap(({ definitions: members }) => members.map(({ name, type }) => `type ${name}
|
|
78870
|
-
const inputs = generated.map(({ entry, name, type }) => [
|
|
79299
|
+
const referenceField = referenceKind === "exact" ? "publicationId" : "inputContractId";
|
|
79300
|
+
const referenceNote = bySlug ? "Each helper names a template by slug, so a send from this file renders the template's current publication; its input is typed from the input contract current when you generated." : referenceKind === "exact" ? "Each reference pins one exact publication, so a send from this file renders the same message until you regenerate." : "Each reference names an input contract, so a send from this file follows the newest publication that still validates input identically.";
|
|
79301
|
+
const definitions = generated.flatMap(({ definitions: members }) => members.map(({ name, type }) => declaration(`type ${name} =`, type)));
|
|
79302
|
+
const inputs = generated.map(({ entry, name, type }) => [
|
|
79303
|
+
`/** Input for the \`${entry.key}\` template. */`,
|
|
79304
|
+
declaration(`export type ${name}Input =`, type)
|
|
79305
|
+
].join(`
|
|
78871
79306
|
`));
|
|
78872
|
-
const
|
|
79307
|
+
const keying = bySlug ? [
|
|
79308
|
+
"/**",
|
|
79309
|
+
" * Email content for one template, named by slug. TypeScript rejects input the template's",
|
|
79310
|
+
" * input contract would reject; spread the result into `email.send`.",
|
|
79311
|
+
" */",
|
|
79312
|
+
"export const templateContent = <Slug extends TemplateSlug>(",
|
|
79313
|
+
" slug: Slug,",
|
|
79314
|
+
" templateData: SamvaTemplateInputs[Slug],",
|
|
79315
|
+
") => ({ templateSlug: slug, templateData: asTemplateData(templateData) });"
|
|
79316
|
+
] : [
|
|
79317
|
+
`/** ${referenceNote} */`,
|
|
79318
|
+
generated.length === 0 ? "export const samvaTemplates = {} as const;" : `export const samvaTemplates = {
|
|
79319
|
+
${generated.map(({ entry, reference }) => mapEntry(memberKey(entry.key), [
|
|
79320
|
+
["templateId", JSON.stringify(entry.templateId)],
|
|
79321
|
+
[referenceField, JSON.stringify(reference)]
|
|
79322
|
+
])).join(`
|
|
79323
|
+
`)}
|
|
79324
|
+
} as const;`,
|
|
79325
|
+
"",
|
|
79326
|
+
"/** What a send spreads in: the template's reference and its input as JSON. */",
|
|
79327
|
+
"export type TemplateContent = {",
|
|
79328
|
+
" readonly templateId: string;",
|
|
79329
|
+
` readonly ${referenceField}: string;`,
|
|
79330
|
+
" readonly templateData: TemplateValues;",
|
|
79331
|
+
"};",
|
|
79332
|
+
"",
|
|
79333
|
+
"/**",
|
|
79334
|
+
" * Email content for one template. TypeScript rejects input the published",
|
|
79335
|
+
" * schema would reject, and the reference travels with it. Spread it into `email.send`.",
|
|
79336
|
+
" */",
|
|
79337
|
+
"export const templateContent = <Slug extends TemplateSlug>(",
|
|
79338
|
+
" slug: Slug,",
|
|
79339
|
+
" templateData: SamvaTemplateInputs[Slug],",
|
|
79340
|
+
"): TemplateContent => ({",
|
|
79341
|
+
" ...samvaTemplates[slug],",
|
|
79342
|
+
" templateData: asTemplateData(templateData),",
|
|
79343
|
+
"});"
|
|
79344
|
+
];
|
|
78873
79345
|
const source = `${[
|
|
78874
79346
|
"// Generated by `samva templates types`. Do not edit.",
|
|
78875
79347
|
`//`,
|
|
@@ -78886,24 +79358,43 @@ var renderTemplateTypes = (input) => {
|
|
|
78886
79358
|
`), ""],
|
|
78887
79359
|
"/** What each published template accepts, keyed by slug. */",
|
|
78888
79360
|
generated.length === 0 ? "export interface SamvaTemplateInputs {}" : `export interface SamvaTemplateInputs {
|
|
78889
|
-
${generated.map(({ entry, name }) => ` readonly ${
|
|
79361
|
+
${generated.map(({ entry, name }) => ` readonly ${memberKey(entry.key)}: ${name}Input;`).join(`
|
|
78890
79362
|
`)}
|
|
78891
79363
|
}`,
|
|
78892
79364
|
"",
|
|
78893
|
-
|
|
78894
|
-
|
|
78895
|
-
${generated.map(({ entry, reference }) => ` ${key(entry.key)}: { templateId: ${JSON.stringify(entry.templateId)}, ${referenceField}: ${JSON.stringify(reference)} },`).join(`
|
|
78896
|
-
`)}
|
|
78897
|
-
} as const;`,
|
|
79365
|
+
"/** The slug of every template in this file. */",
|
|
79366
|
+
"export type TemplateSlug = keyof SamvaTemplateInputs;",
|
|
78898
79367
|
"",
|
|
78899
|
-
"
|
|
78900
|
-
"
|
|
78901
|
-
"
|
|
78902
|
-
"
|
|
78903
|
-
"
|
|
78904
|
-
"
|
|
78905
|
-
"
|
|
78906
|
-
"
|
|
79368
|
+
"// What the API accepts as template data. A generated input is made of these values, but its",
|
|
79369
|
+
"// readonly lists and optional properties are not always assignable to them, so the helper",
|
|
79370
|
+
"// rebuilds the input as JSON values, leaving out a property that is undefined.",
|
|
79371
|
+
"type TemplateValue =",
|
|
79372
|
+
" | string",
|
|
79373
|
+
" | number",
|
|
79374
|
+
" | boolean",
|
|
79375
|
+
" | null",
|
|
79376
|
+
" | TemplateValue[]",
|
|
79377
|
+
" | { [key: string]: TemplateValue };",
|
|
79378
|
+
"type TemplateValues = { [key: string]: TemplateValue };",
|
|
79379
|
+
"const toTemplateValue = (value: unknown): TemplateValue => {",
|
|
79380
|
+
' if (value === null || typeof value === "string") return value;',
|
|
79381
|
+
' if (typeof value === "number" || typeof value === "boolean") return value;',
|
|
79382
|
+
" if (Array.isArray(value)) return value.map(toTemplateValue);",
|
|
79383
|
+
' if (typeof value !== "object") return null;',
|
|
79384
|
+
" return Object.fromEntries(",
|
|
79385
|
+
" Object.entries(value)",
|
|
79386
|
+
" .filter(([, member]) => member !== undefined)",
|
|
79387
|
+
" .map(([key, member]) => [key, toTemplateValue(member)]),",
|
|
79388
|
+
" );",
|
|
79389
|
+
"};",
|
|
79390
|
+
"const asTemplateData = (input: SamvaTemplateInputs[TemplateSlug]): TemplateValues =>",
|
|
79391
|
+
" Object.fromEntries(",
|
|
79392
|
+
" Object.entries(input)",
|
|
79393
|
+
" .filter(([, member]) => member !== undefined)",
|
|
79394
|
+
" .map(([key, member]) => [key, toTemplateValue(member)]),",
|
|
79395
|
+
" );",
|
|
79396
|
+
"",
|
|
79397
|
+
...keying
|
|
78907
79398
|
].join(`
|
|
78908
79399
|
`)}
|
|
78909
79400
|
`;
|
|
@@ -78920,6 +79411,13 @@ var templateTypesDrift = (existing, generated) => {
|
|
|
78920
79411
|
detail: "The file carries no samva:catalog manifest; it was not written by this command."
|
|
78921
79412
|
}
|
|
78922
79413
|
];
|
|
79414
|
+
if (manifest.by !== generated.manifest.by)
|
|
79415
|
+
return [
|
|
79416
|
+
{
|
|
79417
|
+
kind: "keying",
|
|
79418
|
+
detail: `Generated by ${manifest.by}; asked for ${generated.manifest.by}.`
|
|
79419
|
+
}
|
|
79420
|
+
];
|
|
78923
79421
|
if (manifest.reference !== generated.manifest.reference)
|
|
78924
79422
|
return [
|
|
78925
79423
|
{
|
|
@@ -78936,7 +79434,14 @@ var templateTypesDrift = (existing, generated) => {
|
|
|
78936
79434
|
drift.push({ kind: "added", key, detail: `${key} is published and not in the file.` });
|
|
78937
79435
|
continue;
|
|
78938
79436
|
}
|
|
78939
|
-
if (
|
|
79437
|
+
if (generated.manifest.by === "slug") {
|
|
79438
|
+
if (previous.inputContractId !== entry.inputContractId)
|
|
79439
|
+
drift.push({
|
|
79440
|
+
kind: "contract",
|
|
79441
|
+
key,
|
|
79442
|
+
detail: `${key} was typed from input contract ${previous.inputContractId}; the catalog now has ${entry.inputContractId}.`
|
|
79443
|
+
});
|
|
79444
|
+
} else if (previous.reference !== entry.reference)
|
|
78940
79445
|
drift.push({
|
|
78941
79446
|
kind: "reference",
|
|
78942
79447
|
key,
|
|
@@ -78982,13 +79487,22 @@ var readCatalog = fn2("templates.types.readCatalog")(function* () {
|
|
|
78982
79487
|
...item.inputSchema === null ? {} : { inputSchema: item.inputSchema }
|
|
78983
79488
|
}))), { concurrency: CATALOG_READ_CONCURRENCY });
|
|
78984
79489
|
});
|
|
79490
|
+
var keyingRows = (by, reference) => by === "slug" ? [
|
|
79491
|
+
["By", "slug"],
|
|
79492
|
+
["Publication", "current"],
|
|
79493
|
+
["Drift", "input contract"]
|
|
79494
|
+
] : [
|
|
79495
|
+
["By", "id"],
|
|
79496
|
+
["Reference", reference ?? "exact"]
|
|
79497
|
+
];
|
|
78985
79498
|
var readExisting = (path) => gen2(function* () {
|
|
78986
79499
|
const fs = yield* FileSystem;
|
|
78987
79500
|
return (yield* fs.exists(path)) ? yield* fs.readFileString(path) : undefined;
|
|
78988
79501
|
}).pipe(catch_2(() => succeed6(undefined)));
|
|
78989
79502
|
var typesCommand = make29("types", {
|
|
78990
79503
|
out: String9("out").pipe(withDescription2("TypeScript file to write the generated template inputs into"), withDefault5("samva-templates.ts")),
|
|
78991
|
-
|
|
79504
|
+
by: Literals3("by", ["id", "slug"]).pipe(withDescription2("id keys each send by template id with a reference; slug keys it by template slug and follows the template's current publication"), withDefault5("id")),
|
|
79505
|
+
reference: String9("reference").pipe(withDescription2("With --by id (default exact): exact pins one publication per template; contract-latest follows the newest publication that validates input identically"), optional4),
|
|
78992
79506
|
check: Boolean6("check").pipe(withDescription2("Report drift without writing; exits 1 when the file is out of date"), withDefault5(false)),
|
|
78993
79507
|
json: jsonFlag
|
|
78994
79508
|
}).pipe(withDescription3("Generate typed template inputs from the authenticated catalog"), withExamples([
|
|
@@ -78996,21 +79510,32 @@ var typesCommand = make29("types", {
|
|
|
78996
79510
|
command: "samva templates types --out src/samva-templates.ts",
|
|
78997
79511
|
description: "Pin each template's current publication and type its input"
|
|
78998
79512
|
},
|
|
79513
|
+
{
|
|
79514
|
+
command: "samva templates types --by slug --out src/samva-templates.ts",
|
|
79515
|
+
description: "Type a send that names the template by slug: { templateSlug, templateData }"
|
|
79516
|
+
},
|
|
78999
79517
|
{
|
|
79000
79518
|
command: "samva templates types --check",
|
|
79001
79519
|
description: "Fail CI when the generated file no longer matches the catalog"
|
|
79002
79520
|
}
|
|
79003
|
-
]), withHandler(fnUntraced2(function* ({ out, reference, check, json }) {
|
|
79521
|
+
]), withHandler(fnUntraced2(function* ({ out, by, reference: requested, check, json }) {
|
|
79522
|
+
const reference = getOrElse(requested, () => "exact");
|
|
79004
79523
|
if (reference !== "exact" && reference !== "contract-latest") {
|
|
79005
79524
|
return yield* new SamvaCliError({
|
|
79006
79525
|
message: `Unknown --reference ${reference}. Use exact or contract-latest.`
|
|
79007
79526
|
});
|
|
79008
79527
|
}
|
|
79528
|
+
if (by === "slug" && isSome2(requested)) {
|
|
79529
|
+
return yield* new SamvaCliError({
|
|
79530
|
+
message: "--reference does not apply with --by slug: a send by slug renders the template's current publication, and the types follow its input contract."
|
|
79531
|
+
});
|
|
79532
|
+
}
|
|
79009
79533
|
const context = yield* resolveExecutionContext;
|
|
79010
|
-
const path =
|
|
79534
|
+
const path = resolve15(out);
|
|
79011
79535
|
const entries = yield* readCatalog();
|
|
79012
79536
|
const generated = renderTemplateTypes({
|
|
79013
79537
|
entries,
|
|
79538
|
+
by,
|
|
79014
79539
|
reference,
|
|
79015
79540
|
origin: context.apiUrl
|
|
79016
79541
|
});
|
|
@@ -79023,7 +79548,8 @@ var typesCommand = make29("types", {
|
|
|
79023
79548
|
action: "templates.types",
|
|
79024
79549
|
ok: false,
|
|
79025
79550
|
out: path,
|
|
79026
|
-
|
|
79551
|
+
by,
|
|
79552
|
+
...generated.manifest.reference === undefined ? {} : { reference: generated.manifest.reference },
|
|
79027
79553
|
problems: generated.problems
|
|
79028
79554
|
},
|
|
79029
79555
|
human: [
|
|
@@ -79039,7 +79565,8 @@ var typesCommand = make29("types", {
|
|
|
79039
79565
|
action: "templates.types",
|
|
79040
79566
|
ok: check ? drift.length === 0 : true,
|
|
79041
79567
|
out: path,
|
|
79042
|
-
|
|
79568
|
+
by,
|
|
79569
|
+
...generated.manifest.reference === undefined ? {} : { reference: generated.manifest.reference },
|
|
79043
79570
|
templates: generated.manifest.templates,
|
|
79044
79571
|
skipped: generated.skipped,
|
|
79045
79572
|
drift,
|
|
@@ -79051,7 +79578,7 @@ var typesCommand = make29("types", {
|
|
|
79051
79578
|
return yield* printJson(result);
|
|
79052
79579
|
return yield* printFields([
|
|
79053
79580
|
["File", path],
|
|
79054
|
-
|
|
79581
|
+
...keyingRows(by, generated.manifest.reference),
|
|
79055
79582
|
["Templates", generated.manifest.templates.length],
|
|
79056
79583
|
["Status", "up to date"]
|
|
79057
79584
|
]);
|
|
@@ -79078,7 +79605,7 @@ var typesCommand = make29("types", {
|
|
|
79078
79605
|
return yield* printJson(written);
|
|
79079
79606
|
yield* printFields([
|
|
79080
79607
|
["File", path],
|
|
79081
|
-
|
|
79608
|
+
...keyingRows(by, generated.manifest.reference),
|
|
79082
79609
|
["Templates", generated.manifest.templates.length],
|
|
79083
79610
|
["Skipped", generated.skipped.length]
|
|
79084
79611
|
]);
|
|
@@ -79087,9 +79614,22 @@ var typesCommand = make29("types", {
|
|
|
79087
79614
|
})));
|
|
79088
79615
|
|
|
79089
79616
|
// src/commands/templates/workspace.ts
|
|
79090
|
-
import { basename as basename2, resolve as
|
|
79617
|
+
import { basename as basename2, resolve as resolve16 } from "path";
|
|
79091
79618
|
var templateIdArgument = String10("template-id").pipe(withDescription4("Template whose project workspace to act on"));
|
|
79092
79619
|
var revisionFlag2 = String9("revision").pipe(withDescription2("Workspace revision this call is fenced to; a workspace that moved refuses the call"));
|
|
79620
|
+
var readRevisionFlag = String9("revision").pipe(withDescription2("Workspace revision this call is fenced to; a workspace that moved refuses the call (default: the workspace's current revision)"), optional4);
|
|
79621
|
+
var currentRevision = (id, revision) => isSome2(revision) ? succeed6(revision.value) : gen2(function* () {
|
|
79622
|
+
const client = yield* getClientProvider;
|
|
79623
|
+
const view = yield* openWorkspace({ id }).pipe(client.provide, mapError2((error) => {
|
|
79624
|
+
const failure = toCliApiError("Could not read the template workspace revision", error);
|
|
79625
|
+
return new SamvaCliError({
|
|
79626
|
+
message: `${failure.message} The current revision is read by opening the workspace, which needs templates:create; pass --revision to skip that.`,
|
|
79627
|
+
api: failure.api,
|
|
79628
|
+
details: failure.details
|
|
79629
|
+
});
|
|
79630
|
+
}));
|
|
79631
|
+
return view.workspace.revision;
|
|
79632
|
+
});
|
|
79093
79633
|
var idempotencyKeyFlag4 = String9("idempotency-key").pipe(withDescription2("Key so an identical retry returns the original result rather than repeating it"));
|
|
79094
79634
|
var apiFailure2 = (what) => (error) => toCliApiError(`Could not ${what}`, error);
|
|
79095
79635
|
var emit2 = (value) => printJsonDocument(value);
|
|
@@ -79105,11 +79645,12 @@ var open3 = make29("open", { id: templateIdArgument, json: jsonFlag }).pipe(with
|
|
|
79105
79645
|
})));
|
|
79106
79646
|
var diff = make29("diff", {
|
|
79107
79647
|
id: templateIdArgument,
|
|
79108
|
-
revision:
|
|
79648
|
+
revision: readRevisionFlag,
|
|
79109
79649
|
json: jsonFlag
|
|
79110
79650
|
}).pipe(withDescription3("Show every unsaved change against the workspace Git base"), withHandler(fnUntraced2(function* ({ id, revision, json }) {
|
|
79651
|
+
const expectedRevision = yield* currentRevision(id, revision);
|
|
79111
79652
|
const client = yield* getClientProvider;
|
|
79112
|
-
const result = yield* diffWorkspace({ id, expectedRevision
|
|
79653
|
+
const result = yield* diffWorkspace({ id, expectedRevision }).pipe(client.provide, mapError2(apiFailure2("diff the template workspace")));
|
|
79113
79654
|
yield* emit2(result);
|
|
79114
79655
|
})));
|
|
79115
79656
|
var patch2 = make29("patch", {
|
|
@@ -79140,7 +79681,7 @@ var patch2 = make29("patch", {
|
|
|
79140
79681
|
message: `--set must be <project-path>=<local-file>; got ${entry}.`
|
|
79141
79682
|
});
|
|
79142
79683
|
const path = entry.slice(0, separator);
|
|
79143
|
-
const source =
|
|
79684
|
+
const source = resolve16(entry.slice(separator + 1));
|
|
79144
79685
|
const content = yield* fs.readFileString(source).pipe(mapError2((cause) => new SamvaCliError({ message: `Could not read ${source}: ${String(cause)}` })));
|
|
79145
79686
|
written.push({ path, content });
|
|
79146
79687
|
}
|
|
@@ -79174,7 +79715,7 @@ var addAsset = make29("add-asset", {
|
|
|
79174
79715
|
}
|
|
79175
79716
|
]), withHandler(fnUntraced2(function* ({ id, file, revision, path, replace, idempotencyKey, json }) {
|
|
79176
79717
|
const fs = yield* FileSystem;
|
|
79177
|
-
const source =
|
|
79718
|
+
const source = resolve16(file);
|
|
79178
79719
|
const bytes = yield* fs.readFile(source).pipe(mapError2((cause) => new SamvaCliError({ message: `Could not read ${source}: ${String(cause)}` })));
|
|
79179
79720
|
const client = yield* getClientProvider;
|
|
79180
79721
|
const view = yield* putWorkspaceAsset({
|
|
@@ -79189,28 +79730,30 @@ var addAsset = make29("add-asset", {
|
|
|
79189
79730
|
})));
|
|
79190
79731
|
var check4 = make29("check", {
|
|
79191
79732
|
id: templateIdArgument,
|
|
79192
|
-
revision:
|
|
79733
|
+
revision: readRevisionFlag,
|
|
79193
79734
|
json: jsonFlag
|
|
79194
79735
|
}).pipe(withDescription3("Build the effective workspace tree and report what it declares plus every finding"), withExamples([
|
|
79195
79736
|
{
|
|
79196
|
-
command: "samva templates workspace check tmpl_abc123
|
|
79197
|
-
description: "Read the template id, input schema, fixture names, and located diagnostics without rendering or writing"
|
|
79737
|
+
command: "samva templates workspace check tmpl_abc123",
|
|
79738
|
+
description: "Read the template id, input schema, fixture names, and located diagnostics without rendering or writing; --revision 5 fences the call to a revision you inspected"
|
|
79198
79739
|
}
|
|
79199
79740
|
]), withHandler(fnUntraced2(function* ({ id, revision, json }) {
|
|
79741
|
+
const expectedRevision = yield* currentRevision(id, revision);
|
|
79200
79742
|
const client = yield* getClientProvider;
|
|
79201
|
-
const result = yield* checkWorkspace({ id, expectedRevision
|
|
79743
|
+
const result = yield* checkWorkspace({ id, expectedRevision }).pipe(client.provide, mapError2(apiFailure2("check the template workspace")));
|
|
79202
79744
|
yield* emit2(result);
|
|
79203
79745
|
})));
|
|
79204
79746
|
var fixture = make29("fixture", {
|
|
79205
79747
|
id: templateIdArgument,
|
|
79206
|
-
revision:
|
|
79748
|
+
revision: readRevisionFlag,
|
|
79207
79749
|
name: String9("name").pipe(withDescription2("One of the fixture names `workspace check` reported")),
|
|
79208
79750
|
json: jsonFlag
|
|
79209
79751
|
}).pipe(withDescription3("Render one input the template declares, as the recipient receives it"), withHandler(fnUntraced2(function* ({ id, revision, name, json }) {
|
|
79752
|
+
const expectedRevision = yield* currentRevision(id, revision);
|
|
79210
79753
|
const client = yield* getClientProvider;
|
|
79211
79754
|
const result = yield* renderWorkspaceFixture({
|
|
79212
79755
|
id,
|
|
79213
|
-
expectedRevision
|
|
79756
|
+
expectedRevision,
|
|
79214
79757
|
fixture: name
|
|
79215
79758
|
}).pipe(client.provide, mapError2(apiFailure2("render the template fixture")));
|
|
79216
79759
|
yield* emit2(result);
|
|
@@ -79287,42 +79830,52 @@ var workspaceCommand = make29("workspace").pipe(withDescription3("Author a templ
|
|
|
79287
79830
|
|
|
79288
79831
|
// src/commands/templates.ts
|
|
79289
79832
|
var tsconfigFlag = String9("tsconfig").pipe(withDescription2("TypeScript project used to check authored templates"), withDefault5("tsconfig.json"));
|
|
79290
|
-
var
|
|
79833
|
+
var dryRunFlag7 = Boolean6("dry-run").pipe(withDescription2("Show the request without calling the API"), withDefault5(false));
|
|
79291
79834
|
var templateIdArgument2 = String10("id").pipe(withDescription4("Remote template id"));
|
|
79292
79835
|
var parseObject = (raw, flag) => try_3({
|
|
79293
79836
|
try: () => JSON.parse(raw),
|
|
79294
79837
|
catch: () => new SamvaCliError({ message: `${flag} must be a valid JSON object.` })
|
|
79295
79838
|
}).pipe(filterOrFail2((value) => isObject(value) && !Array.isArray(value), () => new SamvaCliError({ message: `${flag} must be a non-null JSON object.` })));
|
|
79296
79839
|
var decodePayload = (raw, flag, schema) => parseObject(raw, flag).pipe(flatMap3(decodeUnknownEffect2(schema)), mapError2((error) => error instanceof SamvaCliError ? error : new SamvaCliError({ message: `${flag} does not match the API schema: ${String(error)}` })));
|
|
79297
|
-
var createProjectBuildSession = (dir, assetBase) =>
|
|
79298
|
-
|
|
79299
|
-
|
|
79300
|
-
|
|
79301
|
-
|
|
79302
|
-
|
|
79303
|
-
|
|
79304
|
-
|
|
79840
|
+
var createProjectBuildSession = (dir, assetBase) => gen2(function* () {
|
|
79841
|
+
yield* requireCompatibleToolchain(`Could not start template watch${dir === undefined ? "" : ` in ${dir}`}`);
|
|
79842
|
+
const selection = yield* invocationEnv;
|
|
79843
|
+
return yield* tryPromise2({
|
|
79844
|
+
try: async () => {
|
|
79845
|
+
const entry = Bun.resolveSync("@samva/vite/build", process.cwd());
|
|
79846
|
+
const projectBuild = await import(pathToFileURL5(entry).href);
|
|
79847
|
+
const { createBrandResolver, loadBrandEnv } = await loadSamvaBrandResolver(process.cwd());
|
|
79848
|
+
const projectBrand = await import(pathToFileURL5(Bun.resolveSync("@samva/markup/brand", process.cwd())).href);
|
|
79849
|
+
return projectBuild.createTemplateBuildSession({
|
|
79850
|
+
brandResolver: createBrandResolver({
|
|
79851
|
+
root: process.cwd(),
|
|
79852
|
+
env: { ...await loadBrandEnv(process.cwd()), ...selection }
|
|
79853
|
+
}),
|
|
79854
|
+
brandPlugin: projectBrand.samvaBrandPlugin,
|
|
79305
79855
|
root: process.cwd(),
|
|
79306
|
-
|
|
79307
|
-
|
|
79308
|
-
|
|
79309
|
-
|
|
79310
|
-
|
|
79311
|
-
|
|
79312
|
-
})
|
|
79313
|
-
}
|
|
79314
|
-
catch: (cause) => new SamvaCliError({
|
|
79315
|
-
message: toolchainFailure(String(cause), `Could not start template watch${dir === undefined ? "" : ` in ${dir}`}`)
|
|
79316
|
-
})
|
|
79856
|
+
...dir === undefined ? {} : { dir: resolve17(dir) },
|
|
79857
|
+
...assetBase === undefined ? {} : { assetBase }
|
|
79858
|
+
});
|
|
79859
|
+
},
|
|
79860
|
+
catch: (cause) => new SamvaCliError({
|
|
79861
|
+
message: toolchainFailure(String(cause), `Could not start template watch${dir === undefined ? "" : ` in ${dir}`}`)
|
|
79862
|
+
})
|
|
79863
|
+
});
|
|
79317
79864
|
});
|
|
79318
79865
|
var TSC_DIAGNOSTIC_LINE = /^(?:(.*?)(?:\((\d+),(\d+)\))?: )?(?:error )?(TS\d+): (.*)$/;
|
|
79866
|
+
var BRAND_MODULE_NOT_FOUND = /^Cannot find module 'samva:brand(?:\/[^']*)?'/;
|
|
79867
|
+
var ASSET_MODULE_NOT_FOUND = /^Cannot find module '[^']+\.(?:png|jpe?g|gif|webp|woff2)'/;
|
|
79868
|
+
var withTypesHint = (message, tsconfig) => {
|
|
79869
|
+
const types = BRAND_MODULE_NOT_FOUND.test(message) ? "@samva/markup/samva-brand" : ASSET_MODULE_NOT_FOUND.test(message) ? "vite/client" : undefined;
|
|
79870
|
+
return types === undefined ? message : `${message} Add "${types}" to compilerOptions.types in ${basename3(tsconfig)}.`;
|
|
79871
|
+
};
|
|
79319
79872
|
var parseTypeScriptDiagnostics = (output, tsconfig) => output.split(`
|
|
79320
79873
|
`).filter((line) => line.length > 0).map((line) => {
|
|
79321
79874
|
const match = TSC_DIAGNOSTIC_LINE.exec(line);
|
|
79322
79875
|
return match === null ? { file: tsconfig, code: "TSC", message: line } : {
|
|
79323
79876
|
file: match[1] ?? tsconfig,
|
|
79324
79877
|
code: match[4] ?? "TSC",
|
|
79325
|
-
message: match[5] ?? line,
|
|
79878
|
+
message: withTypesHint(match[5] ?? line, tsconfig),
|
|
79326
79879
|
...match[2] === undefined ? {} : { line: Number(match[2]) },
|
|
79327
79880
|
...match[3] === undefined ? {} : { column: Number(match[3]) }
|
|
79328
79881
|
};
|
|
@@ -79330,16 +79883,16 @@ var parseTypeScriptDiagnostics = (output, tsconfig) => output.split(`
|
|
|
79330
79883
|
var typecheckProject = (tsconfig) => tryPromise2({
|
|
79331
79884
|
try: async () => {
|
|
79332
79885
|
const typescriptPackage = Bun.resolveSync("typescript/package.json", process.cwd());
|
|
79333
|
-
const tsc =
|
|
79886
|
+
const tsc = resolve17(dirname5(typescriptPackage), "bin/tsc");
|
|
79334
79887
|
const typescriptManifest = await Bun.file(typescriptPackage).json();
|
|
79335
|
-
const child = Bun.spawn(["node", tsc, "--noEmit", "--pretty", "false", "--project",
|
|
79888
|
+
const child = Bun.spawn(["node", tsc, "--noEmit", "--pretty", "false", "--project", resolve17(tsconfig)], { cwd: process.cwd(), stdout: "pipe", stderr: "pipe" });
|
|
79336
79889
|
const [stdout, stderr, exitCode] = await Promise.all([
|
|
79337
79890
|
new Response(child.stdout).text(),
|
|
79338
79891
|
new Response(child.stderr).text(),
|
|
79339
79892
|
child.exited
|
|
79340
79893
|
]);
|
|
79341
79894
|
const output = `${stdout}${stderr}`.trim();
|
|
79342
|
-
const diagnostics = parseTypeScriptDiagnostics(output,
|
|
79895
|
+
const diagnostics = parseTypeScriptDiagnostics(output, resolve17(tsconfig));
|
|
79343
79896
|
if (exitCode !== 0 && diagnostics.length === 0) {
|
|
79344
79897
|
return Promise.reject(new SamvaCliError({
|
|
79345
79898
|
message: output || `Could not run TypeScript from this project. Install typescript and check ${tsconfig}.`
|
|
@@ -79634,7 +80187,7 @@ var build3 = make29("build", {
|
|
|
79634
80187
|
}
|
|
79635
80188
|
return yield* new SamvaCliError({ message });
|
|
79636
80189
|
}
|
|
79637
|
-
const target =
|
|
80190
|
+
const target = resolve17(out);
|
|
79638
80191
|
const artifact = toTemplateBuildArtifact(built);
|
|
79639
80192
|
yield* writeJsonFile(target, artifact);
|
|
79640
80193
|
const result = {
|
|
@@ -79718,7 +80271,7 @@ var createRemote = make29("create", {
|
|
|
79718
80271
|
data: String9("data").pipe(withDescription2("Complete template JSON payload")),
|
|
79719
80272
|
namespace: namespaceFlag("create"),
|
|
79720
80273
|
shared: Boolean6("shared").pipe(withDescription2("Share the new organization-level project with every namespace; namespace-scoped keys read and send it but cannot change it"), withDefault5(false)),
|
|
79721
|
-
dryRun:
|
|
80274
|
+
dryRun: dryRunFlag7,
|
|
79722
80275
|
json: jsonFlag
|
|
79723
80276
|
}).pipe(withDescription3("Create a remote template from JSON"), withExamples([
|
|
79724
80277
|
{
|
|
@@ -79761,7 +80314,7 @@ var updateRemote = make29("update", {
|
|
|
79761
80314
|
id: templateIdArgument2,
|
|
79762
80315
|
data: String9("data").pipe(withDescription2("JSON object of template fields to update")),
|
|
79763
80316
|
shared: Literals3("shared", ["true", "false"]).pipe(withDescription2("Share the template's organization-level project with every namespace (true) or stop sharing it (false); applies to every entry in the project"), optional4),
|
|
79764
|
-
dryRun:
|
|
80317
|
+
dryRun: dryRunFlag7,
|
|
79765
80318
|
json: jsonFlag
|
|
79766
80319
|
}).pipe(withDescription3("Update a remote template from JSON"), withExamples([
|
|
79767
80320
|
{
|
|
@@ -79791,7 +80344,7 @@ var updateRemote = make29("update", {
|
|
|
79791
80344
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
79792
80345
|
var removeRemote = make29("remove", {
|
|
79793
80346
|
id: templateIdArgument2,
|
|
79794
|
-
dryRun:
|
|
80347
|
+
dryRun: dryRunFlag7,
|
|
79795
80348
|
yes: Boolean6("yes").pipe(withDescription2("Confirm destructive state change"), withDefault5(false)),
|
|
79796
80349
|
json: jsonFlag
|
|
79797
80350
|
}).pipe(withDescription3("Deactivate a remote template; its project file and publications remain"), withExamples([{ command: "samva templates remove tmpl_abc123 --dry-run" }]), withHandler(({ id, dryRun, yes, json }) => gen2(function* () {
|
|
@@ -79804,7 +80357,7 @@ var removeRemote = make29("remove", {
|
|
|
79804
80357
|
nonInteractiveMessage: "remove requires --yes in non-interactive mode. Preview with --dry-run."
|
|
79805
80358
|
});
|
|
79806
80359
|
const client = yield* getClientProvider;
|
|
79807
|
-
const result = yield*
|
|
80360
|
+
const result = yield* remove15({ id }).pipe(client.provide, mapError2((error) => toCliApiError("Could not remove template", error)));
|
|
79808
80361
|
if (json)
|
|
79809
80362
|
return yield* printJson(result);
|
|
79810
80363
|
yield* printFields([
|
|
@@ -79812,18 +80365,6 @@ var removeRemote = make29("remove", {
|
|
|
79812
80365
|
["Removed", result.success]
|
|
79813
80366
|
]);
|
|
79814
80367
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
79815
|
-
var exportProject = (input) => runToolchain({
|
|
79816
|
-
action: `Could not export templates${input.dir === undefined ? "" : ` in ${input.dir}`}`,
|
|
79817
|
-
options: {
|
|
79818
|
-
root: process.cwd(),
|
|
79819
|
-
out: resolve16(input.out),
|
|
79820
|
-
...input.dir === undefined ? {} : { dir: resolve16(input.dir) },
|
|
79821
|
-
...input.assetBase === undefined ? {} : { assetBase: input.assetBase }
|
|
79822
|
-
},
|
|
79823
|
-
script: `import { exportProject } from "@samva/vite/project"; ${OPTIONS_PRELUDE}
|
|
79824
|
-
${brandResolverPrelude()}
|
|
79825
|
-
process.stdout.write(JSON.stringify(await exportProject(options)));`
|
|
79826
|
-
});
|
|
79827
80368
|
var exportCommand = make29("export", {
|
|
79828
80369
|
dir: dirFlag,
|
|
79829
80370
|
out: Directory2("out").pipe(withDescription2("Directory to write rendered fixtures, assets, and the catalog into")),
|
|
@@ -79844,7 +80385,7 @@ var exportCommand = make29("export", {
|
|
|
79844
80385
|
const result = {
|
|
79845
80386
|
action: "templates.export",
|
|
79846
80387
|
ok: errors.length === 0,
|
|
79847
|
-
out:
|
|
80388
|
+
out: resolve17(out),
|
|
79848
80389
|
assetBase: receipt.assets.base,
|
|
79849
80390
|
templates: receipt.templates.map((template) => ({
|
|
79850
80391
|
id: template.id,
|
|
@@ -80486,7 +81027,7 @@ var list27 = /* @__PURE__ */ make55("webhooksList");
|
|
|
80486
81027
|
var create16 = /* @__PURE__ */ make55("webhooksCreate");
|
|
80487
81028
|
var getSecret = /* @__PURE__ */ make55("webhooksGetSecret");
|
|
80488
81029
|
var get28 = /* @__PURE__ */ make55("webhooksGet");
|
|
80489
|
-
var
|
|
81030
|
+
var remove16 = /* @__PURE__ */ make55("webhooksRemove");
|
|
80490
81031
|
var update14 = /* @__PURE__ */ make55("webhooksUpdate");
|
|
80491
81032
|
var test = /* @__PURE__ */ make55("webhooksTest");
|
|
80492
81033
|
var getLogs = /* @__PURE__ */ make55("webhooksGetLogs");
|
|
@@ -80808,7 +81349,7 @@ var update15 = make29("update", {
|
|
|
80808
81349
|
return yield* printJson(result);
|
|
80809
81350
|
yield* printFields(objectRows(result));
|
|
80810
81351
|
}).pipe(json ? provideService2(MinimumLogLevel2, "None") : identity)));
|
|
80811
|
-
var
|
|
81352
|
+
var remove17 = make29("remove", {
|
|
80812
81353
|
id: idArgument4,
|
|
80813
81354
|
dryRun: Boolean6("dry-run").pipe(withDefault5(false)),
|
|
80814
81355
|
yes: Boolean6("yes").pipe(withDefault5(false)),
|
|
@@ -80826,7 +81367,7 @@ var remove15 = make29("remove", {
|
|
|
80826
81367
|
nonInteractiveMessage: "Permanent webhook deletion requires --yes in non-interactive mode. Preview with --dry-run."
|
|
80827
81368
|
});
|
|
80828
81369
|
const client = yield* getClientProvider;
|
|
80829
|
-
const result = yield*
|
|
81370
|
+
const result = yield* remove16({ id }).pipe(client.provide, mapError2((error) => toCliApiError("Could not remove webhook", error)));
|
|
80830
81371
|
if (json)
|
|
80831
81372
|
return yield* printJson(result);
|
|
80832
81373
|
yield* log(`Removed webhook ${id}.`);
|
|
@@ -80842,7 +81383,7 @@ var webhooksCommand = make29("webhooks").pipe(withDescription3("Inspect, test, a
|
|
|
80842
81383
|
stats3,
|
|
80843
81384
|
retry4,
|
|
80844
81385
|
rotate3,
|
|
80845
|
-
|
|
81386
|
+
remove17
|
|
80846
81387
|
]));
|
|
80847
81388
|
|
|
80848
81389
|
// src/lib/root-commands.ts
|