@siteoshq/cli 1.13.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -22
- package/dist/cli.js +789 -2471
- package/dist/cli.js.map +1 -1
- package/package.json +18 -20
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ __export(cookie_verification_exports, {
|
|
|
17
17
|
verificationTarget: () => verificationTarget,
|
|
18
18
|
verifyCookieWebsite: () => verifyCookieWebsite
|
|
19
19
|
});
|
|
20
|
-
import { z as
|
|
20
|
+
import { z as z12 } from "zod";
|
|
21
21
|
function verificationTarget(websiteUrl, candidate) {
|
|
22
22
|
const website = new URL(websiteUrl);
|
|
23
23
|
const target = new URL(candidate ?? websiteUrl, website);
|
|
@@ -362,80 +362,80 @@ var Names, Service, Envelope, State, VerificationInstallation;
|
|
|
362
362
|
var init_cookie_verification = __esm({
|
|
363
363
|
"src/services/cookie-verification.ts"() {
|
|
364
364
|
"use strict";
|
|
365
|
-
Names =
|
|
366
|
-
exact:
|
|
367
|
-
prefixes:
|
|
368
|
-
});
|
|
369
|
-
Service =
|
|
370
|
-
key:
|
|
371
|
-
purposeKey:
|
|
372
|
-
lifecycle:
|
|
373
|
-
scriptOrigins:
|
|
374
|
-
iframeOrigins:
|
|
375
|
-
pixelOrigins:
|
|
365
|
+
Names = z12.object({
|
|
366
|
+
exact: z12.array(z12.string()),
|
|
367
|
+
prefixes: z12.array(z12.string())
|
|
368
|
+
});
|
|
369
|
+
Service = z12.object({
|
|
370
|
+
key: z12.string(),
|
|
371
|
+
purposeKey: z12.string(),
|
|
372
|
+
lifecycle: z12.object({
|
|
373
|
+
scriptOrigins: z12.array(z12.string()),
|
|
374
|
+
iframeOrigins: z12.array(z12.string()),
|
|
375
|
+
pixelOrigins: z12.array(z12.string()),
|
|
376
376
|
firstPartyCookies: Names,
|
|
377
377
|
localStorage: Names
|
|
378
378
|
}).optional()
|
|
379
379
|
});
|
|
380
|
-
Envelope =
|
|
381
|
-
publicKey:
|
|
382
|
-
revision:
|
|
383
|
-
ruleKey:
|
|
384
|
-
profileKey:
|
|
385
|
-
trustedSignals:
|
|
386
|
-
region:
|
|
387
|
-
countryCode:
|
|
388
|
-
subdivisionCode:
|
|
380
|
+
Envelope = z12.object({
|
|
381
|
+
publicKey: z12.string(),
|
|
382
|
+
revision: z12.number(),
|
|
383
|
+
ruleKey: z12.string(),
|
|
384
|
+
profileKey: z12.string(),
|
|
385
|
+
trustedSignals: z12.object({
|
|
386
|
+
region: z12.object({
|
|
387
|
+
countryCode: z12.string().nullable(),
|
|
388
|
+
subdivisionCode: z12.string().nullable()
|
|
389
389
|
}).optional()
|
|
390
390
|
}).optional(),
|
|
391
|
-
config:
|
|
392
|
-
services:
|
|
393
|
-
categories:
|
|
394
|
-
integrations:
|
|
391
|
+
config: z12.object({
|
|
392
|
+
services: z12.array(Service),
|
|
393
|
+
categories: z12.array(z12.object({ key: z12.string(), required: z12.boolean() })),
|
|
394
|
+
integrations: z12.object({ googleConsentMode: z12.string() })
|
|
395
395
|
})
|
|
396
396
|
});
|
|
397
|
-
State =
|
|
398
|
-
runtimeVersion:
|
|
399
|
-
preview:
|
|
400
|
-
resolved:
|
|
401
|
-
publicKey:
|
|
402
|
-
revision:
|
|
403
|
-
ruleKey:
|
|
404
|
-
profileKey:
|
|
397
|
+
State = z12.object({
|
|
398
|
+
runtimeVersion: z12.string(),
|
|
399
|
+
preview: z12.boolean(),
|
|
400
|
+
resolved: z12.object({
|
|
401
|
+
publicKey: z12.string(),
|
|
402
|
+
revision: z12.number(),
|
|
403
|
+
ruleKey: z12.string(),
|
|
404
|
+
profileKey: z12.string()
|
|
405
405
|
}).nullable(),
|
|
406
|
-
consent:
|
|
407
|
-
categories:
|
|
408
|
-
decision:
|
|
409
|
-
globalPrivacyControl:
|
|
410
|
-
privacyChoices:
|
|
411
|
-
saleOrShareOptOut:
|
|
412
|
-
targetedAdvertisingOptOut:
|
|
406
|
+
consent: z12.object({
|
|
407
|
+
categories: z12.array(z12.string()),
|
|
408
|
+
decision: z12.string(),
|
|
409
|
+
globalPrivacyControl: z12.boolean(),
|
|
410
|
+
privacyChoices: z12.object({
|
|
411
|
+
saleOrShareOptOut: z12.boolean(),
|
|
412
|
+
targetedAdvertisingOptOut: z12.boolean()
|
|
413
413
|
})
|
|
414
414
|
}),
|
|
415
|
-
services:
|
|
416
|
-
|
|
417
|
-
key:
|
|
418
|
-
allowed:
|
|
419
|
-
footprintPresent:
|
|
415
|
+
services: z12.array(
|
|
416
|
+
z12.object({
|
|
417
|
+
key: z12.string(),
|
|
418
|
+
allowed: z12.boolean(),
|
|
419
|
+
footprintPresent: z12.boolean()
|
|
420
420
|
})
|
|
421
421
|
)
|
|
422
422
|
});
|
|
423
|
-
VerificationInstallation =
|
|
424
|
-
publicKey:
|
|
425
|
-
currentPublishedRevision:
|
|
426
|
-
delivery:
|
|
427
|
-
runtimeUrl:
|
|
428
|
-
configUrl:
|
|
429
|
-
analyticsUrl:
|
|
430
|
-
receiptsUrl:
|
|
431
|
-
handshakeUrl:
|
|
423
|
+
VerificationInstallation = z12.object({
|
|
424
|
+
publicKey: z12.string(),
|
|
425
|
+
currentPublishedRevision: z12.number().int().positive(),
|
|
426
|
+
delivery: z12.object({
|
|
427
|
+
runtimeUrl: z12.string().url(),
|
|
428
|
+
configUrl: z12.string().url(),
|
|
429
|
+
analyticsUrl: z12.string().url().nullable(),
|
|
430
|
+
receiptsUrl: z12.string().url(),
|
|
431
|
+
handshakeUrl: z12.string().url()
|
|
432
432
|
})
|
|
433
433
|
});
|
|
434
434
|
}
|
|
435
435
|
});
|
|
436
436
|
|
|
437
437
|
// src/health-check.ts
|
|
438
|
-
import
|
|
438
|
+
import path8 from "path";
|
|
439
439
|
|
|
440
440
|
// src/projects/project-context.ts
|
|
441
441
|
import path6 from "path";
|
|
@@ -1033,13 +1033,6 @@ import { realpath } from "fs/promises";
|
|
|
1033
1033
|
import path4 from "path";
|
|
1034
1034
|
import { z as z3 } from "zod";
|
|
1035
1035
|
|
|
1036
|
-
// src/core/ports/project-binding-store.ts
|
|
1037
|
-
var PRODUCT_SERVICES = ["pulse", "forms", "search"];
|
|
1038
|
-
var PROJECT_BINDING_SERVICES = [
|
|
1039
|
-
"project",
|
|
1040
|
-
...PRODUCT_SERVICES
|
|
1041
|
-
];
|
|
1042
|
-
|
|
1043
1036
|
// src/core/adapters/node-json-document-store.ts
|
|
1044
1037
|
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
1045
1038
|
import {
|
|
@@ -1206,7 +1199,7 @@ function isNodeErrorCode2(error, code) {
|
|
|
1206
1199
|
|
|
1207
1200
|
// src/core/adapters/node-project-binding-store.ts
|
|
1208
1201
|
var projectBindingSchema = z3.object({
|
|
1209
|
-
service: z3.
|
|
1202
|
+
service: z3.literal("project"),
|
|
1210
1203
|
apiOrigin: z3.string().url().refine((value) => new URL(value).origin === value),
|
|
1211
1204
|
repositoryRoot: z3.string().refine(path4.isAbsolute),
|
|
1212
1205
|
organizationId: z3.string().trim().min(1).max(255),
|
|
@@ -1331,13 +1324,13 @@ function normalizeApiOrigin(value) {
|
|
|
1331
1324
|
} catch {
|
|
1332
1325
|
throw new ProjectBindingStoreError(
|
|
1333
1326
|
"PROJECT_BINDINGS_INVALID",
|
|
1334
|
-
"The
|
|
1327
|
+
"The Project binding is invalid."
|
|
1335
1328
|
);
|
|
1336
1329
|
}
|
|
1337
1330
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
1338
1331
|
throw new ProjectBindingStoreError(
|
|
1339
1332
|
"PROJECT_BINDINGS_INVALID",
|
|
1340
|
-
"The
|
|
1333
|
+
"The Project binding is invalid."
|
|
1341
1334
|
);
|
|
1342
1335
|
}
|
|
1343
1336
|
return url.origin;
|
|
@@ -1350,26 +1343,26 @@ function mapStoreError(error) {
|
|
|
1350
1343
|
if (error instanceof z3.ZodError) {
|
|
1351
1344
|
return new ProjectBindingStoreError(
|
|
1352
1345
|
"PROJECT_BINDINGS_INVALID",
|
|
1353
|
-
"
|
|
1346
|
+
"Project bindings are invalid."
|
|
1354
1347
|
);
|
|
1355
1348
|
}
|
|
1356
1349
|
if (error instanceof JsonDocumentStoreError) {
|
|
1357
1350
|
if (error.code === "JSON_DOCUMENT_CONFLICT") {
|
|
1358
1351
|
return new ProjectBindingStoreError(
|
|
1359
1352
|
"PROJECT_BINDINGS_CONFLICT",
|
|
1360
|
-
"
|
|
1353
|
+
"Project bindings changed before they could be saved."
|
|
1361
1354
|
);
|
|
1362
1355
|
}
|
|
1363
1356
|
if (error.code === "JSON_DOCUMENT_INVALID" || error.code === "JSON_DOCUMENT_UNSAFE") {
|
|
1364
1357
|
return new ProjectBindingStoreError(
|
|
1365
1358
|
"PROJECT_BINDINGS_INVALID",
|
|
1366
|
-
"
|
|
1359
|
+
"Project bindings are invalid."
|
|
1367
1360
|
);
|
|
1368
1361
|
}
|
|
1369
1362
|
}
|
|
1370
1363
|
return new ProjectBindingStoreError(
|
|
1371
1364
|
"PROJECT_BINDINGS_UNAVAILABLE",
|
|
1372
|
-
"
|
|
1365
|
+
"Project bindings could not be accessed."
|
|
1373
1366
|
);
|
|
1374
1367
|
}
|
|
1375
1368
|
|
|
@@ -1439,6 +1432,12 @@ function isNodeErrorCode3(error, code) {
|
|
|
1439
1432
|
return error instanceof Error && "code" in error && error.code === code;
|
|
1440
1433
|
}
|
|
1441
1434
|
|
|
1435
|
+
// src/environment-slug.ts
|
|
1436
|
+
var environmentSlugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1437
|
+
function isValidEnvironmentSlug(value) {
|
|
1438
|
+
return value.length >= 2 && value.length <= 30 && environmentSlugPattern.test(value);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1442
1441
|
// src/projects/project-api.ts
|
|
1443
1442
|
import { z as z4 } from "zod";
|
|
1444
1443
|
var PROJECT_SERVICES = [
|
|
@@ -1502,7 +1501,7 @@ var OverviewSchema = z4.object({
|
|
|
1502
1501
|
});
|
|
1503
1502
|
function createProjectApi(input) {
|
|
1504
1503
|
const origin = resolveSiteOSAuthBaseUrl(input.env);
|
|
1505
|
-
async function request(
|
|
1504
|
+
async function request(path29, schema, body, method) {
|
|
1506
1505
|
const scope = body === void 0 ? "projects:workspace:read" : "projects:workspace:write";
|
|
1507
1506
|
const grant = await input.grants.acquire({
|
|
1508
1507
|
audience: "siteos-projects",
|
|
@@ -1516,7 +1515,7 @@ function createProjectApi(input) {
|
|
|
1516
1515
|
message: "SiteOS API access is unavailable."
|
|
1517
1516
|
});
|
|
1518
1517
|
const response = await input.fetchImpl(
|
|
1519
|
-
`${origin}/api/projects/v1/projects${
|
|
1518
|
+
`${origin}/api/projects/v1/projects${path29}`,
|
|
1520
1519
|
{
|
|
1521
1520
|
method: method ?? (body === void 0 ? "GET" : "POST"),
|
|
1522
1521
|
headers: {
|
|
@@ -1660,7 +1659,7 @@ function invalidResponse() {
|
|
|
1660
1659
|
// src/projects/project-context.ts
|
|
1661
1660
|
function commonProjectRuntime(options) {
|
|
1662
1661
|
const store = options.projectBindingStore ?? new NodeProjectBindingStore(
|
|
1663
|
-
path6.join(resolveSiteOSConfigHome(options), "
|
|
1662
|
+
path6.join(resolveSiteOSConfigHome(options), "projects.json")
|
|
1664
1663
|
);
|
|
1665
1664
|
const grants = options.serviceGrantProvider ?? createSiteOSServiceGrantProvider(options);
|
|
1666
1665
|
return { store, grants, api: createProjectApi({ ...options, grants }) };
|
|
@@ -1681,7 +1680,12 @@ async function readCommonProject(options, environmentSlug) {
|
|
|
1681
1680
|
const local = await readLocalCommonProject(options);
|
|
1682
1681
|
if (!local) return null;
|
|
1683
1682
|
const { api, binding } = local;
|
|
1684
|
-
const selectedSlug = environmentSlug ?? binding.environmentSlug
|
|
1683
|
+
const selectedSlug = environmentSlug ?? binding.environmentSlug;
|
|
1684
|
+
if (!selectedSlug)
|
|
1685
|
+
throw new SiteOSAuthApiError({
|
|
1686
|
+
code: "PROJECT_ENVIRONMENT_REQUIRED",
|
|
1687
|
+
message: "Select an environment with `siteos project environment use <slug>`."
|
|
1688
|
+
});
|
|
1685
1689
|
const overview = await api.get(binding.project.id, selectedSlug);
|
|
1686
1690
|
if (overview.project.organizationId !== binding.organizationId)
|
|
1687
1691
|
throw new SiteOSAuthApiError({
|
|
@@ -1732,11 +1736,6 @@ async function commonEnvironmentArguments(options, service, args2) {
|
|
|
1732
1736
|
throw cause;
|
|
1733
1737
|
});
|
|
1734
1738
|
if (!local) return args2;
|
|
1735
|
-
if (args2[0] === "environment" && args2[1] !== "list")
|
|
1736
|
-
throw new Error(
|
|
1737
|
-
"Manage shared environments with `siteos project environment` or Project settings."
|
|
1738
|
-
);
|
|
1739
|
-
if (["project", "environment", "submit"].includes(args2[0] ?? "")) return args2;
|
|
1740
1739
|
const normalized = args2.flatMap(
|
|
1741
1740
|
(arg) => arg.startsWith("--environment=") ? ["--environment", arg.slice("--environment=".length)] : [arg]
|
|
1742
1741
|
);
|
|
@@ -1745,6 +1744,8 @@ async function commonEnvironmentArguments(options, service, args2) {
|
|
|
1745
1744
|
const index = normalized.indexOf("--environment");
|
|
1746
1745
|
const slug2 = index >= 0 ? normalized[index + 1] : void 0;
|
|
1747
1746
|
if (index >= 0 && (!slug2 || slug2.startsWith("--"))) return args2;
|
|
1747
|
+
if (slug2 && !isValidEnvironmentSlug(slug2))
|
|
1748
|
+
throw new Error("--environment must be a valid environment slug.");
|
|
1748
1749
|
const context = await commonServiceContext(options, service, slug2);
|
|
1749
1750
|
const binding = context?.environmentBinding;
|
|
1750
1751
|
if (!context || !binding?.slug)
|
|
@@ -1757,113 +1758,11 @@ async function commonEnvironmentArguments(options, service, args2) {
|
|
|
1757
1758
|
return result;
|
|
1758
1759
|
}
|
|
1759
1760
|
|
|
1760
|
-
// src/forms/project-reference.ts
|
|
1761
|
-
import path7 from "path";
|
|
1762
|
-
import { z as z5 } from "zod";
|
|
1763
|
-
var FORMS_PROJECT_REFERENCE_RELATIVE_PATH = path7.join(
|
|
1764
|
-
".siteos",
|
|
1765
|
-
"forms",
|
|
1766
|
-
"project.json"
|
|
1767
|
-
);
|
|
1768
|
-
var formsProjectReferenceSchema = z5.object({
|
|
1769
|
-
version: z5.literal(1),
|
|
1770
|
-
service: z5.literal("forms"),
|
|
1771
|
-
project: z5.object({
|
|
1772
|
-
name: z5.string().trim().min(1).max(255),
|
|
1773
|
-
slug: z5.string().trim().min(1).max(80).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
|
|
1774
|
-
}).strict()
|
|
1775
|
-
}).strict();
|
|
1776
|
-
var codec = {
|
|
1777
|
-
decode(input) {
|
|
1778
|
-
return { migrated: false, value: formsProjectReferenceSchema.parse(input) };
|
|
1779
|
-
},
|
|
1780
|
-
encode(value) {
|
|
1781
|
-
return formsProjectReferenceSchema.parse(value);
|
|
1782
|
-
}
|
|
1783
|
-
};
|
|
1784
|
-
var FormsProjectReferenceError = class extends Error {
|
|
1785
|
-
code;
|
|
1786
|
-
constructor(code, message) {
|
|
1787
|
-
super(message);
|
|
1788
|
-
this.name = "FormsProjectReferenceError";
|
|
1789
|
-
this.code = code;
|
|
1790
|
-
}
|
|
1791
|
-
};
|
|
1792
|
-
async function inspectFormsProjectReference(startDir, documents = new NodeJsonDocumentStore()) {
|
|
1793
|
-
try {
|
|
1794
|
-
const rootDir = await findRepositoryRoot(startDir);
|
|
1795
|
-
const snapshot = await documents.read({
|
|
1796
|
-
codec,
|
|
1797
|
-
filePath: path7.join(rootDir, FORMS_PROJECT_REFERENCE_RELATIVE_PATH),
|
|
1798
|
-
security: "tracked"
|
|
1799
|
-
});
|
|
1800
|
-
if (snapshot.status === "missing") return { rootDir, status: "missing" };
|
|
1801
|
-
return {
|
|
1802
|
-
checksum: snapshot.checksum,
|
|
1803
|
-
reference: snapshot.value,
|
|
1804
|
-
rootDir,
|
|
1805
|
-
status: "loaded"
|
|
1806
|
-
};
|
|
1807
|
-
} catch (error) {
|
|
1808
|
-
throw mapReferenceError(error);
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
async function writeFormsProjectReference(options) {
|
|
1812
|
-
const reference = formsProjectReferenceSchema.parse({
|
|
1813
|
-
version: 1,
|
|
1814
|
-
service: "forms",
|
|
1815
|
-
project: options.project
|
|
1816
|
-
});
|
|
1817
|
-
try {
|
|
1818
|
-
await (options.documents ?? new NodeJsonDocumentStore()).write({
|
|
1819
|
-
codec,
|
|
1820
|
-
expectedChecksum: options.expectedChecksum,
|
|
1821
|
-
filePath: path7.join(
|
|
1822
|
-
await findRepositoryRoot(options.rootDir),
|
|
1823
|
-
FORMS_PROJECT_REFERENCE_RELATIVE_PATH
|
|
1824
|
-
),
|
|
1825
|
-
security: "tracked",
|
|
1826
|
-
value: reference
|
|
1827
|
-
});
|
|
1828
|
-
return reference;
|
|
1829
|
-
} catch (error) {
|
|
1830
|
-
throw mapReferenceError(error);
|
|
1831
|
-
}
|
|
1832
|
-
}
|
|
1833
|
-
function mapReferenceError(error) {
|
|
1834
|
-
if (error instanceof FormsProjectReferenceError) return error;
|
|
1835
|
-
if (error instanceof RepositoryRootError) throw error;
|
|
1836
|
-
if (error instanceof JsonDocumentStoreError) {
|
|
1837
|
-
if (error.code === "JSON_DOCUMENT_CONFLICT") {
|
|
1838
|
-
return new FormsProjectReferenceError(
|
|
1839
|
-
"FORMS_PROJECT_REFERENCE_CONFLICT",
|
|
1840
|
-
"The Forms Project reference changed before it could be saved."
|
|
1841
|
-
);
|
|
1842
|
-
}
|
|
1843
|
-
if (error.code === "JSON_DOCUMENT_INVALID" || error.code === "JSON_DOCUMENT_UNSAFE") {
|
|
1844
|
-
return new FormsProjectReferenceError(
|
|
1845
|
-
"FORMS_PROJECT_REFERENCE_INVALID",
|
|
1846
|
-
"The Forms Project reference is invalid."
|
|
1847
|
-
);
|
|
1848
|
-
}
|
|
1849
|
-
}
|
|
1850
|
-
if (error instanceof z5.ZodError) {
|
|
1851
|
-
return new FormsProjectReferenceError(
|
|
1852
|
-
"FORMS_PROJECT_REFERENCE_INVALID",
|
|
1853
|
-
"The Forms Project reference is invalid."
|
|
1854
|
-
);
|
|
1855
|
-
}
|
|
1856
|
-
return new FormsProjectReferenceError(
|
|
1857
|
-
"FORMS_PROJECT_REFERENCE_UNAVAILABLE",
|
|
1858
|
-
"The Forms Project reference could not be accessed."
|
|
1859
|
-
);
|
|
1860
|
-
}
|
|
1861
|
-
|
|
1862
1761
|
// src/pulse/config.ts
|
|
1863
1762
|
import { createHash as createHash3, randomBytes } from "crypto";
|
|
1864
1763
|
import { readFile as readFile3, rename as rename3, unlink, writeFile as writeFile3 } from "fs/promises";
|
|
1865
|
-
import
|
|
1866
|
-
import { z as
|
|
1764
|
+
import path7 from "path";
|
|
1765
|
+
import { z as z5 } from "zod";
|
|
1867
1766
|
|
|
1868
1767
|
// src/pulse/errors.ts
|
|
1869
1768
|
var CliError = class extends Error {
|
|
@@ -1882,44 +1781,43 @@ var CliError = class extends Error {
|
|
|
1882
1781
|
// src/pulse/config.ts
|
|
1883
1782
|
var CONFIG_FILE = "siteos.config.json";
|
|
1884
1783
|
function isSafeRelativePath(value) {
|
|
1885
|
-
if (!value ||
|
|
1784
|
+
if (!value || path7.isAbsolute(value) || value.startsWith("!")) return false;
|
|
1886
1785
|
return !value.split(/[\\/]/).includes("..");
|
|
1887
1786
|
}
|
|
1888
|
-
var safeRelativePath =
|
|
1787
|
+
var safeRelativePath = z5.string().trim().min(1).refine(
|
|
1889
1788
|
isSafeRelativePath,
|
|
1890
1789
|
"Use a relative path without '..' or negated glob patterns."
|
|
1891
1790
|
);
|
|
1892
|
-
var slug =
|
|
1791
|
+
var slug = z5.string().trim().min(1).max(80).regex(
|
|
1893
1792
|
/^[a-z0-9]+(?:-[a-z0-9]+)*$/,
|
|
1894
1793
|
"Use lowercase letters, numbers, and hyphens."
|
|
1895
1794
|
);
|
|
1896
|
-
var displayName =
|
|
1897
|
-
var httpUrl =
|
|
1795
|
+
var displayName = z5.string().trim().min(1).max(120);
|
|
1796
|
+
var httpUrl = z5.string().url().refine((value) => ["http:", "https:"].includes(new URL(value).protocol), {
|
|
1898
1797
|
message: "Use an HTTP or HTTPS URL."
|
|
1899
1798
|
});
|
|
1900
|
-
var legacySchedule =
|
|
1901
|
-
enabled:
|
|
1902
|
-
cadenceSeconds:
|
|
1799
|
+
var legacySchedule = z5.object({
|
|
1800
|
+
enabled: z5.boolean().default(true),
|
|
1801
|
+
cadenceSeconds: z5.number().int().min(60).max(2592e3).default(300)
|
|
1903
1802
|
}).default({ enabled: true, cadenceSeconds: 300 });
|
|
1904
|
-
var ChecksConfigV1Schema =
|
|
1905
|
-
version:
|
|
1803
|
+
var ChecksConfigV1Schema = z5.object({
|
|
1804
|
+
version: z5.literal(1),
|
|
1906
1805
|
project: slug,
|
|
1907
1806
|
suite: slug.default("smoke"),
|
|
1908
1807
|
testsDir: safeRelativePath.default("tests/checks"),
|
|
1909
1808
|
playwrightConfig: safeRelativePath.optional(),
|
|
1910
|
-
include:
|
|
1809
|
+
include: z5.array(safeRelativePath).min(1).max(100),
|
|
1911
1810
|
baseUrl: httpUrl.optional(),
|
|
1912
|
-
schedule: legacySchedule
|
|
1913
|
-
apiUrl: httpUrl.optional()
|
|
1811
|
+
schedule: legacySchedule
|
|
1914
1812
|
});
|
|
1915
|
-
var ScheduledConfigSchema =
|
|
1916
|
-
mode:
|
|
1917
|
-
cadenceSeconds:
|
|
1813
|
+
var ScheduledConfigSchema = z5.object({
|
|
1814
|
+
mode: z5.literal("scheduled"),
|
|
1815
|
+
cadenceSeconds: z5.number().int().min(60).max(2592e3).default(300)
|
|
1918
1816
|
});
|
|
1919
|
-
var ManualConfigSchema =
|
|
1920
|
-
var CheckConfigSchema =
|
|
1921
|
-
environmentVariables:
|
|
1922
|
-
|
|
1817
|
+
var ManualConfigSchema = z5.object({ mode: z5.literal("manual") });
|
|
1818
|
+
var CheckConfigSchema = z5.object({
|
|
1819
|
+
environmentVariables: z5.array(
|
|
1820
|
+
z5.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/).refine(
|
|
1923
1821
|
(name) => !/^(?:SITEOS_|PLAYWRIGHT_|DOCKER_|NODE_|NPM_|PNPM_|LD_|DYLD_)/.test(
|
|
1924
1822
|
name
|
|
1925
1823
|
) && ![
|
|
@@ -1940,29 +1838,28 @@ var CheckConfigSchema = z6.object({
|
|
|
1940
1838
|
).optional(),
|
|
1941
1839
|
slug,
|
|
1942
1840
|
name: displayName,
|
|
1943
|
-
include:
|
|
1944
|
-
active:
|
|
1945
|
-
schedule:
|
|
1841
|
+
include: z5.array(safeRelativePath).min(1).max(100),
|
|
1842
|
+
active: z5.boolean().default(true),
|
|
1843
|
+
schedule: z5.discriminatedUnion("mode", [ScheduledConfigSchema, ManualConfigSchema]).default({ mode: "scheduled", cadenceSeconds: 300 })
|
|
1946
1844
|
});
|
|
1947
|
-
var ChecksConfigV2Schema =
|
|
1948
|
-
version:
|
|
1949
|
-
project:
|
|
1845
|
+
var ChecksConfigV2Schema = z5.object({
|
|
1846
|
+
version: z5.literal(2),
|
|
1847
|
+
project: z5.object({
|
|
1950
1848
|
slug,
|
|
1951
1849
|
name: displayName,
|
|
1952
1850
|
baseUrl: httpUrl.optional(),
|
|
1953
|
-
monitoringEnabled:
|
|
1851
|
+
monitoringEnabled: z5.boolean().default(true)
|
|
1954
1852
|
}),
|
|
1955
1853
|
testsDir: safeRelativePath.default("tests/siteos"),
|
|
1956
1854
|
playwrightConfig: safeRelativePath.optional(),
|
|
1957
|
-
bundle:
|
|
1958
|
-
checks:
|
|
1959
|
-
apiUrl: httpUrl.optional()
|
|
1855
|
+
bundle: z5.object({ include: z5.array(safeRelativePath).max(500).default([]) }).strict().optional(),
|
|
1856
|
+
checks: z5.array(CheckConfigSchema).min(1).max(100)
|
|
1960
1857
|
}).superRefine((config, context) => {
|
|
1961
1858
|
const slugs = /* @__PURE__ */ new Set();
|
|
1962
1859
|
for (const [index, check] of config.checks.entries()) {
|
|
1963
1860
|
if (slugs.has(check.slug)) {
|
|
1964
1861
|
context.addIssue({
|
|
1965
|
-
code:
|
|
1862
|
+
code: z5.ZodIssueCode.custom,
|
|
1966
1863
|
path: ["checks", index, "slug"],
|
|
1967
1864
|
message: `Duplicate Check slug: ${check.slug}`
|
|
1968
1865
|
});
|
|
@@ -1970,7 +1867,7 @@ var ChecksConfigV2Schema = z6.object({
|
|
|
1970
1867
|
slugs.add(check.slug);
|
|
1971
1868
|
}
|
|
1972
1869
|
});
|
|
1973
|
-
var ChecksConfigSchema =
|
|
1870
|
+
var ChecksConfigSchema = z5.union([
|
|
1974
1871
|
ChecksConfigV1Schema,
|
|
1975
1872
|
ChecksConfigV2Schema
|
|
1976
1873
|
]);
|
|
@@ -2003,8 +1900,7 @@ function normalizeChecksConfig(config) {
|
|
|
2003
1900
|
cadenceSeconds: config.schedule.cadenceSeconds
|
|
2004
1901
|
} : { mode: "manual" }
|
|
2005
1902
|
}
|
|
2006
|
-
]
|
|
2007
|
-
apiUrl: config.apiUrl
|
|
1903
|
+
]
|
|
2008
1904
|
});
|
|
2009
1905
|
}
|
|
2010
1906
|
async function fileExists(filePath) {
|
|
@@ -2017,7 +1913,7 @@ async function fileExists(filePath) {
|
|
|
2017
1913
|
}
|
|
2018
1914
|
}
|
|
2019
1915
|
async function findChecksConfigFile(projectRoot) {
|
|
2020
|
-
return await fileExists(
|
|
1916
|
+
return await fileExists(path7.join(projectRoot, CONFIG_FILE)) ? CONFIG_FILE : null;
|
|
2021
1917
|
}
|
|
2022
1918
|
async function loadChecksConfigFile(projectRoot) {
|
|
2023
1919
|
return (await loadChecksConfigSnapshot(projectRoot)).fileConfig;
|
|
@@ -2033,7 +1929,7 @@ async function loadChecksConfigSnapshot(projectRoot) {
|
|
|
2033
1929
|
}
|
|
2034
1930
|
);
|
|
2035
1931
|
}
|
|
2036
|
-
const configPath =
|
|
1932
|
+
const configPath = path7.join(projectRoot, configFile);
|
|
2037
1933
|
let source;
|
|
2038
1934
|
try {
|
|
2039
1935
|
source = await readFile3(configPath, "utf8");
|
|
@@ -2081,8 +1977,8 @@ async function loadChecksConfig(projectRoot) {
|
|
|
2081
1977
|
}
|
|
2082
1978
|
async function saveChecksConfig(projectRoot, config, options = {}) {
|
|
2083
1979
|
const configFile = await findChecksConfigFile(projectRoot) ?? CONFIG_FILE;
|
|
2084
|
-
const configPath =
|
|
2085
|
-
const temporaryPath =
|
|
1980
|
+
const configPath = path7.join(projectRoot, configFile);
|
|
1981
|
+
const temporaryPath = path7.join(
|
|
2086
1982
|
projectRoot,
|
|
2087
1983
|
`.${configFile}.${process.pid}.${randomBytes(6).toString("hex")}`
|
|
2088
1984
|
);
|
|
@@ -2119,19 +2015,6 @@ async function saveChecksConfig(projectRoot, config, options = {}) {
|
|
|
2119
2015
|
throw error;
|
|
2120
2016
|
}
|
|
2121
2017
|
}
|
|
2122
|
-
async function reconcileProjectSlug(projectRoot, projectSlug2, options = {}) {
|
|
2123
|
-
const snapshot = await loadChecksConfigSnapshot(projectRoot);
|
|
2124
|
-
const config = ChecksConfigV2Schema.parse({
|
|
2125
|
-
...snapshot.config,
|
|
2126
|
-
project: { ...snapshot.config.project, slug: projectSlug2 }
|
|
2127
|
-
});
|
|
2128
|
-
if (config.project.slug !== snapshot.config.project.slug || snapshot.migrationRequired) {
|
|
2129
|
-
await saveChecksConfig(projectRoot, config, {
|
|
2130
|
-
expectedChecksum: options.expectedChecksum ?? snapshot.checksum
|
|
2131
|
-
});
|
|
2132
|
-
}
|
|
2133
|
-
return loadChecksConfigSnapshot(projectRoot);
|
|
2134
|
-
}
|
|
2135
2018
|
function projectSlug(value) {
|
|
2136
2019
|
const normalized = value.trim().toLowerCase().replace(/^@[^/]+\//, "").replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 80);
|
|
2137
2020
|
return normalized || "siteos-pulse-project";
|
|
@@ -2143,111 +2026,6 @@ function projectDisplayName(value) {
|
|
|
2143
2026
|
return name.slice(0, 120) || "SiteOS Pulse Project";
|
|
2144
2027
|
}
|
|
2145
2028
|
|
|
2146
|
-
// src/search/project-reference.ts
|
|
2147
|
-
import path9 from "path";
|
|
2148
|
-
import { z as z7 } from "zod";
|
|
2149
|
-
var SEARCH_PROJECT_REFERENCE_RELATIVE_PATH = path9.join(
|
|
2150
|
-
".siteos",
|
|
2151
|
-
"search",
|
|
2152
|
-
"project.json"
|
|
2153
|
-
);
|
|
2154
|
-
var searchProjectReferenceSchema = z7.object({
|
|
2155
|
-
version: z7.literal(1),
|
|
2156
|
-
service: z7.literal("search"),
|
|
2157
|
-
project: z7.object({
|
|
2158
|
-
name: z7.string().trim().min(1).max(255),
|
|
2159
|
-
slug: z7.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
|
|
2160
|
-
}).strict()
|
|
2161
|
-
}).strict();
|
|
2162
|
-
var codec2 = {
|
|
2163
|
-
decode(input) {
|
|
2164
|
-
return {
|
|
2165
|
-
migrated: false,
|
|
2166
|
-
value: searchProjectReferenceSchema.parse(input)
|
|
2167
|
-
};
|
|
2168
|
-
},
|
|
2169
|
-
encode(value) {
|
|
2170
|
-
return searchProjectReferenceSchema.parse(value);
|
|
2171
|
-
}
|
|
2172
|
-
};
|
|
2173
|
-
var SearchProjectReferenceError = class extends Error {
|
|
2174
|
-
code;
|
|
2175
|
-
constructor(code, message) {
|
|
2176
|
-
super(message);
|
|
2177
|
-
this.name = "SearchProjectReferenceError";
|
|
2178
|
-
this.code = code;
|
|
2179
|
-
}
|
|
2180
|
-
};
|
|
2181
|
-
async function inspectSearchProjectReference(startDir, documents = new NodeJsonDocumentStore()) {
|
|
2182
|
-
try {
|
|
2183
|
-
const rootDir = await findRepositoryRoot(startDir);
|
|
2184
|
-
const snapshot = await documents.read({
|
|
2185
|
-
codec: codec2,
|
|
2186
|
-
filePath: path9.join(rootDir, SEARCH_PROJECT_REFERENCE_RELATIVE_PATH),
|
|
2187
|
-
security: "tracked"
|
|
2188
|
-
});
|
|
2189
|
-
if (snapshot.status === "missing") return { rootDir, status: "missing" };
|
|
2190
|
-
return {
|
|
2191
|
-
checksum: snapshot.checksum,
|
|
2192
|
-
reference: snapshot.value,
|
|
2193
|
-
rootDir,
|
|
2194
|
-
status: "loaded"
|
|
2195
|
-
};
|
|
2196
|
-
} catch (error) {
|
|
2197
|
-
throw mapReferenceError2(error);
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
async function writeSearchProjectReference(options) {
|
|
2201
|
-
const reference = searchProjectReferenceSchema.parse({
|
|
2202
|
-
version: 1,
|
|
2203
|
-
service: "search",
|
|
2204
|
-
project: options.project
|
|
2205
|
-
});
|
|
2206
|
-
try {
|
|
2207
|
-
await (options.documents ?? new NodeJsonDocumentStore()).write({
|
|
2208
|
-
codec: codec2,
|
|
2209
|
-
expectedChecksum: options.expectedChecksum,
|
|
2210
|
-
filePath: path9.join(
|
|
2211
|
-
await findRepositoryRoot(options.rootDir),
|
|
2212
|
-
SEARCH_PROJECT_REFERENCE_RELATIVE_PATH
|
|
2213
|
-
),
|
|
2214
|
-
security: "tracked",
|
|
2215
|
-
value: reference
|
|
2216
|
-
});
|
|
2217
|
-
return reference;
|
|
2218
|
-
} catch (error) {
|
|
2219
|
-
throw mapReferenceError2(error);
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
function mapReferenceError2(error) {
|
|
2223
|
-
if (error instanceof SearchProjectReferenceError) return error;
|
|
2224
|
-
if (error instanceof RepositoryRootError) throw error;
|
|
2225
|
-
if (error instanceof JsonDocumentStoreError) {
|
|
2226
|
-
if (error.code === "JSON_DOCUMENT_CONFLICT") {
|
|
2227
|
-
return new SearchProjectReferenceError(
|
|
2228
|
-
"SEARCH_PROJECT_REFERENCE_CONFLICT",
|
|
2229
|
-
"The Search Project reference changed before it could be saved."
|
|
2230
|
-
);
|
|
2231
|
-
}
|
|
2232
|
-
if (error.code === "JSON_DOCUMENT_INVALID" || error.code === "JSON_DOCUMENT_UNSAFE") {
|
|
2233
|
-
return new SearchProjectReferenceError(
|
|
2234
|
-
"SEARCH_PROJECT_REFERENCE_INVALID",
|
|
2235
|
-
"The Search Project reference is invalid."
|
|
2236
|
-
);
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
if (error instanceof z7.ZodError) {
|
|
2240
|
-
return new SearchProjectReferenceError(
|
|
2241
|
-
"SEARCH_PROJECT_REFERENCE_INVALID",
|
|
2242
|
-
"The Search Project reference is invalid."
|
|
2243
|
-
);
|
|
2244
|
-
}
|
|
2245
|
-
return new SearchProjectReferenceError(
|
|
2246
|
-
"SEARCH_PROJECT_REFERENCE_UNAVAILABLE",
|
|
2247
|
-
"The Search Project reference could not be accessed."
|
|
2248
|
-
);
|
|
2249
|
-
}
|
|
2250
|
-
|
|
2251
2029
|
// src/health-check.ts
|
|
2252
2030
|
async function createHealthCheckResult(options = {}) {
|
|
2253
2031
|
const packageMetadata = options.packageMetadata ?? {
|
|
@@ -2260,7 +2038,7 @@ async function createHealthCheckResult(options = {}) {
|
|
|
2260
2038
|
homeDir: options.homeDir
|
|
2261
2039
|
});
|
|
2262
2040
|
const repositoryRoot = await optionalRepositoryRoot(cwd);
|
|
2263
|
-
const
|
|
2041
|
+
const pulse = repositoryRoot ? await inspectPulse(repositoryRoot) : { path: path8.join(cwd, CONFIG_FILE), status: "missing" };
|
|
2264
2042
|
let project = { status: "missing" };
|
|
2265
2043
|
if (repositoryRoot) {
|
|
2266
2044
|
try {
|
|
@@ -2278,13 +2056,11 @@ async function createHealthCheckResult(options = {}) {
|
|
|
2278
2056
|
project = { status: "invalid" };
|
|
2279
2057
|
}
|
|
2280
2058
|
}
|
|
2281
|
-
const configured = project.status === "selected"
|
|
2282
|
-
(project2) => project2.status === "configured"
|
|
2283
|
-
);
|
|
2059
|
+
const configured = project.status === "selected";
|
|
2284
2060
|
return {
|
|
2285
2061
|
checks: {
|
|
2286
2062
|
configHome: { path: configHome, status: "ok" },
|
|
2287
|
-
|
|
2063
|
+
pulse,
|
|
2288
2064
|
project,
|
|
2289
2065
|
repository: repositoryRoot ? { rootDir: repositoryRoot, status: "ok" } : { status: "missing" }
|
|
2290
2066
|
},
|
|
@@ -2307,41 +2083,8 @@ async function optionalRepositoryRoot(cwd) {
|
|
|
2307
2083
|
throw error;
|
|
2308
2084
|
}
|
|
2309
2085
|
}
|
|
2310
|
-
async function inspectProductProjects(repositoryRoot) {
|
|
2311
|
-
const [forms, pulse, search] = await Promise.all([
|
|
2312
|
-
inspectReference(
|
|
2313
|
-
"forms",
|
|
2314
|
-
path10.join(repositoryRoot, FORMS_PROJECT_REFERENCE_RELATIVE_PATH),
|
|
2315
|
-
() => inspectFormsProjectReference(repositoryRoot)
|
|
2316
|
-
),
|
|
2317
|
-
inspectPulse(repositoryRoot),
|
|
2318
|
-
inspectReference(
|
|
2319
|
-
"search",
|
|
2320
|
-
path10.join(repositoryRoot, SEARCH_PROJECT_REFERENCE_RELATIVE_PATH),
|
|
2321
|
-
() => inspectSearchProjectReference(repositoryRoot)
|
|
2322
|
-
)
|
|
2323
|
-
]);
|
|
2324
|
-
return { forms, pulse, search };
|
|
2325
|
-
}
|
|
2326
|
-
async function inspectReference(service, referencePath, inspect) {
|
|
2327
|
-
try {
|
|
2328
|
-
const state = await inspect();
|
|
2329
|
-
return state.status === "loaded" ? {
|
|
2330
|
-
path: referencePath,
|
|
2331
|
-
slug: state.reference.project.slug,
|
|
2332
|
-
status: "configured",
|
|
2333
|
-
version: state.reference.version
|
|
2334
|
-
} : { path: referencePath, status: "missing" };
|
|
2335
|
-
} catch (error) {
|
|
2336
|
-
return {
|
|
2337
|
-
error: error instanceof Error && "code" in error ? String(error.code) : `${service.toUpperCase()}_PROJECT_REFERENCE_INVALID`,
|
|
2338
|
-
path: referencePath,
|
|
2339
|
-
status: "invalid"
|
|
2340
|
-
};
|
|
2341
|
-
}
|
|
2342
|
-
}
|
|
2343
2086
|
async function inspectPulse(repositoryRoot) {
|
|
2344
|
-
const configPath =
|
|
2087
|
+
const configPath = path8.join(repositoryRoot, CONFIG_FILE);
|
|
2345
2088
|
try {
|
|
2346
2089
|
const snapshot = await loadChecksConfigSnapshot(repositoryRoot);
|
|
2347
2090
|
return {
|
|
@@ -2361,27 +2104,13 @@ async function inspectPulse(repositoryRoot) {
|
|
|
2361
2104
|
};
|
|
2362
2105
|
}
|
|
2363
2106
|
}
|
|
2364
|
-
function missingProductProjects(cwd) {
|
|
2365
|
-
const root = path10.resolve(cwd);
|
|
2366
|
-
return {
|
|
2367
|
-
forms: {
|
|
2368
|
-
path: path10.join(root, FORMS_PROJECT_REFERENCE_RELATIVE_PATH),
|
|
2369
|
-
status: "missing"
|
|
2370
|
-
},
|
|
2371
|
-
pulse: { path: path10.join(root, CONFIG_FILE), status: "missing" },
|
|
2372
|
-
search: {
|
|
2373
|
-
path: path10.join(root, SEARCH_PROJECT_REFERENCE_RELATIVE_PATH),
|
|
2374
|
-
status: "missing"
|
|
2375
|
-
}
|
|
2376
|
-
};
|
|
2377
|
-
}
|
|
2378
2107
|
|
|
2379
2108
|
// src/auth-command.ts
|
|
2380
2109
|
import { createHash as createHash4, randomBytes as randomBytes2 } from "crypto";
|
|
2381
2110
|
import os3 from "os";
|
|
2382
|
-
import { z as
|
|
2111
|
+
import { z as z6 } from "zod";
|
|
2383
2112
|
var HELP_FLAGS = /* @__PURE__ */ new Set(["--help", "-h"]);
|
|
2384
|
-
var organizationDisplayNameSchema =
|
|
2113
|
+
var organizationDisplayNameSchema = z6.string().transform((value) => value.trim()).refine((value) => {
|
|
2385
2114
|
const visibleLength = Array.from(value).length;
|
|
2386
2115
|
return visibleLength >= 2 && visibleLength <= 80;
|
|
2387
2116
|
});
|
|
@@ -2412,7 +2141,7 @@ async function runAuthCommand(options) {
|
|
|
2412
2141
|
if (subcommand === "start") {
|
|
2413
2142
|
const parsed = parseValueCommand(args2, "--email");
|
|
2414
2143
|
if (!parsed.ok) return usageError(parsed.error, parsed.json);
|
|
2415
|
-
const email =
|
|
2144
|
+
const email = z6.string().trim().email().safeParse(parsed.value);
|
|
2416
2145
|
if (!email.success) return usageError("--email is invalid.", parsed.json);
|
|
2417
2146
|
return runStart({
|
|
2418
2147
|
...options,
|
|
@@ -2425,7 +2154,7 @@ async function runAuthCommand(options) {
|
|
|
2425
2154
|
if (subcommand === "complete") {
|
|
2426
2155
|
const parsed = parseValueCommand(args2, "--token");
|
|
2427
2156
|
if (!parsed.ok) return usageError(parsed.error, parsed.json);
|
|
2428
|
-
const token =
|
|
2157
|
+
const token = z6.string().trim().regex(/^[A-Za-z0-9_-]{16}$/).safeParse(parsed.value);
|
|
2429
2158
|
if (!token.success) return usageError("--token is invalid.", parsed.json);
|
|
2430
2159
|
return runComplete({
|
|
2431
2160
|
...options,
|
|
@@ -2960,137 +2689,124 @@ function isCliExitCode(value) {
|
|
|
2960
2689
|
|
|
2961
2690
|
// src/forms-command.ts
|
|
2962
2691
|
import { readFile as readFile5 } from "fs/promises";
|
|
2963
|
-
import
|
|
2964
|
-
import { z as z10 } from "zod";
|
|
2692
|
+
import path10 from "path";
|
|
2965
2693
|
import { Ajv } from "ajv";
|
|
2966
2694
|
import addFormats from "ajv-formats";
|
|
2695
|
+
import { z as z8 } from "zod";
|
|
2967
2696
|
|
|
2968
2697
|
// src/siteos-forms-api.ts
|
|
2969
|
-
import { z as
|
|
2970
|
-
var
|
|
2971
|
-
var
|
|
2972
|
-
|
|
2973
|
-
var formsProjectSchema = z9.object({
|
|
2974
|
-
createdAt: z9.string().datetime({ offset: true }),
|
|
2975
|
-
id: opaqueIdentifierSchema,
|
|
2976
|
-
name: z9.string().trim().min(1).max(255),
|
|
2977
|
-
organizationId: opaqueIdentifierSchema,
|
|
2978
|
-
slug: z9.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
2979
|
-
updatedAt: z9.string().datetime({ offset: true })
|
|
2980
|
-
}).strict();
|
|
2981
|
-
var formsProjectListSchema = z9.object({ projects: z9.array(formsProjectSchema) }).strict();
|
|
2982
|
-
var formsProjectResponseSchema = z9.object({ project: formsProjectSchema }).strict();
|
|
2983
|
-
var formsEnvironmentSchema = z9.object({
|
|
2984
|
-
createdAt: z9.string().datetime({ offset: true }),
|
|
2698
|
+
import { z as z7 } from "zod";
|
|
2699
|
+
var opaqueIdentifierSchema = z7.string().trim().min(1).max(255);
|
|
2700
|
+
var formsEnvironmentSchema = z7.object({
|
|
2701
|
+
createdAt: z7.string().datetime({ offset: true }),
|
|
2985
2702
|
id: opaqueIdentifierSchema,
|
|
2986
|
-
name:
|
|
2703
|
+
name: z7.string().trim().min(1).max(255),
|
|
2987
2704
|
projectId: opaqueIdentifierSchema,
|
|
2988
|
-
slug:
|
|
2989
|
-
updatedAt:
|
|
2705
|
+
slug: z7.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
2706
|
+
updatedAt: z7.string().datetime({ offset: true })
|
|
2990
2707
|
}).strict();
|
|
2991
|
-
var formsEnvironmentListSchema =
|
|
2992
|
-
var
|
|
2993
|
-
var formDefinitionSyncResponseSchema = z9.object({
|
|
2708
|
+
var formsEnvironmentListSchema = z7.object({ environments: z7.array(formsEnvironmentSchema) }).strict();
|
|
2709
|
+
var formDefinitionSyncResponseSchema = z7.object({
|
|
2994
2710
|
activeVersionId: opaqueIdentifierSchema,
|
|
2995
|
-
createdForm:
|
|
2996
|
-
createdVersion:
|
|
2711
|
+
createdForm: z7.boolean(),
|
|
2712
|
+
createdVersion: z7.boolean(),
|
|
2997
2713
|
formId: opaqueIdentifierSchema,
|
|
2998
2714
|
formKey: opaqueIdentifierSchema,
|
|
2999
|
-
success:
|
|
3000
|
-
version:
|
|
2715
|
+
success: z7.literal(true),
|
|
2716
|
+
version: z7.number().int().positive()
|
|
3001
2717
|
}).strict();
|
|
3002
|
-
var definitionSchema =
|
|
2718
|
+
var definitionSchema = z7.object({
|
|
3003
2719
|
id: opaqueIdentifierSchema,
|
|
3004
2720
|
environmentId: opaqueIdentifierSchema,
|
|
3005
2721
|
formKey: opaqueIdentifierSchema,
|
|
3006
|
-
name:
|
|
3007
|
-
sourcePagePath:
|
|
3008
|
-
activeVersion:
|
|
2722
|
+
name: z7.string(),
|
|
2723
|
+
sourcePagePath: z7.string().nullable(),
|
|
2724
|
+
activeVersion: z7.number().int().positive(),
|
|
3009
2725
|
activeVersionId: opaqueIdentifierSchema,
|
|
3010
|
-
status:
|
|
3011
|
-
submissionCount:
|
|
3012
|
-
lastSubmittedAt:
|
|
3013
|
-
createdAt:
|
|
3014
|
-
updatedAt:
|
|
2726
|
+
status: z7.enum(["active", "inactive"]),
|
|
2727
|
+
submissionCount: z7.number().int().nonnegative(),
|
|
2728
|
+
lastSubmittedAt: z7.string().datetime({ offset: true }).nullable(),
|
|
2729
|
+
createdAt: z7.string().datetime({ offset: true }),
|
|
2730
|
+
updatedAt: z7.string().datetime({ offset: true })
|
|
3015
2731
|
});
|
|
3016
|
-
var definitionListSchema =
|
|
3017
|
-
definitions:
|
|
2732
|
+
var definitionListSchema = z7.object({
|
|
2733
|
+
definitions: z7.array(definitionSchema)
|
|
3018
2734
|
});
|
|
3019
|
-
var definitionContextSchema =
|
|
2735
|
+
var definitionContextSchema = z7.object({
|
|
3020
2736
|
definition: definitionSchema,
|
|
3021
|
-
revision:
|
|
3022
|
-
canManage:
|
|
3023
|
-
project:
|
|
3024
|
-
environment:
|
|
2737
|
+
revision: z7.number().int().positive(),
|
|
2738
|
+
canManage: z7.boolean(),
|
|
2739
|
+
project: z7.object({ id: opaqueIdentifierSchema, name: z7.string() }),
|
|
2740
|
+
environment: z7.object({
|
|
3025
2741
|
id: opaqueIdentifierSchema,
|
|
3026
|
-
name:
|
|
3027
|
-
slug:
|
|
2742
|
+
name: z7.string(),
|
|
2743
|
+
slug: z7.string()
|
|
3028
2744
|
})
|
|
3029
2745
|
});
|
|
3030
|
-
var definitionChangeResponseSchema =
|
|
3031
|
-
deleted:
|
|
2746
|
+
var definitionChangeResponseSchema = z7.object({
|
|
2747
|
+
deleted: z7.boolean(),
|
|
3032
2748
|
formId: opaqueIdentifierSchema
|
|
3033
2749
|
});
|
|
3034
|
-
var formSubmissionResponseSchema =
|
|
2750
|
+
var formSubmissionResponseSchema = z7.object({
|
|
3035
2751
|
formId: opaqueIdentifierSchema,
|
|
3036
|
-
receivedAt:
|
|
2752
|
+
receivedAt: z7.string().datetime({ offset: true }),
|
|
3037
2753
|
submissionId: opaqueIdentifierSchema,
|
|
3038
|
-
success:
|
|
2754
|
+
success: z7.literal(true)
|
|
3039
2755
|
}).strict();
|
|
3040
|
-
var formsSubmissionStatusSchema =
|
|
2756
|
+
var formsSubmissionStatusSchema = z7.enum([
|
|
3041
2757
|
"new",
|
|
3042
2758
|
"read",
|
|
3043
2759
|
"archived",
|
|
3044
2760
|
"spam"
|
|
3045
2761
|
]);
|
|
3046
|
-
var submissionSummarySchema =
|
|
2762
|
+
var submissionSummarySchema = z7.object({
|
|
3047
2763
|
id: opaqueIdentifierSchema,
|
|
3048
2764
|
formId: opaqueIdentifierSchema,
|
|
3049
|
-
normalized:
|
|
3050
|
-
|
|
2765
|
+
normalized: z7.record(
|
|
2766
|
+
z7.union([z7.string(), z7.number(), z7.boolean(), z7.null()])
|
|
3051
2767
|
),
|
|
3052
2768
|
status: formsSubmissionStatusSchema,
|
|
3053
|
-
submittedAt:
|
|
2769
|
+
submittedAt: z7.string().datetime({ offset: true })
|
|
3054
2770
|
});
|
|
3055
2771
|
var submissionDetailSchema = submissionSummarySchema.extend({
|
|
3056
|
-
payload:
|
|
3057
|
-
fields:
|
|
3058
|
-
|
|
3059
|
-
key:
|
|
3060
|
-
label:
|
|
3061
|
-
kind:
|
|
3062
|
-
displayRole:
|
|
3063
|
-
multiple:
|
|
3064
|
-
options:
|
|
2772
|
+
payload: z7.record(z7.unknown()),
|
|
2773
|
+
fields: z7.array(
|
|
2774
|
+
z7.object({
|
|
2775
|
+
key: z7.string(),
|
|
2776
|
+
label: z7.string().optional(),
|
|
2777
|
+
kind: z7.string().optional(),
|
|
2778
|
+
displayRole: z7.enum(["primary", "secondary"]).optional(),
|
|
2779
|
+
multiple: z7.boolean().optional(),
|
|
2780
|
+
options: z7.array(z7.object({ value: z7.string(), label: z7.string() })).optional()
|
|
3065
2781
|
})
|
|
3066
2782
|
),
|
|
3067
|
-
version:
|
|
2783
|
+
version: z7.number().int().positive(),
|
|
3068
2784
|
versionId: opaqueIdentifierSchema
|
|
3069
2785
|
});
|
|
3070
|
-
var submissionPageSchema =
|
|
3071
|
-
submissions:
|
|
3072
|
-
total:
|
|
3073
|
-
nextCursor:
|
|
2786
|
+
var submissionPageSchema = z7.object({
|
|
2787
|
+
submissions: z7.array(submissionSummarySchema),
|
|
2788
|
+
total: z7.number().int().nonnegative(),
|
|
2789
|
+
nextCursor: z7.string().nullable()
|
|
3074
2790
|
});
|
|
3075
|
-
var submissionDetailResponseSchema =
|
|
2791
|
+
var submissionDetailResponseSchema = z7.object({
|
|
3076
2792
|
submission: submissionDetailSchema
|
|
3077
2793
|
});
|
|
3078
|
-
var formsCredentialMetadataSchema =
|
|
3079
|
-
createdAt:
|
|
3080
|
-
id:
|
|
3081
|
-
lastUsedAt:
|
|
3082
|
-
name:
|
|
3083
|
-
projectEnvironmentId:
|
|
3084
|
-
revokedAt:
|
|
3085
|
-
status:
|
|
2794
|
+
var formsCredentialMetadataSchema = z7.object({
|
|
2795
|
+
createdAt: z7.string().datetime({ offset: true }),
|
|
2796
|
+
id: z7.string().trim().min(1).max(255),
|
|
2797
|
+
lastUsedAt: z7.string().datetime({ offset: true }).nullable(),
|
|
2798
|
+
name: z7.string().trim().min(1).max(255),
|
|
2799
|
+
projectEnvironmentId: z7.string().trim().min(1).max(255),
|
|
2800
|
+
revokedAt: z7.string().datetime({ offset: true }).nullable(),
|
|
2801
|
+
status: z7.enum(["active", "revoked"])
|
|
3086
2802
|
}).strict();
|
|
3087
|
-
var formsCredentialListSchema =
|
|
3088
|
-
tokens:
|
|
2803
|
+
var formsCredentialListSchema = z7.object({
|
|
2804
|
+
tokens: z7.array(formsCredentialMetadataSchema)
|
|
3089
2805
|
}).strict();
|
|
3090
2806
|
var formsCredentialExchangeSchema = formsCredentialMetadataSchema.extend({
|
|
3091
|
-
token:
|
|
2807
|
+
token: z7.string().regex(/^pfs_[A-Za-z0-9_-]{22}$/)
|
|
3092
2808
|
});
|
|
3093
|
-
var formsErrorCodeSchema =
|
|
2809
|
+
var formsErrorCodeSchema = z7.enum([
|
|
3094
2810
|
"AUTHENTICATION_REQUIRED",
|
|
3095
2811
|
"FORBIDDEN",
|
|
3096
2812
|
"CONFLICT",
|
|
@@ -3138,10 +2854,10 @@ var safeFormsErrorMessages = {
|
|
|
3138
2854
|
SERVICE_UNAVAILABLE: "The Forms service is unavailable.",
|
|
3139
2855
|
INTERNAL_ERROR: "The Forms request could not be completed."
|
|
3140
2856
|
};
|
|
3141
|
-
var apiErrorResponseSchema =
|
|
3142
|
-
error:
|
|
2857
|
+
var apiErrorResponseSchema = z7.object({
|
|
2858
|
+
error: z7.object({
|
|
3143
2859
|
code: formsErrorCodeSchema,
|
|
3144
|
-
message:
|
|
2860
|
+
message: z7.string().trim().min(1).max(240)
|
|
3145
2861
|
}).strict()
|
|
3146
2862
|
}).strict();
|
|
3147
2863
|
var SiteOSFormsApiError = class extends Error {
|
|
@@ -3154,20 +2870,15 @@ var SiteOSFormsApiError = class extends Error {
|
|
|
3154
2870
|
this.status = options.status;
|
|
3155
2871
|
}
|
|
3156
2872
|
};
|
|
3157
|
-
|
|
3158
|
-
return normalizeFormsOrigin(
|
|
3159
|
-
env[SITEOS_FORMS_BASE_URL_ENV]?.trim() || DEFAULT_SITEOS_FORMS_BASE_URL
|
|
3160
|
-
);
|
|
3161
|
-
}
|
|
3162
|
-
var deploymentResponseSchema = z9.object({
|
|
2873
|
+
var deploymentResponseSchema = z7.object({
|
|
3163
2874
|
environmentId: opaqueIdentifierSchema,
|
|
3164
|
-
forms:
|
|
3165
|
-
|
|
2875
|
+
forms: z7.array(
|
|
2876
|
+
z7.object({
|
|
3166
2877
|
formKey: opaqueIdentifierSchema,
|
|
3167
2878
|
formId: opaqueIdentifierSchema,
|
|
3168
|
-
contractVersion:
|
|
2879
|
+
contractVersion: z7.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
3169
2880
|
versionId: opaqueIdentifierSchema,
|
|
3170
|
-
version:
|
|
2881
|
+
version: z7.number().int().positive()
|
|
3171
2882
|
})
|
|
3172
2883
|
)
|
|
3173
2884
|
});
|
|
@@ -3236,24 +2947,6 @@ function createSiteOSFormsApiClient(options) {
|
|
|
3236
2947
|
body: { status: input.status, expectedStatus: input.expectedStatus },
|
|
3237
2948
|
responseSchema: submissionDetailResponseSchema
|
|
3238
2949
|
}),
|
|
3239
|
-
createProject: (input) => requestJson2({
|
|
3240
|
-
apiBaseUrl,
|
|
3241
|
-
body: { name: input.name, slug: input.slug },
|
|
3242
|
-
fetchImpl: options.fetchImpl,
|
|
3243
|
-
headers: managementHeaders(input),
|
|
3244
|
-
method: "POST",
|
|
3245
|
-
path: "/api/v1/forms/projects",
|
|
3246
|
-
responseSchema: formsProjectResponseSchema
|
|
3247
|
-
}),
|
|
3248
|
-
createEnvironment: (input) => requestJson2({
|
|
3249
|
-
apiBaseUrl,
|
|
3250
|
-
body: { name: input.name, slug: input.slug },
|
|
3251
|
-
fetchImpl: options.fetchImpl,
|
|
3252
|
-
headers: managementHeaders(input),
|
|
3253
|
-
method: "POST",
|
|
3254
|
-
path: environmentCollectionPath(input),
|
|
3255
|
-
responseSchema: formsEnvironmentResponseSchema
|
|
3256
|
-
}),
|
|
3257
2950
|
issueCredential: (input) => requestJson2({
|
|
3258
2951
|
apiBaseUrl,
|
|
3259
2952
|
body: input.name ? { name: input.name } : {},
|
|
@@ -3262,7 +2955,7 @@ function createSiteOSFormsApiClient(options) {
|
|
|
3262
2955
|
method: "POST",
|
|
3263
2956
|
path: keyCollection(input),
|
|
3264
2957
|
responseSchema: options.deploymentKeys ? formsCredentialExchangeSchema.extend({
|
|
3265
|
-
token:
|
|
2958
|
+
token: z7.string().regex(/^pfd_[A-Za-z0-9_-]{43}$/)
|
|
3266
2959
|
}) : formsCredentialExchangeSchema
|
|
3267
2960
|
}),
|
|
3268
2961
|
listEnvironments: (input) => requestJson2({
|
|
@@ -3273,14 +2966,6 @@ function createSiteOSFormsApiClient(options) {
|
|
|
3273
2966
|
path: environmentCollectionPath(input),
|
|
3274
2967
|
responseSchema: formsEnvironmentListSchema
|
|
3275
2968
|
}),
|
|
3276
|
-
listProjects: (input) => requestJson2({
|
|
3277
|
-
apiBaseUrl,
|
|
3278
|
-
fetchImpl: options.fetchImpl,
|
|
3279
|
-
headers: managementHeaders(input),
|
|
3280
|
-
method: "GET",
|
|
3281
|
-
path: "/api/v1/forms/projects",
|
|
3282
|
-
responseSchema: formsProjectListSchema
|
|
3283
|
-
}),
|
|
3284
2969
|
listCredentials: (input) => requestJson2({
|
|
3285
2970
|
apiBaseUrl,
|
|
3286
2971
|
fetchImpl: options.fetchImpl,
|
|
@@ -3305,7 +2990,7 @@ function createSiteOSFormsApiClient(options) {
|
|
|
3305
2990
|
method: "POST",
|
|
3306
2991
|
path: credentialRotatePath(input),
|
|
3307
2992
|
responseSchema: options.deploymentKeys ? formsCredentialExchangeSchema.extend({
|
|
3308
|
-
token:
|
|
2993
|
+
token: z7.string().regex(/^pfd_[A-Za-z0-9_-]{43}$/)
|
|
3309
2994
|
}) : formsCredentialExchangeSchema
|
|
3310
2995
|
}),
|
|
3311
2996
|
submitForm: (input) => requestJson2({
|
|
@@ -3433,7 +3118,7 @@ import {
|
|
|
3433
3118
|
rm as rm3,
|
|
3434
3119
|
writeFile as writeFile4
|
|
3435
3120
|
} from "fs/promises";
|
|
3436
|
-
import
|
|
3121
|
+
import path9 from "path";
|
|
3437
3122
|
var SITEOS_FORMS_SUBMISSION_CREDENTIAL_ENV = "SITEOS_FORMS_SUBMISSION_CREDENTIAL";
|
|
3438
3123
|
var SITEOS_FORMS_DEPLOYMENT_KEY_ENV = "SITEOS_FORMS_DEPLOYMENT_KEY";
|
|
3439
3124
|
var SiteOSFormsCredentialStorageError = class extends Error {
|
|
@@ -3449,8 +3134,8 @@ var SiteOSFormsCredentialStorageError = class extends Error {
|
|
|
3449
3134
|
async function prepareSiteOSFormsCredentialInstallation(options) {
|
|
3450
3135
|
const variable = options.deployment ? SITEOS_FORMS_DEPLOYMENT_KEY_ENV : SITEOS_FORMS_SUBMISSION_CREDENTIAL_ENV;
|
|
3451
3136
|
const credentialPattern = options.deployment ? /^pfd_[A-Za-z0-9_-]{43}$/ : /^pfs_[A-Za-z0-9_-]{22}$/;
|
|
3452
|
-
const projectRoot =
|
|
3453
|
-
const dotenvPath =
|
|
3137
|
+
const projectRoot = path9.resolve(options.projectRoot);
|
|
3138
|
+
const dotenvPath = path9.join(projectRoot, ".env");
|
|
3454
3139
|
try {
|
|
3455
3140
|
await assertSafeProjectRoot(projectRoot);
|
|
3456
3141
|
if (!await isDotenvIgnored(projectRoot)) {
|
|
@@ -3524,7 +3209,7 @@ async function readSafeDotenv(dotenvPath) {
|
|
|
3524
3209
|
return content;
|
|
3525
3210
|
}
|
|
3526
3211
|
async function writeCredentialAtomically(options) {
|
|
3527
|
-
const temporaryPath =
|
|
3212
|
+
const temporaryPath = path9.join(
|
|
3528
3213
|
options.projectRoot,
|
|
3529
3214
|
`.siteos-forms-credential.${process.pid}.${randomUUID3()}.tmp`
|
|
3530
3215
|
);
|
|
@@ -3577,12 +3262,6 @@ function isNodeErrorCode4(error, code) {
|
|
|
3577
3262
|
return error instanceof Error && "code" in error && error.code === code;
|
|
3578
3263
|
}
|
|
3579
3264
|
|
|
3580
|
-
// src/environment-slug.ts
|
|
3581
|
-
var environmentSlugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
3582
|
-
function isValidEnvironmentSlug(value) {
|
|
3583
|
-
return value.length >= 2 && value.length <= 30 && environmentSlugPattern.test(value);
|
|
3584
|
-
}
|
|
3585
|
-
|
|
3586
3265
|
// src/forms-command.ts
|
|
3587
3266
|
var HELP_FLAGS2 = /* @__PURE__ */ new Set(["--help", "-h"]);
|
|
3588
3267
|
var JSON_FLAG = "--json";
|
|
@@ -3591,28 +3270,26 @@ var MANIFEST_FLAG = "--manifest";
|
|
|
3591
3270
|
var ENVIRONMENT_FLAG = "--environment";
|
|
3592
3271
|
var INSTALL_FLAG = "--install";
|
|
3593
3272
|
var NAME_FLAG = "--name";
|
|
3594
|
-
var SLUG_FLAG = "--slug";
|
|
3595
3273
|
var CREDENTIAL_FLAG = "--credential";
|
|
3596
|
-
var
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
value: z10.string().trim().min(1).max(255)
|
|
3274
|
+
var normalizedFieldOptionSchema = z8.object({
|
|
3275
|
+
label: z8.string().trim().min(1).max(255),
|
|
3276
|
+
value: z8.string().trim().min(1).max(255)
|
|
3600
3277
|
});
|
|
3601
|
-
var normalizedFieldSchema =
|
|
3602
|
-
key:
|
|
3603
|
-
kind:
|
|
3604
|
-
label:
|
|
3605
|
-
displayRole:
|
|
3606
|
-
multiple:
|
|
3607
|
-
options:
|
|
3278
|
+
var normalizedFieldSchema = z8.object({
|
|
3279
|
+
key: z8.string().trim().min(1).max(255),
|
|
3280
|
+
kind: z8.string().trim().min(1).max(64).optional(),
|
|
3281
|
+
label: z8.string().trim().min(1).max(255).optional(),
|
|
3282
|
+
displayRole: z8.enum(["primary", "secondary"]).optional(),
|
|
3283
|
+
multiple: z8.boolean().optional(),
|
|
3284
|
+
options: z8.array(normalizedFieldOptionSchema).max(500).optional()
|
|
3608
3285
|
}).strict();
|
|
3609
|
-
var definitionSyncInputSchema =
|
|
3610
|
-
formKey:
|
|
3611
|
-
name:
|
|
3612
|
-
normalizedFieldsJson:
|
|
3613
|
-
schemaJson:
|
|
3614
|
-
sourceExportId:
|
|
3615
|
-
sourcePagePath:
|
|
3286
|
+
var definitionSyncInputSchema = z8.object({
|
|
3287
|
+
formKey: z8.string().trim().min(1).max(255),
|
|
3288
|
+
name: z8.string().trim().min(1).max(255),
|
|
3289
|
+
normalizedFieldsJson: z8.array(normalizedFieldSchema).min(1).max(500),
|
|
3290
|
+
schemaJson: z8.record(z8.unknown()),
|
|
3291
|
+
sourceExportId: z8.string().trim().min(1).max(255).optional(),
|
|
3292
|
+
sourcePagePath: z8.string().trim().min(1).max(2048).optional()
|
|
3616
3293
|
}).strict().superRefine((definition, context) => {
|
|
3617
3294
|
const ajv = new Ajv({
|
|
3618
3295
|
allErrors: true,
|
|
@@ -3624,7 +3301,7 @@ var definitionSyncInputSchema = z10.object({
|
|
|
3624
3301
|
ajv.compile(definition.schemaJson);
|
|
3625
3302
|
} catch {
|
|
3626
3303
|
context.addIssue({
|
|
3627
|
-
code:
|
|
3304
|
+
code: z8.ZodIssueCode.custom,
|
|
3628
3305
|
message: "schemaJson must be an executable JSON Schema supported by SiteOS Forms.",
|
|
3629
3306
|
path: ["schemaJson"]
|
|
3630
3307
|
});
|
|
@@ -3633,7 +3310,7 @@ var definitionSyncInputSchema = z10.object({
|
|
|
3633
3310
|
const duplicateKeys = fields.map((field) => field.key).filter((key, index, keys) => keys.indexOf(key) !== index);
|
|
3634
3311
|
for (const key of new Set(duplicateKeys)) {
|
|
3635
3312
|
context.addIssue({
|
|
3636
|
-
code:
|
|
3313
|
+
code: z8.ZodIssueCode.custom,
|
|
3637
3314
|
message: `Field key "${key}" is registered more than once.`,
|
|
3638
3315
|
path: ["normalizedFieldsJson"]
|
|
3639
3316
|
});
|
|
@@ -3643,7 +3320,7 @@ var definitionSyncInputSchema = z10.object({
|
|
|
3643
3320
|
);
|
|
3644
3321
|
if (primaryFields.length !== 1) {
|
|
3645
3322
|
context.addIssue({
|
|
3646
|
-
code:
|
|
3323
|
+
code: z8.ZodIssueCode.custom,
|
|
3647
3324
|
message: "Exactly one managed field must use the primary display role.",
|
|
3648
3325
|
path: ["normalizedFieldsJson"]
|
|
3649
3326
|
});
|
|
@@ -3651,7 +3328,7 @@ var definitionSyncInputSchema = z10.object({
|
|
|
3651
3328
|
const schemaProperties = definition.schemaJson.properties;
|
|
3652
3329
|
if (!isRecord(schemaProperties)) {
|
|
3653
3330
|
context.addIssue({
|
|
3654
|
-
code:
|
|
3331
|
+
code: z8.ZodIssueCode.custom,
|
|
3655
3332
|
message: "schemaJson.properties must define the managed form fields.",
|
|
3656
3333
|
path: ["schemaJson", "properties"]
|
|
3657
3334
|
});
|
|
@@ -3661,7 +3338,7 @@ var definitionSyncInputSchema = z10.object({
|
|
|
3661
3338
|
for (const key of Object.keys(schemaProperties)) {
|
|
3662
3339
|
if (!metadataKeys.has(key)) {
|
|
3663
3340
|
context.addIssue({
|
|
3664
|
-
code:
|
|
3341
|
+
code: z8.ZodIssueCode.custom,
|
|
3665
3342
|
message: `Schema field "${key}" is missing managed field metadata.`,
|
|
3666
3343
|
path: ["normalizedFieldsJson"]
|
|
3667
3344
|
});
|
|
@@ -3670,7 +3347,7 @@ var definitionSyncInputSchema = z10.object({
|
|
|
3670
3347
|
for (const [index, field] of fields.entries()) {
|
|
3671
3348
|
if (!Object.prototype.hasOwnProperty.call(schemaProperties, field.key)) {
|
|
3672
3349
|
context.addIssue({
|
|
3673
|
-
code:
|
|
3350
|
+
code: z8.ZodIssueCode.custom,
|
|
3674
3351
|
message: `Managed field "${field.key}" is missing from schemaJson.properties.`,
|
|
3675
3352
|
path: ["normalizedFieldsJson", index, "key"]
|
|
3676
3353
|
});
|
|
@@ -3680,33 +3357,27 @@ var definitionSyncInputSchema = z10.object({
|
|
|
3680
3357
|
const requiredFields = definition.schemaJson.required;
|
|
3681
3358
|
if (primaryField && (!Array.isArray(requiredFields) || !requiredFields.includes(primaryField.key))) {
|
|
3682
3359
|
context.addIssue({
|
|
3683
|
-
code:
|
|
3360
|
+
code: z8.ZodIssueCode.custom,
|
|
3684
3361
|
message: `Primary display field "${primaryField.key}" must be required by schemaJson.`,
|
|
3685
3362
|
path: ["schemaJson", "required"]
|
|
3686
3363
|
});
|
|
3687
3364
|
}
|
|
3688
3365
|
});
|
|
3689
|
-
var definitionManifestSchema =
|
|
3690
|
-
version:
|
|
3691
|
-
forms:
|
|
3366
|
+
var definitionManifestSchema = z8.object({
|
|
3367
|
+
version: z8.literal(1),
|
|
3368
|
+
forms: z8.array(z8.string().trim().min(1)).min(1)
|
|
3692
3369
|
});
|
|
3693
|
-
var submitInputSchema =
|
|
3694
|
-
formKey:
|
|
3695
|
-
idempotencyKey:
|
|
3696
|
-
ipAddress:
|
|
3697
|
-
payload:
|
|
3698
|
-
sourceUrl:
|
|
3699
|
-
userAgent:
|
|
3370
|
+
var submitInputSchema = z8.object({
|
|
3371
|
+
formKey: z8.string().trim().min(1),
|
|
3372
|
+
idempotencyKey: z8.string().trim().min(1),
|
|
3373
|
+
ipAddress: z8.string().trim().min(1).optional(),
|
|
3374
|
+
payload: z8.record(z8.unknown()),
|
|
3375
|
+
sourceUrl: z8.string().trim().min(1).optional(),
|
|
3376
|
+
userAgent: z8.string().trim().min(1).optional()
|
|
3700
3377
|
}).passthrough();
|
|
3701
|
-
var environmentNameSchema =
|
|
3702
|
-
var projectSlugSchema =
|
|
3378
|
+
var environmentNameSchema = z8.string().transform((value) => value.trim()).refine((value) => value.length >= 1 && value.length <= 255);
|
|
3379
|
+
var projectSlugSchema = z8.string().trim().min(1).max(120).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
|
|
3703
3380
|
var FORMS_HELP = `Usage:
|
|
3704
|
-
siteos forms project list [--json]
|
|
3705
|
-
siteos forms project create --slug <slug> --name <name> [--json]
|
|
3706
|
-
siteos forms project use <slug> [--replace] [--json]
|
|
3707
|
-
siteos forms project status [--json]
|
|
3708
|
-
siteos forms environment list [--json]
|
|
3709
|
-
siteos forms environment create --slug <slug> --name <name> [--json]
|
|
3710
3381
|
siteos forms definition sync --environment <slug> --input <path> [--json]
|
|
3711
3382
|
siteos forms definition sync --environment <slug> --manifest <path> [--json]
|
|
3712
3383
|
siteos forms definition list --environment <slug> [--status <active|inactive|all>] [--json]
|
|
@@ -3720,7 +3391,6 @@ var FORMS_HELP = `Usage:
|
|
|
3720
3391
|
siteos forms credential issue --environment <slug> --install [--name <name>] [--json]
|
|
3721
3392
|
siteos forms credential rotate --environment <slug> --install [--name <name>] [--json]
|
|
3722
3393
|
siteos forms credential revoke --environment <slug> --credential <credential-id> [--json]
|
|
3723
|
-
siteos forms credentials issue --environment <slug> [--name <name>] [--json]
|
|
3724
3394
|
siteos forms submissions list --environment <slug> --form <form-id> [--query <text>] [--status <status>] [--from <ISO>] [--to <ISO>] [--limit <1-100>] [--cursor <cursor>] [--json]
|
|
3725
3395
|
siteos forms submissions read --environment <slug> --form <form-id> --submission <id> [--json]
|
|
3726
3396
|
siteos forms submissions status --environment <slug> --form <form-id> --submission <id> --status <new|read|archived|spam> --expected-status <status> [--json]
|
|
@@ -3739,12 +3409,26 @@ async function runFormsCommand(options) {
|
|
|
3739
3409
|
stdout: FORMS_HELP
|
|
3740
3410
|
};
|
|
3741
3411
|
}
|
|
3412
|
+
const environmentFlags = args2.flatMap(
|
|
3413
|
+
(arg) => arg.startsWith("--environment=") ? ["--environment", arg.slice(14)] : [arg]
|
|
3414
|
+
);
|
|
3415
|
+
const environmentIndex = environmentFlags.indexOf("--environment");
|
|
3416
|
+
options = {
|
|
3417
|
+
...options,
|
|
3418
|
+
selectedEnvironment: environmentIndex >= 0 ? environmentFlags[environmentIndex + 1] : void 0
|
|
3419
|
+
};
|
|
3420
|
+
if (["project", "environment"].includes(args2[0] ?? ""))
|
|
3421
|
+
return usageError2(
|
|
3422
|
+
"Use `siteos project` to manage Projects and environments."
|
|
3423
|
+
);
|
|
3742
3424
|
if (args2[0] === "deploy")
|
|
3743
3425
|
return runDeployment({ ...options, args: args2.slice(1) });
|
|
3744
|
-
if (args2[0] !== "submit"
|
|
3426
|
+
if (args2[0] !== "submit") {
|
|
3745
3427
|
try {
|
|
3746
3428
|
args2 = await commonEnvironmentArguments(options, "forms", args2);
|
|
3747
3429
|
} catch (error) {
|
|
3430
|
+
if (error instanceof SiteOSAuthApiError)
|
|
3431
|
+
return formatAuthError(error).error;
|
|
3748
3432
|
return {
|
|
3749
3433
|
exitCode: 1,
|
|
3750
3434
|
stderr: error instanceof Error ? error.message : "Environment could not be selected."
|
|
@@ -3759,18 +3443,6 @@ async function runFormsCommand(options) {
|
|
|
3759
3443
|
args: args2.slice(1)
|
|
3760
3444
|
});
|
|
3761
3445
|
}
|
|
3762
|
-
if (args2[0] === "environment") {
|
|
3763
|
-
return runEnvironmentCommand({
|
|
3764
|
-
...options,
|
|
3765
|
-
args: args2.slice(1)
|
|
3766
|
-
});
|
|
3767
|
-
}
|
|
3768
|
-
if (args2[0] === "project") {
|
|
3769
|
-
return runProjectCommand({
|
|
3770
|
-
...options,
|
|
3771
|
-
args: args2.slice(1)
|
|
3772
|
-
});
|
|
3773
|
-
}
|
|
3774
3446
|
if (args2[0] === "submit") {
|
|
3775
3447
|
return runSubmit({
|
|
3776
3448
|
...options,
|
|
@@ -3790,17 +3462,6 @@ async function runFormsCommand(options) {
|
|
|
3790
3462
|
args: args2.slice(1)
|
|
3791
3463
|
});
|
|
3792
3464
|
}
|
|
3793
|
-
if (args2[0] === "credentials" && args2[1] === "issue") {
|
|
3794
|
-
const compatibilityArgs = args2.slice(2);
|
|
3795
|
-
return runCredentialCommand({
|
|
3796
|
-
...options,
|
|
3797
|
-
args: [
|
|
3798
|
-
"issue",
|
|
3799
|
-
...compatibilityArgs,
|
|
3800
|
-
...compatibilityArgs.includes(INSTALL_FLAG) ? [] : [INSTALL_FLAG]
|
|
3801
|
-
]
|
|
3802
|
-
});
|
|
3803
|
-
}
|
|
3804
3465
|
return usageError2("Unknown SiteOS forms command.");
|
|
3805
3466
|
}
|
|
3806
3467
|
async function runSubmissionsCommand(options) {
|
|
@@ -3850,7 +3511,7 @@ async function runSubmissionsCommand(options) {
|
|
|
3850
3511
|
if ((value("query")?.length ?? 0) > 200 || (value("cursor")?.length ?? 0) > 2048)
|
|
3851
3512
|
return usageError2("The query or cursor is too long.");
|
|
3852
3513
|
for (const key of ["from", "to"])
|
|
3853
|
-
if (value(key) && !
|
|
3514
|
+
if (value(key) && !z8.string().datetime({ offset: true }).safeParse(value(key)).success)
|
|
3854
3515
|
return usageError2(
|
|
3855
3516
|
`--${key} must be an ISO timestamp including a timezone.`
|
|
3856
3517
|
);
|
|
@@ -3872,7 +3533,7 @@ async function runSubmissionsCommand(options) {
|
|
|
3872
3533
|
);
|
|
3873
3534
|
if (!environment)
|
|
3874
3535
|
return usageError2(
|
|
3875
|
-
"The selected Forms Environment does not exist. Run
|
|
3536
|
+
"The selected Forms Environment does not exist. Run siteos project environment list."
|
|
3876
3537
|
);
|
|
3877
3538
|
const input = {
|
|
3878
3539
|
grant: context.grant,
|
|
@@ -3893,277 +3554,56 @@ async function runSubmissionsCommand(options) {
|
|
|
3893
3554
|
return formatApiError(error);
|
|
3894
3555
|
}
|
|
3895
3556
|
}
|
|
3896
|
-
async function
|
|
3557
|
+
async function runCredentialCommand(options) {
|
|
3897
3558
|
const action = options.args[0];
|
|
3898
|
-
if (!action || !["
|
|
3899
|
-
return usageError2("Unknown SiteOS forms
|
|
3559
|
+
if (!action || !["issue", "list", "revoke", "rotate"].includes(action)) {
|
|
3560
|
+
return usageError2("Unknown SiteOS forms credential command.");
|
|
3900
3561
|
}
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
return formatApiError(
|
|
3905
|
-
new SiteOSFormsApiError({
|
|
3906
|
-
code: "FORMS_UNAVAILABLE",
|
|
3907
|
-
message: "SiteOS Forms access is unavailable in this runtime."
|
|
3908
|
-
})
|
|
3562
|
+
if (options.deployment && action === "rotate")
|
|
3563
|
+
return usageError2(
|
|
3564
|
+
"Issue a new deployment key, update the release secret, then revoke the old key."
|
|
3909
3565
|
);
|
|
3910
|
-
|
|
3566
|
+
const variable = options.deployment ? SITEOS_FORMS_DEPLOYMENT_KEY_ENV : SITEOS_FORMS_SUBMISSION_CREDENTIAL_ENV;
|
|
3567
|
+
const parsed = parseCredentialFlags(action, options.args.slice(1));
|
|
3568
|
+
if (!parsed.ok) return parsed.error;
|
|
3569
|
+
const context = await loadCredentialManagementContext({
|
|
3570
|
+
...options,
|
|
3571
|
+
install: parsed.install
|
|
3572
|
+
});
|
|
3573
|
+
if (!context.ok) return context.error;
|
|
3911
3574
|
try {
|
|
3912
|
-
const apiBaseUrl = resolveSiteOSFormsBaseUrl(options.env);
|
|
3913
|
-
const grant = await serviceGrantProvider(options).acquire({
|
|
3914
|
-
audience: "siteos-forms",
|
|
3915
|
-
scopes: ["forms:workspace:write"]
|
|
3916
|
-
});
|
|
3917
|
-
requireGrant(grant, "forms:workspace:write");
|
|
3918
|
-
const client = createSiteOSFormsApiClient({
|
|
3919
|
-
apiBaseUrl,
|
|
3920
|
-
fetchImpl: options.fetchImpl
|
|
3921
|
-
});
|
|
3922
3575
|
if (action === "list") {
|
|
3923
|
-
const response = await client.
|
|
3924
|
-
|
|
3576
|
+
const response = await context.client.listCredentials({
|
|
3577
|
+
environmentSlug: parsed.environmentSlug,
|
|
3578
|
+
grant: context.grant,
|
|
3579
|
+
projectId: context.project.id
|
|
3580
|
+
});
|
|
3581
|
+
const output2 = {
|
|
3582
|
+
credentials: response.tokens,
|
|
3583
|
+
environment: parsed.environmentSlug
|
|
3584
|
+
};
|
|
3925
3585
|
return {
|
|
3926
3586
|
exitCode: 0,
|
|
3927
|
-
stdout: parsed.json ? stringifySafeJson(
|
|
3587
|
+
stdout: parsed.json ? stringifySafeJson(output2) : formatCredentialListOutput(output2)
|
|
3928
3588
|
};
|
|
3929
3589
|
}
|
|
3930
|
-
if (action === "
|
|
3931
|
-
const
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3590
|
+
if (action === "revoke") {
|
|
3591
|
+
const credential2 = await context.client.revokeCredential({
|
|
3592
|
+
credentialId: parsed.credentialId,
|
|
3593
|
+
environmentSlug: parsed.environmentSlug,
|
|
3594
|
+
grant: context.grant,
|
|
3595
|
+
projectId: context.project.id
|
|
3935
3596
|
});
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3597
|
+
const output2 = {
|
|
3598
|
+
credential: credential2,
|
|
3599
|
+
environment: parsed.environmentSlug,
|
|
3600
|
+
revoked: true
|
|
3601
|
+
};
|
|
3940
3602
|
return {
|
|
3941
3603
|
exitCode: 0,
|
|
3942
|
-
stdout: parsed.json ? stringifySafeJson(
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
`Name: ${response.project.name}`,
|
|
3946
|
-
"Run `siteos forms project use " + response.project.slug + "` to select it for this repository."
|
|
3947
|
-
].join("\n")
|
|
3948
|
-
};
|
|
3949
|
-
}
|
|
3950
|
-
const reference = await inspectFormsProjectReference(
|
|
3951
|
-
options.cwd ?? process.cwd()
|
|
3952
|
-
);
|
|
3953
|
-
const store = projectBindingStore(options);
|
|
3954
|
-
const locator = {
|
|
3955
|
-
apiOrigin: apiBaseUrl,
|
|
3956
|
-
repositoryRoot: reference.rootDir,
|
|
3957
|
-
service: "forms"
|
|
3958
|
-
};
|
|
3959
|
-
if (action === "use") {
|
|
3960
|
-
const response = await client.listProjects({ grant: grant.accessToken });
|
|
3961
|
-
requireProjectOrganization(response.projects, grant.grant.organizationId);
|
|
3962
|
-
const matches = response.projects.filter(
|
|
3963
|
-
(project3) => project3.slug === parsed.slug
|
|
3964
|
-
);
|
|
3965
|
-
if (matches.length !== 1) {
|
|
3966
|
-
throw new SiteOSFormsApiError({
|
|
3967
|
-
code: matches.length === 0 ? "PROJECT_NOT_FOUND" : "INVALID_RESPONSE",
|
|
3968
|
-
message: matches.length === 0 ? "The Forms Project was not found." : "SiteOS Forms returned an invalid response.",
|
|
3969
|
-
status: matches.length === 0 ? 404 : void 0
|
|
3970
|
-
});
|
|
3971
|
-
}
|
|
3972
|
-
const project2 = matches[0];
|
|
3973
|
-
if (reference.status === "loaded" && reference.reference.project.slug !== project2.slug && !parsed.replace) {
|
|
3974
|
-
throw new FormsProjectReferenceError(
|
|
3975
|
-
"FORMS_PROJECT_REFERENCE_CONFLICT",
|
|
3976
|
-
"A different Forms Project is already selected. Use --replace to replace it."
|
|
3977
|
-
);
|
|
3978
|
-
}
|
|
3979
|
-
const previousBinding = await store.read(locator);
|
|
3980
|
-
await store.write({
|
|
3981
|
-
...locator,
|
|
3982
|
-
organizationId: grant.grant.organizationId,
|
|
3983
|
-
project: { id: project2.id, slug: project2.slug }
|
|
3984
|
-
});
|
|
3985
|
-
try {
|
|
3986
|
-
await writeFormsProjectReference({
|
|
3987
|
-
expectedChecksum: reference.status === "loaded" ? reference.checksum : null,
|
|
3988
|
-
project: { name: project2.name, slug: project2.slug },
|
|
3989
|
-
rootDir: reference.rootDir
|
|
3990
|
-
});
|
|
3991
|
-
} catch (error) {
|
|
3992
|
-
if (previousBinding) await store.write(previousBinding);
|
|
3993
|
-
else await store.remove(locator);
|
|
3994
|
-
throw error;
|
|
3995
|
-
}
|
|
3996
|
-
const output2 = {
|
|
3997
|
-
apiOrigin: apiBaseUrl,
|
|
3998
|
-
organizationId: grant.grant.organizationId,
|
|
3999
|
-
project: project2,
|
|
4000
|
-
referencePath: path12.join(
|
|
4001
|
-
reference.rootDir,
|
|
4002
|
-
".siteos",
|
|
4003
|
-
"forms",
|
|
4004
|
-
"project.json"
|
|
4005
|
-
)
|
|
4006
|
-
};
|
|
4007
|
-
return {
|
|
4008
|
-
exitCode: 0,
|
|
4009
|
-
stdout: parsed.json ? stringifySafeJson(output2) : [
|
|
4010
|
-
"SiteOS Forms Project selected.",
|
|
4011
|
-
`Project: ${project2.slug}`,
|
|
4012
|
-
`Reference: ${output2.referencePath}`
|
|
4013
|
-
].join("\n")
|
|
4014
|
-
};
|
|
4015
|
-
}
|
|
4016
|
-
if (reference.status === "missing") {
|
|
4017
|
-
throw new FormsProjectReferenceError(
|
|
4018
|
-
"FORMS_PROJECT_REFERENCE_REQUIRED",
|
|
4019
|
-
"Select a Forms Project for this repository first."
|
|
4020
|
-
);
|
|
4021
|
-
}
|
|
4022
|
-
const binding = await store.read(locator);
|
|
4023
|
-
if (!binding) {
|
|
4024
|
-
throw new FormsProjectReferenceError(
|
|
4025
|
-
"FORMS_PROJECT_REFERENCE_REQUIRED",
|
|
4026
|
-
"Select a Forms Project for this repository first."
|
|
4027
|
-
);
|
|
4028
|
-
}
|
|
4029
|
-
if (binding.organizationId !== grant.grant.organizationId || binding.project.slug !== reference.reference.project.slug) {
|
|
4030
|
-
throw new FormsProjectReferenceError(
|
|
4031
|
-
"FORMS_PROJECT_REFERENCE_INVALID",
|
|
4032
|
-
"The Forms Project reference and private binding do not match."
|
|
4033
|
-
);
|
|
4034
|
-
}
|
|
4035
|
-
const projects = await client.listProjects({ grant: grant.accessToken });
|
|
4036
|
-
requireProjectOrganization(projects.projects, grant.grant.organizationId);
|
|
4037
|
-
const project = projects.projects.find(
|
|
4038
|
-
(candidate) => candidate.id === binding.project.id
|
|
4039
|
-
);
|
|
4040
|
-
if (!project || project.slug !== binding.project.slug) {
|
|
4041
|
-
throw new SiteOSFormsApiError({
|
|
4042
|
-
code: "PROJECT_NOT_FOUND",
|
|
4043
|
-
message: "The Forms Project was not found.",
|
|
4044
|
-
status: 404
|
|
4045
|
-
});
|
|
4046
|
-
}
|
|
4047
|
-
const output = {
|
|
4048
|
-
apiOrigin: apiBaseUrl,
|
|
4049
|
-
connected: true,
|
|
4050
|
-
organizationId: binding.organizationId,
|
|
4051
|
-
project,
|
|
4052
|
-
repositoryRoot: reference.rootDir
|
|
4053
|
-
};
|
|
4054
|
-
return {
|
|
4055
|
-
exitCode: 0,
|
|
4056
|
-
stdout: parsed.json ? stringifySafeJson(output) : [
|
|
4057
|
-
"SiteOS Forms Project connection is valid.",
|
|
4058
|
-
`Project: ${project.slug}`,
|
|
4059
|
-
`Organization: ${binding.organizationId}`,
|
|
4060
|
-
`API: ${apiBaseUrl}`
|
|
4061
|
-
].join("\n")
|
|
4062
|
-
};
|
|
4063
|
-
} catch (error) {
|
|
4064
|
-
return formatProjectError(error);
|
|
4065
|
-
}
|
|
4066
|
-
}
|
|
4067
|
-
async function runEnvironmentCommand(options) {
|
|
4068
|
-
const action = options.args[0];
|
|
4069
|
-
if (!action || !["create", "list"].includes(action)) {
|
|
4070
|
-
return usageError2("Unknown SiteOS forms environment command.");
|
|
4071
|
-
}
|
|
4072
|
-
const parsed = parseEnvironmentFlags(action, options.args.slice(1));
|
|
4073
|
-
if (!parsed.ok) return parsed.error;
|
|
4074
|
-
const context = await loadFormsManagementContext(
|
|
4075
|
-
options,
|
|
4076
|
-
"forms:workspace:write"
|
|
4077
|
-
);
|
|
4078
|
-
if (!context.ok) return context.error;
|
|
4079
|
-
try {
|
|
4080
|
-
if (action === "list") {
|
|
4081
|
-
const response2 = await context.client.listEnvironments({
|
|
4082
|
-
grant: context.grant,
|
|
4083
|
-
projectId: context.project.id
|
|
4084
|
-
});
|
|
4085
|
-
requireEnvironmentProjectConvergence(
|
|
4086
|
-
response2.environments,
|
|
4087
|
-
context.project.id
|
|
4088
|
-
);
|
|
4089
|
-
return {
|
|
4090
|
-
exitCode: 0,
|
|
4091
|
-
stdout: parsed.json ? stringifySafeJson(response2) : formatEnvironmentListOutput(response2.environments)
|
|
4092
|
-
};
|
|
4093
|
-
}
|
|
4094
|
-
const response = await context.client.createEnvironment({
|
|
4095
|
-
grant: context.grant,
|
|
4096
|
-
name: parsed.name,
|
|
4097
|
-
projectId: context.project.id,
|
|
4098
|
-
slug: parsed.slug
|
|
4099
|
-
});
|
|
4100
|
-
requireEnvironmentProjectConvergence(
|
|
4101
|
-
[response.environment],
|
|
4102
|
-
context.project.id
|
|
4103
|
-
);
|
|
4104
|
-
return {
|
|
4105
|
-
exitCode: 0,
|
|
4106
|
-
stdout: parsed.json ? stringifySafeJson(response) : [
|
|
4107
|
-
"SiteOS Forms Environment created.",
|
|
4108
|
-
`Environment: ${response.environment.slug}`,
|
|
4109
|
-
`Name: ${response.environment.name}`,
|
|
4110
|
-
`Project: ${response.environment.projectId}`
|
|
4111
|
-
].join("\n")
|
|
4112
|
-
};
|
|
4113
|
-
} catch (error) {
|
|
4114
|
-
return formatApiError(error);
|
|
4115
|
-
}
|
|
4116
|
-
}
|
|
4117
|
-
async function runCredentialCommand(options) {
|
|
4118
|
-
const action = options.args[0];
|
|
4119
|
-
if (!action || !["issue", "list", "revoke", "rotate"].includes(action)) {
|
|
4120
|
-
return usageError2("Unknown SiteOS forms credential command.");
|
|
4121
|
-
}
|
|
4122
|
-
if (options.deployment && action === "rotate")
|
|
4123
|
-
return usageError2(
|
|
4124
|
-
"Issue a new deployment key, update the release secret, then revoke the old key."
|
|
4125
|
-
);
|
|
4126
|
-
const variable = options.deployment ? SITEOS_FORMS_DEPLOYMENT_KEY_ENV : SITEOS_FORMS_SUBMISSION_CREDENTIAL_ENV;
|
|
4127
|
-
const parsed = parseCredentialFlags(action, options.args.slice(1));
|
|
4128
|
-
if (!parsed.ok) return parsed.error;
|
|
4129
|
-
const context = await loadCredentialManagementContext({
|
|
4130
|
-
...options,
|
|
4131
|
-
install: parsed.install
|
|
4132
|
-
});
|
|
4133
|
-
if (!context.ok) return context.error;
|
|
4134
|
-
try {
|
|
4135
|
-
if (action === "list") {
|
|
4136
|
-
const response = await context.client.listCredentials({
|
|
4137
|
-
environmentSlug: parsed.environmentSlug,
|
|
4138
|
-
grant: context.grant,
|
|
4139
|
-
projectId: context.project.id
|
|
4140
|
-
});
|
|
4141
|
-
const output2 = {
|
|
4142
|
-
credentials: response.tokens,
|
|
4143
|
-
environment: parsed.environmentSlug
|
|
4144
|
-
};
|
|
4145
|
-
return {
|
|
4146
|
-
exitCode: 0,
|
|
4147
|
-
stdout: parsed.json ? stringifySafeJson(output2) : formatCredentialListOutput(output2)
|
|
4148
|
-
};
|
|
4149
|
-
}
|
|
4150
|
-
if (action === "revoke") {
|
|
4151
|
-
const credential2 = await context.client.revokeCredential({
|
|
4152
|
-
credentialId: parsed.credentialId,
|
|
4153
|
-
environmentSlug: parsed.environmentSlug,
|
|
4154
|
-
grant: context.grant,
|
|
4155
|
-
projectId: context.project.id
|
|
4156
|
-
});
|
|
4157
|
-
const output2 = {
|
|
4158
|
-
credential: credential2,
|
|
4159
|
-
environment: parsed.environmentSlug,
|
|
4160
|
-
revoked: true
|
|
4161
|
-
};
|
|
4162
|
-
return {
|
|
4163
|
-
exitCode: 0,
|
|
4164
|
-
stdout: parsed.json ? stringifySafeJson(output2) : `SiteOS Forms credential revoked.
|
|
4165
|
-
Credential: ${credential2.id}
|
|
4166
|
-
Environment: ${parsed.environmentSlug}`
|
|
3604
|
+
stdout: parsed.json ? stringifySafeJson(output2) : `SiteOS Forms credential revoked.
|
|
3605
|
+
Credential: ${credential2.id}
|
|
3606
|
+
Environment: ${parsed.environmentSlug}`
|
|
4167
3607
|
};
|
|
4168
3608
|
}
|
|
4169
3609
|
const previousCredentials = action === "rotate" ? (await context.client.listCredentials({
|
|
@@ -4215,7 +3655,12 @@ Environment: ${parsed.environmentSlug}`
|
|
|
4215
3655
|
async function loadCredentialManagementContext(options) {
|
|
4216
3656
|
try {
|
|
4217
3657
|
const local = await readLocalCommonProject(options);
|
|
4218
|
-
|
|
3658
|
+
if (!local)
|
|
3659
|
+
throw new SiteOSAuthApiError({
|
|
3660
|
+
code: "PROJECT_REQUIRED",
|
|
3661
|
+
message: "Select a Project with `siteos project use <id-or-slug>`."
|
|
3662
|
+
});
|
|
3663
|
+
const rootDir = local.rootDir;
|
|
4219
3664
|
const installation = options.install ? await (options.prepareCredentialInstallation ?? prepareSiteOSFormsCredentialInstallation)({
|
|
4220
3665
|
projectRoot: rootDir,
|
|
4221
3666
|
...options.deployment ? { deployment: true } : {}
|
|
@@ -4242,31 +3687,41 @@ async function loadCredentialManagementContext(options) {
|
|
|
4242
3687
|
}
|
|
4243
3688
|
async function loadFormsManagementContext(options, scope) {
|
|
4244
3689
|
try {
|
|
4245
|
-
const common = await commonServiceContext(
|
|
4246
|
-
|
|
3690
|
+
const common = await commonServiceContext(
|
|
3691
|
+
options,
|
|
3692
|
+
"forms",
|
|
3693
|
+
options.selectedEnvironment
|
|
3694
|
+
);
|
|
3695
|
+
if (!common)
|
|
3696
|
+
throw new SiteOSAuthApiError({
|
|
3697
|
+
code: "PROJECT_REQUIRED",
|
|
3698
|
+
message: "Select a Project with `siteos project use <id-or-slug>`."
|
|
3699
|
+
});
|
|
3700
|
+
{
|
|
4247
3701
|
if (!options.fetchImpl)
|
|
4248
3702
|
throw new SiteOSAuthApiError({
|
|
4249
3703
|
code: "AUTH_UNAVAILABLE",
|
|
4250
3704
|
message: "SiteOS API access is unavailable."
|
|
4251
3705
|
});
|
|
4252
|
-
const
|
|
3706
|
+
const grant = await serviceGrantProvider(options).acquire({
|
|
4253
3707
|
audience: "siteos-forms",
|
|
4254
3708
|
scopes: [scope]
|
|
4255
3709
|
});
|
|
4256
|
-
requireGrant(
|
|
4257
|
-
if (
|
|
3710
|
+
requireGrant(grant, scope);
|
|
3711
|
+
if (grant.grant.organizationId !== common.overview.project.organizationId)
|
|
4258
3712
|
throw new SiteOSAuthApiError({
|
|
4259
3713
|
code: "PROJECT_ORGANIZATION_MISMATCH",
|
|
4260
3714
|
message: "The Project and service grant belong to different organizations."
|
|
4261
3715
|
});
|
|
4262
3716
|
return {
|
|
4263
3717
|
commonProjectId: common.overview.project.id,
|
|
3718
|
+
environmentSlug: common.environment.slug,
|
|
4264
3719
|
apiBaseUrl: common.api.origin,
|
|
4265
3720
|
client: createSiteOSFormsApiClient({
|
|
4266
3721
|
apiBaseUrl: common.api.origin,
|
|
4267
3722
|
fetchImpl: options.fetchImpl
|
|
4268
3723
|
}),
|
|
4269
|
-
grant:
|
|
3724
|
+
grant: grant.accessToken,
|
|
4270
3725
|
ok: true,
|
|
4271
3726
|
organization: { id: common.overview.project.organizationId },
|
|
4272
3727
|
project: {
|
|
@@ -4277,73 +3732,10 @@ async function loadFormsManagementContext(options, scope) {
|
|
|
4277
3732
|
rootDir: common.rootDir
|
|
4278
3733
|
};
|
|
4279
3734
|
}
|
|
4280
|
-
const reference = await requireFormsProjectReference(
|
|
4281
|
-
options.cwd ?? process.cwd()
|
|
4282
|
-
);
|
|
4283
|
-
if (!options.fetchImpl) {
|
|
4284
|
-
throw new SiteOSFormsApiError({
|
|
4285
|
-
code: "FORMS_UNAVAILABLE",
|
|
4286
|
-
message: "SiteOS Forms access is unavailable in this runtime."
|
|
4287
|
-
});
|
|
4288
|
-
}
|
|
4289
|
-
const apiBaseUrl = resolveSiteOSFormsBaseUrl(options.env);
|
|
4290
|
-
const binding = await projectBindingStore(options).read({
|
|
4291
|
-
apiOrigin: apiBaseUrl,
|
|
4292
|
-
repositoryRoot: reference.rootDir,
|
|
4293
|
-
service: "forms"
|
|
4294
|
-
});
|
|
4295
|
-
if (!binding) {
|
|
4296
|
-
throw new FormsProjectReferenceError(
|
|
4297
|
-
"FORMS_PROJECT_REFERENCE_REQUIRED",
|
|
4298
|
-
"Select a Forms Project for this repository first."
|
|
4299
|
-
);
|
|
4300
|
-
}
|
|
4301
|
-
const grant = await serviceGrantProvider(options).acquire({
|
|
4302
|
-
audience: "siteos-forms",
|
|
4303
|
-
scopes: [scope]
|
|
4304
|
-
});
|
|
4305
|
-
if (grant.grant.audience !== "siteos-forms" || grant.grant.scopes.length !== 1 || grant.grant.scopes[0] !== scope) {
|
|
4306
|
-
throw new SiteOSAuthApiError({
|
|
4307
|
-
code: "AUTH_INVALID_RESPONSE",
|
|
4308
|
-
message: "The SiteOS Auth service returned an invalid response."
|
|
4309
|
-
});
|
|
4310
|
-
}
|
|
4311
|
-
if (grant.grant.organizationId !== binding.organizationId || binding.project.slug !== reference.reference.project.slug) {
|
|
4312
|
-
throw new SiteOSAuthApiError({
|
|
4313
|
-
code: "AUTH_INVALID_RESPONSE",
|
|
4314
|
-
message: "The selected Forms Project does not match this Auth Organization."
|
|
4315
|
-
});
|
|
4316
|
-
}
|
|
4317
|
-
return {
|
|
4318
|
-
apiBaseUrl,
|
|
4319
|
-
client: createSiteOSFormsApiClient({
|
|
4320
|
-
apiBaseUrl,
|
|
4321
|
-
fetchImpl: options.fetchImpl
|
|
4322
|
-
}),
|
|
4323
|
-
grant: grant.accessToken,
|
|
4324
|
-
ok: true,
|
|
4325
|
-
organization: { id: binding.organizationId },
|
|
4326
|
-
project: {
|
|
4327
|
-
id: binding.project.id,
|
|
4328
|
-
name: reference.reference.project.name,
|
|
4329
|
-
slug: binding.project.slug
|
|
4330
|
-
},
|
|
4331
|
-
rootDir: reference.rootDir
|
|
4332
|
-
};
|
|
4333
3735
|
} catch (error) {
|
|
4334
3736
|
return { error: formatManagementContextError(error), ok: false };
|
|
4335
3737
|
}
|
|
4336
3738
|
}
|
|
4337
|
-
async function requireFormsProjectReference(cwd) {
|
|
4338
|
-
const reference = await inspectFormsProjectReference(cwd);
|
|
4339
|
-
if (reference.status === "missing") {
|
|
4340
|
-
throw new FormsProjectReferenceError(
|
|
4341
|
-
"FORMS_PROJECT_REFERENCE_REQUIRED",
|
|
4342
|
-
"Select a Forms Project for this repository first."
|
|
4343
|
-
);
|
|
4344
|
-
}
|
|
4345
|
-
return reference;
|
|
4346
|
-
}
|
|
4347
3739
|
async function runDefinitionCommand(options) {
|
|
4348
3740
|
if (["list", "read", "archive", "restore", "delete"].includes(
|
|
4349
3741
|
options.args[0] ?? ""
|
|
@@ -4421,7 +3813,7 @@ async function runDefinitionLifecycle(options) {
|
|
|
4421
3813
|
);
|
|
4422
3814
|
if (!environment)
|
|
4423
3815
|
return usageError2(
|
|
4424
|
-
"The selected Forms Environment does not exist. Run
|
|
3816
|
+
"The selected Forms Environment does not exist. Run siteos project environment list."
|
|
4425
3817
|
);
|
|
4426
3818
|
const input = {
|
|
4427
3819
|
grant: context.grant,
|
|
@@ -4647,41 +4039,20 @@ async function loadSubmissionFormsContext(options) {
|
|
|
4647
4039
|
}
|
|
4648
4040
|
try {
|
|
4649
4041
|
const common = await readLocalCommonProject(options);
|
|
4650
|
-
if (common)
|
|
4042
|
+
if (common && common.binding.environmentSlug)
|
|
4651
4043
|
return {
|
|
4652
4044
|
apiBaseUrl: common.api.origin,
|
|
4653
4045
|
commonProjectId: common.binding.project.id,
|
|
4046
|
+
environmentSlug: common.binding.environmentSlug,
|
|
4654
4047
|
ok: true,
|
|
4655
4048
|
organization: { id: common.binding.organizationId },
|
|
4656
4049
|
project: { slug: common.binding.project.slug },
|
|
4657
4050
|
credential
|
|
4658
4051
|
};
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
const apiBaseUrl = resolveSiteOSFormsBaseUrl(options.env);
|
|
4663
|
-
const binding = await projectBindingStore(options).read({
|
|
4664
|
-
apiOrigin: apiBaseUrl,
|
|
4665
|
-
repositoryRoot: reference.rootDir,
|
|
4666
|
-
service: "forms"
|
|
4052
|
+
throw new SiteOSAuthApiError({
|
|
4053
|
+
code: "PROJECT_REQUIRED",
|
|
4054
|
+
message: "Select a Project with `siteos project use <id-or-slug>`."
|
|
4667
4055
|
});
|
|
4668
|
-
if (!binding || binding.project.slug !== reference.reference.project.slug) {
|
|
4669
|
-
throw new FormsProjectReferenceError(
|
|
4670
|
-
binding ? "FORMS_PROJECT_REFERENCE_INVALID" : "FORMS_PROJECT_REFERENCE_REQUIRED",
|
|
4671
|
-
binding ? "The Forms Project reference and private binding do not match." : "Select a Forms Project for this repository first."
|
|
4672
|
-
);
|
|
4673
|
-
}
|
|
4674
|
-
return {
|
|
4675
|
-
apiBaseUrl,
|
|
4676
|
-
ok: true,
|
|
4677
|
-
organization: { id: binding.organizationId },
|
|
4678
|
-
project: {
|
|
4679
|
-
id: binding.project.id,
|
|
4680
|
-
name: reference.reference.project.name,
|
|
4681
|
-
slug: binding.project.slug
|
|
4682
|
-
},
|
|
4683
|
-
credential
|
|
4684
|
-
};
|
|
4685
4056
|
} catch (error) {
|
|
4686
4057
|
return { error: formatManagementContextError(error), ok: false };
|
|
4687
4058
|
}
|
|
@@ -4709,76 +4080,6 @@ function formatAuthError(error) {
|
|
|
4709
4080
|
ok: false
|
|
4710
4081
|
};
|
|
4711
4082
|
}
|
|
4712
|
-
function parseProjectFlags(action, args2) {
|
|
4713
|
-
const creates = action === "create";
|
|
4714
|
-
const uses = action === "use";
|
|
4715
|
-
const parsed = parseFlags(args2, {
|
|
4716
|
-
allowed: /* @__PURE__ */ new Set([
|
|
4717
|
-
JSON_FLAG,
|
|
4718
|
-
...creates ? [NAME_FLAG, SLUG_FLAG] : [],
|
|
4719
|
-
...uses ? [REPLACE_FLAG] : []
|
|
4720
|
-
]),
|
|
4721
|
-
boolean: /* @__PURE__ */ new Set([JSON_FLAG, REPLACE_FLAG]),
|
|
4722
|
-
rejectDuplicates: true
|
|
4723
|
-
});
|
|
4724
|
-
if (!parsed.ok) return { error: usageError2(parsed.error), ok: false };
|
|
4725
|
-
if (uses) {
|
|
4726
|
-
if (parsed.positionals.length !== 1) {
|
|
4727
|
-
return {
|
|
4728
|
-
error: usageError2("Project use requires exactly one Project slug."),
|
|
4729
|
-
ok: false
|
|
4730
|
-
};
|
|
4731
|
-
}
|
|
4732
|
-
const slug3 = projectSlugSchema.safeParse(parsed.positionals[0]);
|
|
4733
|
-
if (!slug3.success) {
|
|
4734
|
-
return { error: usageError2("Project slug is invalid."), ok: false };
|
|
4735
|
-
}
|
|
4736
|
-
return {
|
|
4737
|
-
json: parsed.flags.has(JSON_FLAG),
|
|
4738
|
-
ok: true,
|
|
4739
|
-
replace: parsed.flags.has(REPLACE_FLAG),
|
|
4740
|
-
slug: slug3.data
|
|
4741
|
-
};
|
|
4742
|
-
}
|
|
4743
|
-
if (parsed.positionals.length > 0) {
|
|
4744
|
-
return {
|
|
4745
|
-
error: usageError2(`Unexpected argument: ${parsed.positionals[0]}`),
|
|
4746
|
-
ok: false
|
|
4747
|
-
};
|
|
4748
|
-
}
|
|
4749
|
-
if (!creates) {
|
|
4750
|
-
return {
|
|
4751
|
-
json: parsed.flags.has(JSON_FLAG),
|
|
4752
|
-
ok: true,
|
|
4753
|
-
replace: false
|
|
4754
|
-
};
|
|
4755
|
-
}
|
|
4756
|
-
const slug2 = projectSlugSchema.safeParse(
|
|
4757
|
-
readStringFlag(parsed.flags, SLUG_FLAG)
|
|
4758
|
-
);
|
|
4759
|
-
const name = environmentNameSchema.safeParse(
|
|
4760
|
-
readStringFlag(parsed.flags, NAME_FLAG)
|
|
4761
|
-
);
|
|
4762
|
-
if (!slug2.success) {
|
|
4763
|
-
return {
|
|
4764
|
-
error: usageError2("--slug is required and must be valid."),
|
|
4765
|
-
ok: false
|
|
4766
|
-
};
|
|
4767
|
-
}
|
|
4768
|
-
if (!name.success) {
|
|
4769
|
-
return {
|
|
4770
|
-
error: usageError2("--name is required and must be valid."),
|
|
4771
|
-
ok: false
|
|
4772
|
-
};
|
|
4773
|
-
}
|
|
4774
|
-
return {
|
|
4775
|
-
json: parsed.flags.has(JSON_FLAG),
|
|
4776
|
-
name: name.data,
|
|
4777
|
-
ok: true,
|
|
4778
|
-
replace: false,
|
|
4779
|
-
slug: slug2.data
|
|
4780
|
-
};
|
|
4781
|
-
}
|
|
4782
4083
|
function parseCredentialFlags(action, args2) {
|
|
4783
4084
|
const installs = action === "issue" || action === "rotate";
|
|
4784
4085
|
const revokes = action === "revoke";
|
|
@@ -4847,48 +4148,6 @@ function parseCredentialFlags(action, args2) {
|
|
|
4847
4148
|
ok: true
|
|
4848
4149
|
};
|
|
4849
4150
|
}
|
|
4850
|
-
function parseEnvironmentFlags(action, args2) {
|
|
4851
|
-
const creates = action === "create";
|
|
4852
|
-
const parsed = parseFlags(args2, {
|
|
4853
|
-
allowed: /* @__PURE__ */ new Set([JSON_FLAG, ...creates ? [NAME_FLAG, SLUG_FLAG] : []]),
|
|
4854
|
-
boolean: /* @__PURE__ */ new Set([JSON_FLAG]),
|
|
4855
|
-
rejectDuplicates: true
|
|
4856
|
-
});
|
|
4857
|
-
if (!parsed.ok) return { error: usageError2(parsed.error), ok: false };
|
|
4858
|
-
if (parsed.positionals.length > 0) {
|
|
4859
|
-
return {
|
|
4860
|
-
error: usageError2(`Unexpected argument: ${parsed.positionals[0]}`),
|
|
4861
|
-
ok: false
|
|
4862
|
-
};
|
|
4863
|
-
}
|
|
4864
|
-
if (!creates) {
|
|
4865
|
-
return { json: parsed.flags.has(JSON_FLAG), ok: true };
|
|
4866
|
-
}
|
|
4867
|
-
const slug2 = readStringFlag(parsed.flags, SLUG_FLAG);
|
|
4868
|
-
if (!slug2) {
|
|
4869
|
-
return { error: usageError2("--slug is required."), ok: false };
|
|
4870
|
-
}
|
|
4871
|
-
if (!isValidEnvironmentSlug(slug2)) {
|
|
4872
|
-
return {
|
|
4873
|
-
error: usageError2("--slug must be a valid environment slug."),
|
|
4874
|
-
ok: false
|
|
4875
|
-
};
|
|
4876
|
-
}
|
|
4877
|
-
const name = readStringFlag(parsed.flags, NAME_FLAG);
|
|
4878
|
-
if (!name) {
|
|
4879
|
-
return { error: usageError2("--name is required."), ok: false };
|
|
4880
|
-
}
|
|
4881
|
-
const parsedName = environmentNameSchema.safeParse(name);
|
|
4882
|
-
if (!parsedName.success) {
|
|
4883
|
-
return { error: usageError2("--name is invalid."), ok: false };
|
|
4884
|
-
}
|
|
4885
|
-
return {
|
|
4886
|
-
json: parsed.flags.has(JSON_FLAG),
|
|
4887
|
-
name: parsedName.data,
|
|
4888
|
-
ok: true,
|
|
4889
|
-
slug: slug2
|
|
4890
|
-
};
|
|
4891
|
-
}
|
|
4892
4151
|
function parseDefinitionSourceFlags(args2, options) {
|
|
4893
4152
|
const parsed = parseFlags(args2, {
|
|
4894
4153
|
allowed: /* @__PURE__ */ new Set([
|
|
@@ -4959,7 +4218,7 @@ async function loadFormDefinitions(options) {
|
|
|
4959
4218
|
ok: true
|
|
4960
4219
|
};
|
|
4961
4220
|
}
|
|
4962
|
-
const manifestPath =
|
|
4221
|
+
const manifestPath = path10.resolve(
|
|
4963
4222
|
options.cwd ?? process.cwd(),
|
|
4964
4223
|
options.source.path
|
|
4965
4224
|
);
|
|
@@ -4969,10 +4228,10 @@ async function loadFormDefinitions(options) {
|
|
|
4969
4228
|
schema: definitionManifestSchema
|
|
4970
4229
|
});
|
|
4971
4230
|
if (!manifest.ok) return manifest;
|
|
4972
|
-
const manifestDirectory =
|
|
4231
|
+
const manifestDirectory = path10.dirname(manifestPath);
|
|
4973
4232
|
const definitions = [];
|
|
4974
4233
|
for (const definitionPath of manifest.value.forms) {
|
|
4975
|
-
if (
|
|
4234
|
+
if (path10.isAbsolute(definitionPath)) {
|
|
4976
4235
|
return {
|
|
4977
4236
|
error: usageError2(
|
|
4978
4237
|
`Manifest definition paths must be relative: ${definitionPath}`
|
|
@@ -4980,9 +4239,9 @@ async function loadFormDefinitions(options) {
|
|
|
4980
4239
|
ok: false
|
|
4981
4240
|
};
|
|
4982
4241
|
}
|
|
4983
|
-
const resolvedPath =
|
|
4984
|
-
const relativePath =
|
|
4985
|
-
if (relativePath.startsWith(`..${
|
|
4242
|
+
const resolvedPath = path10.resolve(manifestDirectory, definitionPath);
|
|
4243
|
+
const relativePath = path10.relative(manifestDirectory, resolvedPath);
|
|
4244
|
+
if (relativePath.startsWith(`..${path10.sep}`) || relativePath === "..") {
|
|
4986
4245
|
return {
|
|
4987
4246
|
error: usageError2(
|
|
4988
4247
|
`Manifest definition paths must stay inside the manifest directory: ${definitionPath}`
|
|
@@ -5045,7 +4304,7 @@ function parseInputFlags(args2, options) {
|
|
|
5045
4304
|
};
|
|
5046
4305
|
}
|
|
5047
4306
|
async function readInputFile(options) {
|
|
5048
|
-
const resolvedInputPath =
|
|
4307
|
+
const resolvedInputPath = path10.resolve(
|
|
5049
4308
|
options.cwd ?? process.cwd(),
|
|
5050
4309
|
options.inputPath
|
|
5051
4310
|
);
|
|
@@ -5187,7 +4446,7 @@ function formatCredentialError(error) {
|
|
|
5187
4446
|
stderr: error.message
|
|
5188
4447
|
};
|
|
5189
4448
|
}
|
|
5190
|
-
if (error instanceof
|
|
4449
|
+
if (error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
|
|
5191
4450
|
return {
|
|
5192
4451
|
exitCode: 1,
|
|
5193
4452
|
stderr: [
|
|
@@ -5216,7 +4475,7 @@ function formatManagementContextError(error) {
|
|
|
5216
4475
|
if (error instanceof SiteOSAuthApiError) {
|
|
5217
4476
|
return formatAuthError(error).error;
|
|
5218
4477
|
}
|
|
5219
|
-
if (error instanceof
|
|
4478
|
+
if (error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
|
|
5220
4479
|
return {
|
|
5221
4480
|
exitCode: 1,
|
|
5222
4481
|
stderr: [
|
|
@@ -5228,24 +4487,12 @@ function formatManagementContextError(error) {
|
|
|
5228
4487
|
}
|
|
5229
4488
|
return formatApiError(error);
|
|
5230
4489
|
}
|
|
5231
|
-
function formatProjectError(error) {
|
|
5232
|
-
if (error instanceof SiteOSAuthApiError) return formatAuthError(error).error;
|
|
5233
|
-
return formatManagementContextError(error);
|
|
5234
|
-
}
|
|
5235
4490
|
function serviceGrantProvider(options) {
|
|
5236
4491
|
return options.serviceGrantProvider ?? createSiteOSServiceGrantProvider({
|
|
5237
4492
|
env: options.env,
|
|
5238
4493
|
fetchImpl: options.fetchImpl
|
|
5239
4494
|
});
|
|
5240
4495
|
}
|
|
5241
|
-
function projectBindingStore(options) {
|
|
5242
|
-
return options.projectBindingStore ?? new NodeProjectBindingStore(
|
|
5243
|
-
path12.join(
|
|
5244
|
-
resolveSiteOSConfigHome({ env: options.env }),
|
|
5245
|
-
"project-bindings.json"
|
|
5246
|
-
)
|
|
5247
|
-
);
|
|
5248
|
-
}
|
|
5249
4496
|
function requireGrant(grant, scope) {
|
|
5250
4497
|
if (grant.grant.audience !== "siteos-forms" || grant.grant.scopes.length !== 1 || grant.grant.scopes[0] !== scope) {
|
|
5251
4498
|
throw new SiteOSAuthApiError({
|
|
@@ -5254,23 +4501,6 @@ function requireGrant(grant, scope) {
|
|
|
5254
4501
|
});
|
|
5255
4502
|
}
|
|
5256
4503
|
}
|
|
5257
|
-
function requireProjectOrganization(projects, organizationId) {
|
|
5258
|
-
if (projects.some((project) => project.organizationId !== organizationId)) {
|
|
5259
|
-
throw new SiteOSFormsApiError({
|
|
5260
|
-
code: "INVALID_RESPONSE",
|
|
5261
|
-
message: "SiteOS Forms returned an invalid response."
|
|
5262
|
-
});
|
|
5263
|
-
}
|
|
5264
|
-
}
|
|
5265
|
-
function formatProjectListOutput(projects) {
|
|
5266
|
-
return [
|
|
5267
|
-
"SiteOS Forms Projects.",
|
|
5268
|
-
`Projects: ${projects.length}`,
|
|
5269
|
-
...projects.map(
|
|
5270
|
-
(project) => `- ${project.slug}: ${project.name} (${project.id})`
|
|
5271
|
-
)
|
|
5272
|
-
].join("\n");
|
|
5273
|
-
}
|
|
5274
4504
|
function formatCredentialListOutput(input) {
|
|
5275
4505
|
return [
|
|
5276
4506
|
"SiteOS Forms credentials.",
|
|
@@ -5281,15 +4511,6 @@ function formatCredentialListOutput(input) {
|
|
|
5281
4511
|
)
|
|
5282
4512
|
].join("\n");
|
|
5283
4513
|
}
|
|
5284
|
-
function formatEnvironmentListOutput(environments) {
|
|
5285
|
-
return [
|
|
5286
|
-
"SiteOS Forms Environments.",
|
|
5287
|
-
`Environments: ${environments.length}`,
|
|
5288
|
-
...environments.map(
|
|
5289
|
-
(environment) => `- ${environment.slug}: ${environment.name} (${environment.id})`
|
|
5290
|
-
)
|
|
5291
|
-
].join("\n");
|
|
5292
|
-
}
|
|
5293
4514
|
function requireEnvironmentProjectConvergence(environments, projectId) {
|
|
5294
4515
|
if (environments.some((environment) => environment.projectId !== projectId)) {
|
|
5295
4516
|
throw new SiteOSFormsApiError({
|
|
@@ -5322,12 +4543,12 @@ function readOutputString(value) {
|
|
|
5322
4543
|
}
|
|
5323
4544
|
function createFormsUiOutput(input) {
|
|
5324
4545
|
const commonProjectId = input.context.commonProjectId;
|
|
5325
|
-
const projectId = commonProjectId
|
|
4546
|
+
const projectId = commonProjectId;
|
|
5326
4547
|
if (!projectId) {
|
|
5327
4548
|
return void 0;
|
|
5328
4549
|
}
|
|
5329
4550
|
const url = new URL(
|
|
5330
|
-
|
|
4551
|
+
`/projects/${encodeURIComponent(commonProjectId)}/forms?env=${encodeURIComponent(input.context.environmentSlug)}`,
|
|
5331
4552
|
new URL(input.context.apiBaseUrl).origin
|
|
5332
4553
|
).toString();
|
|
5333
4554
|
return {
|
|
@@ -5386,11 +4607,11 @@ async function runDeployment(options) {
|
|
|
5386
4607
|
|
|
5387
4608
|
// src/package-metadata.ts
|
|
5388
4609
|
import { readFileSync } from "fs";
|
|
5389
|
-
import
|
|
4610
|
+
import path11 from "path";
|
|
5390
4611
|
import { fileURLToPath } from "url";
|
|
5391
4612
|
function readPackageMetadata() {
|
|
5392
|
-
const packageJsonPath =
|
|
5393
|
-
|
|
4613
|
+
const packageJsonPath = path11.resolve(
|
|
4614
|
+
path11.dirname(fileURLToPath(import.meta.url)),
|
|
5394
4615
|
"..",
|
|
5395
4616
|
"package.json"
|
|
5396
4617
|
);
|
|
@@ -5404,7 +4625,7 @@ function readPackageMetadata() {
|
|
|
5404
4625
|
}
|
|
5405
4626
|
|
|
5406
4627
|
// src/pulse-command.ts
|
|
5407
|
-
import
|
|
4628
|
+
import path22 from "path";
|
|
5408
4629
|
import { parseArgs } from "util";
|
|
5409
4630
|
|
|
5410
4631
|
// src/core/errors.ts
|
|
@@ -5417,29 +4638,28 @@ function commandError2(input) {
|
|
|
5417
4638
|
|
|
5418
4639
|
// src/pulse/api-client.ts
|
|
5419
4640
|
import { readFile as readFile6 } from "fs/promises";
|
|
5420
|
-
import { z as
|
|
5421
|
-
var projectSchema =
|
|
5422
|
-
baseUrl:
|
|
5423
|
-
checkCount:
|
|
5424
|
-
id:
|
|
5425
|
-
name:
|
|
5426
|
-
slug:
|
|
4641
|
+
import { z as z9 } from "zod";
|
|
4642
|
+
var projectSchema = z9.object({
|
|
4643
|
+
baseUrl: z9.string().url().nullable(),
|
|
4644
|
+
checkCount: z9.number().int().min(0),
|
|
4645
|
+
id: z9.string().trim().min(1).max(120),
|
|
4646
|
+
name: z9.string().trim().min(1).max(120),
|
|
4647
|
+
slug: z9.string().trim().min(1).max(80).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
|
|
5427
4648
|
}).strict();
|
|
5428
|
-
var
|
|
5429
|
-
var
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
version: z11.number().int().positive()
|
|
4649
|
+
var projectResponseSchema = z9.object({ project: projectSchema }).strict();
|
|
4650
|
+
var deploymentResponseSchema2 = z9.object({
|
|
4651
|
+
checks: z9.array(
|
|
4652
|
+
z9.object({
|
|
4653
|
+
checkId: z9.string().min(1),
|
|
4654
|
+
created: z9.boolean(),
|
|
4655
|
+
deploymentId: z9.string().min(1),
|
|
4656
|
+
slug: z9.string().min(1),
|
|
4657
|
+
version: z9.number().int().positive()
|
|
5438
4658
|
}).strict()
|
|
5439
4659
|
),
|
|
5440
|
-
checksum:
|
|
5441
|
-
dashboardUrl:
|
|
5442
|
-
projectId:
|
|
4660
|
+
checksum: z9.string().min(1),
|
|
4661
|
+
dashboardUrl: z9.string().url().nullable().optional(),
|
|
4662
|
+
projectId: z9.string().min(1)
|
|
5443
4663
|
}).strict();
|
|
5444
4664
|
function createPulseApiClient(input) {
|
|
5445
4665
|
const fetchImpl = input.fetchImpl ?? fetch;
|
|
@@ -5461,7 +4681,7 @@ function createPulseApiClient(input) {
|
|
|
5461
4681
|
"API_UNREACHABLE",
|
|
5462
4682
|
`Could not reach ${endpoint.origin}.`,
|
|
5463
4683
|
{
|
|
5464
|
-
hint: "Check
|
|
4684
|
+
hint: "Check SITEOS_AUTH_BASE_URL and the network connection."
|
|
5465
4685
|
}
|
|
5466
4686
|
);
|
|
5467
4687
|
}
|
|
@@ -5477,21 +4697,6 @@ function createPulseApiClient(input) {
|
|
|
5477
4697
|
return parsed.data;
|
|
5478
4698
|
};
|
|
5479
4699
|
return {
|
|
5480
|
-
async createProject(options) {
|
|
5481
|
-
const result = await request({
|
|
5482
|
-
body: JSON.stringify({
|
|
5483
|
-
baseUrl: options.baseUrl,
|
|
5484
|
-
monitoringEnabled: options.monitoringEnabled,
|
|
5485
|
-
name: options.name,
|
|
5486
|
-
slug: options.slug
|
|
5487
|
-
}),
|
|
5488
|
-
grant: options.grant,
|
|
5489
|
-
method: "POST",
|
|
5490
|
-
path: "/api/cli/v1/projects",
|
|
5491
|
-
schema: projectResponseSchema
|
|
5492
|
-
});
|
|
5493
|
-
return result.project;
|
|
5494
|
-
},
|
|
5495
4700
|
async getProject(options) {
|
|
5496
4701
|
const result = await request({
|
|
5497
4702
|
grant: options.grant,
|
|
@@ -5500,14 +4705,6 @@ function createPulseApiClient(input) {
|
|
|
5500
4705
|
});
|
|
5501
4706
|
return result.project;
|
|
5502
4707
|
},
|
|
5503
|
-
async listProjects(options) {
|
|
5504
|
-
const result = await request({
|
|
5505
|
-
grant: options.grant,
|
|
5506
|
-
path: "/api/cli/v1/projects",
|
|
5507
|
-
schema: projectListSchema
|
|
5508
|
-
});
|
|
5509
|
-
return result.projects;
|
|
5510
|
-
},
|
|
5511
4708
|
async uploadDeployment(options) {
|
|
5512
4709
|
const form = new FormData();
|
|
5513
4710
|
const { archivePath: _archivePath, ...publicManifest } = options.manifest;
|
|
@@ -5545,122 +4742,23 @@ function pulseApiError(body, status) {
|
|
|
5545
4742
|
return new CliError(code, message);
|
|
5546
4743
|
}
|
|
5547
4744
|
|
|
5548
|
-
// src/pulse/binding-migration.ts
|
|
5549
|
-
import { createHash as createHash5 } from "crypto";
|
|
5550
|
-
import { lstat as lstat5, readFile as readFile7, realpath as realpath3 } from "fs/promises";
|
|
5551
|
-
import os4 from "os";
|
|
5552
|
-
import path14 from "path";
|
|
5553
|
-
import { z as z12 } from "zod";
|
|
5554
|
-
|
|
5555
|
-
// src/pulse/constants.ts
|
|
5556
|
-
var DEFAULT_SITEOS_PULSE_API_URL = "https://app.siteos.sh";
|
|
5557
|
-
function normalizeApiUrl(value) {
|
|
5558
|
-
let url;
|
|
5559
|
-
try {
|
|
5560
|
-
url = new URL(value);
|
|
5561
|
-
} catch {
|
|
5562
|
-
throw new Error(
|
|
5563
|
-
"SiteOS Pulse API URL must be an absolute HTTP or HTTPS URL."
|
|
5564
|
-
);
|
|
5565
|
-
}
|
|
5566
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
5567
|
-
throw new Error("SiteOS Pulse API URL must use HTTP or HTTPS.");
|
|
5568
|
-
}
|
|
5569
|
-
return url.origin;
|
|
5570
|
-
}
|
|
5571
|
-
|
|
5572
|
-
// src/pulse/binding-migration.ts
|
|
5573
|
-
var legacyBindingSchema = z12.object({
|
|
5574
|
-
apiUrl: z12.string().url(),
|
|
5575
|
-
organizationId: z12.string().trim().min(1).max(255),
|
|
5576
|
-
projectId: z12.string().trim().min(1).max(255),
|
|
5577
|
-
projectRoot: z12.string().refine(path14.isAbsolute),
|
|
5578
|
-
projectSlug: z12.string().trim().min(1).max(80).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
|
|
5579
|
-
}).strict();
|
|
5580
|
-
var legacyBindingsSchema = z12.object({
|
|
5581
|
-
bindings: z12.record(legacyBindingSchema),
|
|
5582
|
-
version: z12.literal(2)
|
|
5583
|
-
}).strict();
|
|
5584
|
-
async function migrateLegacyPulseBinding(input) {
|
|
5585
|
-
const apiOrigin = normalizeApiUrl(input.apiOrigin);
|
|
5586
|
-
const repositoryRoot = await realpath3(path14.resolve(input.repositoryRoot));
|
|
5587
|
-
const locator = { apiOrigin, repositoryRoot, service: "pulse" };
|
|
5588
|
-
const current = await input.projectBindingStore.read(locator);
|
|
5589
|
-
if (current) return { binding: current, status: "already-current" };
|
|
5590
|
-
const legacy = await readLegacyBindings(
|
|
5591
|
-
input.legacyBindingsPath ?? legacyPulseBindingsFilePath()
|
|
5592
|
-
);
|
|
5593
|
-
if (!legacy) return { binding: null, status: "not-found" };
|
|
5594
|
-
const key = legacyBindingKey(apiOrigin, repositoryRoot);
|
|
5595
|
-
const candidate = legacy.bindings[key];
|
|
5596
|
-
if (!candidate || candidate.apiUrl !== apiOrigin || candidate.projectRoot !== repositoryRoot || candidate.organizationId !== input.organizationId || candidate.projectSlug !== input.projectSlug) {
|
|
5597
|
-
return { binding: null, status: "not-found" };
|
|
5598
|
-
}
|
|
5599
|
-
const imported = await input.projectBindingStore.write({
|
|
5600
|
-
...locator,
|
|
5601
|
-
organizationId: candidate.organizationId,
|
|
5602
|
-
project: { id: candidate.projectId, slug: candidate.projectSlug }
|
|
5603
|
-
});
|
|
5604
|
-
const readBack = await input.projectBindingStore.read(locator);
|
|
5605
|
-
if (!readBack || readBack.project.id !== imported.project.id) {
|
|
5606
|
-
throw new CliError(
|
|
5607
|
-
"PROJECT_BINDING_MIGRATION_FAILED",
|
|
5608
|
-
"The migrated Pulse Project binding could not be verified."
|
|
5609
|
-
);
|
|
5610
|
-
}
|
|
5611
|
-
return { binding: readBack, status: "imported" };
|
|
5612
|
-
}
|
|
5613
|
-
function legacyPulseBindingsFilePath(input = {}) {
|
|
5614
|
-
const env = input.env ?? process.env;
|
|
5615
|
-
const configRoot = env.XDG_CONFIG_HOME ? path14.resolve(env.XDG_CONFIG_HOME) : path14.join(input.homeDir ?? os4.homedir(), ".config");
|
|
5616
|
-
return path14.join(configRoot, "siteos", "pulse", "project-bindings.json");
|
|
5617
|
-
}
|
|
5618
|
-
async function readLegacyBindings(filePath) {
|
|
5619
|
-
try {
|
|
5620
|
-
const stats = await lstat5(filePath);
|
|
5621
|
-
if (stats.isSymbolicLink() || !stats.isFile())
|
|
5622
|
-
throw new Error("unsafe file");
|
|
5623
|
-
const parsed = legacyBindingsSchema.parse(
|
|
5624
|
-
JSON.parse(await readFile7(filePath, "utf8"))
|
|
5625
|
-
);
|
|
5626
|
-
for (const [key, binding] of Object.entries(parsed.bindings)) {
|
|
5627
|
-
if (key !== legacyBindingKey(normalizeApiUrl(binding.apiUrl), binding.projectRoot)) {
|
|
5628
|
-
throw new Error("binding key mismatch");
|
|
5629
|
-
}
|
|
5630
|
-
}
|
|
5631
|
-
return parsed;
|
|
5632
|
-
} catch (error) {
|
|
5633
|
-
if (error.code === "ENOENT") return null;
|
|
5634
|
-
throw new CliError(
|
|
5635
|
-
"PROJECT_BINDINGS_INVALID",
|
|
5636
|
-
"The legacy Pulse Project bindings could not be read safely.",
|
|
5637
|
-
{
|
|
5638
|
-
hint: "Remove the legacy binding file, then run `siteos pulse project use <slug>`."
|
|
5639
|
-
}
|
|
5640
|
-
);
|
|
5641
|
-
}
|
|
5642
|
-
}
|
|
5643
|
-
function legacyBindingKey(apiUrl, projectRoot) {
|
|
5644
|
-
return createHash5("sha256").update(`${apiUrl}\0${projectRoot}`).digest("hex");
|
|
5645
|
-
}
|
|
5646
|
-
|
|
5647
4745
|
// src/pulse/bundle.ts
|
|
5648
|
-
import { createHash as
|
|
4746
|
+
import { createHash as createHash6, randomUUID as randomUUID4 } from "crypto";
|
|
5649
4747
|
import {
|
|
5650
4748
|
access,
|
|
5651
4749
|
mkdir as mkdir3,
|
|
5652
|
-
readFile as
|
|
4750
|
+
readFile as readFile8,
|
|
5653
4751
|
rename as rename5,
|
|
5654
4752
|
rm as rm4,
|
|
5655
4753
|
writeFile as writeFile5
|
|
5656
4754
|
} from "fs/promises";
|
|
5657
|
-
import
|
|
4755
|
+
import path13 from "path";
|
|
5658
4756
|
import * as tar from "tar";
|
|
5659
4757
|
|
|
5660
4758
|
// src/pulse/project-files.ts
|
|
5661
|
-
import { createHash as
|
|
5662
|
-
import { lstat as
|
|
5663
|
-
import
|
|
4759
|
+
import { createHash as createHash5 } from "crypto";
|
|
4760
|
+
import { lstat as lstat5, readFile as readFile7 } from "fs/promises";
|
|
4761
|
+
import path12 from "path";
|
|
5664
4762
|
import fg from "fast-glob";
|
|
5665
4763
|
var MAX_BUNDLE_FILES = 5e3;
|
|
5666
4764
|
var MAX_BUNDLE_BYTES = 50 * 1024 * 1024;
|
|
@@ -5683,7 +4781,7 @@ function isSensitive(relativePath) {
|
|
|
5683
4781
|
return SENSITIVE_FILES.some((pattern) => pattern.test(segments.at(-1) ?? ""));
|
|
5684
4782
|
}
|
|
5685
4783
|
async function hashFile(filePath) {
|
|
5686
|
-
return
|
|
4784
|
+
return createHash5("sha256").update(await readFile7(filePath)).digest("hex");
|
|
5687
4785
|
}
|
|
5688
4786
|
async function discoverProjectFiles(projectRoot, config) {
|
|
5689
4787
|
const errors = [];
|
|
@@ -5756,13 +4854,13 @@ async function discoverProjectFiles(projectRoot, config) {
|
|
|
5756
4854
|
errors.push(`Sensitive path cannot be included: ${relativePath}`);
|
|
5757
4855
|
continue;
|
|
5758
4856
|
}
|
|
5759
|
-
const absolutePath =
|
|
5760
|
-
const relativeToRoot =
|
|
5761
|
-
if (relativeToRoot.startsWith("..") ||
|
|
4857
|
+
const absolutePath = path12.resolve(projectRoot, relativePath);
|
|
4858
|
+
const relativeToRoot = path12.relative(projectRoot, absolutePath);
|
|
4859
|
+
if (relativeToRoot.startsWith("..") || path12.isAbsolute(relativeToRoot)) {
|
|
5762
4860
|
errors.push(`Included path escapes the project root: ${relativePath}`);
|
|
5763
4861
|
continue;
|
|
5764
4862
|
}
|
|
5765
|
-
const stats = await
|
|
4863
|
+
const stats = await lstat5(absolutePath);
|
|
5766
4864
|
if (!stats.isFile()) continue;
|
|
5767
4865
|
if (stats.size > MAX_FILE_BYTES) {
|
|
5768
4866
|
errors.push(`File exceeds the 10 MiB limit: ${relativePath}`);
|
|
@@ -5778,8 +4876,8 @@ async function discoverProjectFiles(projectRoot, config) {
|
|
|
5778
4876
|
if (totalBytes > MAX_BUNDLE_BYTES)
|
|
5779
4877
|
errors.push("The bundle exceeds the 50 MiB size limit.");
|
|
5780
4878
|
try {
|
|
5781
|
-
const packageSource = await
|
|
5782
|
-
|
|
4879
|
+
const packageSource = await readFile7(
|
|
4880
|
+
path12.join(projectRoot, "package.json"),
|
|
5783
4881
|
"utf8"
|
|
5784
4882
|
);
|
|
5785
4883
|
const packageJson = JSON.parse(packageSource);
|
|
@@ -5801,10 +4899,10 @@ async function discoverProjectFiles(projectRoot, config) {
|
|
|
5801
4899
|
|
|
5802
4900
|
// src/pulse/bundle.ts
|
|
5803
4901
|
async function hashArchive(archivePath) {
|
|
5804
|
-
return
|
|
4902
|
+
return createHash6("sha256").update(await readFile8(archivePath)).digest("hex");
|
|
5805
4903
|
}
|
|
5806
4904
|
async function createDeploymentBundle(input) {
|
|
5807
|
-
const projectRoot =
|
|
4905
|
+
const projectRoot = path13.resolve(input.projectRoot);
|
|
5808
4906
|
const config = await loadChecksConfig(projectRoot);
|
|
5809
4907
|
const configFile = await findChecksConfigFile(projectRoot) ?? CONFIG_FILE;
|
|
5810
4908
|
const report = await discoverProjectFiles(projectRoot, config);
|
|
@@ -5817,9 +4915,9 @@ async function createDeploymentBundle(input) {
|
|
|
5817
4915
|
}
|
|
5818
4916
|
);
|
|
5819
4917
|
}
|
|
5820
|
-
const outputDirectory = input.output ?
|
|
4918
|
+
const outputDirectory = input.output ? path13.dirname(path13.resolve(projectRoot, input.output)) : path13.join(projectRoot, ".siteos", "pulse", "deployments");
|
|
5821
4919
|
await mkdir3(outputDirectory, { recursive: true });
|
|
5822
|
-
const temporaryPath =
|
|
4920
|
+
const temporaryPath = path13.join(
|
|
5823
4921
|
outputDirectory,
|
|
5824
4922
|
`.siteos-pulse-${randomUUID4()}.tgz`
|
|
5825
4923
|
);
|
|
@@ -5838,7 +4936,7 @@ async function createDeploymentBundle(input) {
|
|
|
5838
4936
|
archiveFiles
|
|
5839
4937
|
);
|
|
5840
4938
|
const checksum2 = await hashArchive(temporaryPath);
|
|
5841
|
-
const archivePath = input.output ?
|
|
4939
|
+
const archivePath = input.output ? path13.resolve(projectRoot, input.output) : path13.join(outputDirectory, `siteos-pulse-${checksum2.slice(0, 16)}.tgz`);
|
|
5842
4940
|
try {
|
|
5843
4941
|
await access(archivePath);
|
|
5844
4942
|
if (input.output) {
|
|
@@ -5878,13 +4976,13 @@ async function createDeploymentBundle(input) {
|
|
|
5878
4976
|
}
|
|
5879
4977
|
|
|
5880
4978
|
// src/pulse/init.ts
|
|
5881
|
-
import { mkdir as mkdir4, readFile as
|
|
5882
|
-
import
|
|
4979
|
+
import { mkdir as mkdir4, readFile as readFile9, writeFile as writeFile6 } from "fs/promises";
|
|
4980
|
+
import path14 from "path";
|
|
5883
4981
|
var SITEOS_PLAYWRIGHT_CONFIG = "siteos.playwright.config.ts";
|
|
5884
4982
|
var PULSE_CACHE_DIRECTORY = ".siteos/pulse/";
|
|
5885
4983
|
async function exists(filePath) {
|
|
5886
4984
|
try {
|
|
5887
|
-
await
|
|
4985
|
+
await readFile9(filePath);
|
|
5888
4986
|
return true;
|
|
5889
4987
|
} catch (error) {
|
|
5890
4988
|
if (error.code === "ENOENT") return false;
|
|
@@ -5919,7 +5017,7 @@ export default defineConfig({
|
|
|
5919
5017
|
`;
|
|
5920
5018
|
}
|
|
5921
5019
|
async function createPulsePlaywrightConfig(input) {
|
|
5922
|
-
const configPath =
|
|
5020
|
+
const configPath = path14.join(input.projectRoot, SITEOS_PLAYWRIGHT_CONFIG);
|
|
5923
5021
|
if (await exists(configPath)) {
|
|
5924
5022
|
throw new CliError(
|
|
5925
5023
|
"PULSE_PLAYWRIGHT_CONFIG_EXISTS",
|
|
@@ -5936,21 +5034,21 @@ async function createPulsePlaywrightConfig(input) {
|
|
|
5936
5034
|
}
|
|
5937
5035
|
async function detectPackageName(projectRoot) {
|
|
5938
5036
|
try {
|
|
5939
|
-
const contents = await
|
|
5940
|
-
|
|
5037
|
+
const contents = await readFile9(
|
|
5038
|
+
path14.join(projectRoot, "package.json"),
|
|
5941
5039
|
"utf8"
|
|
5942
5040
|
);
|
|
5943
5041
|
const parsed = JSON.parse(contents);
|
|
5944
|
-
return typeof parsed.name === "string" ? parsed.name :
|
|
5042
|
+
return typeof parsed.name === "string" ? parsed.name : path14.basename(projectRoot);
|
|
5945
5043
|
} catch {
|
|
5946
|
-
return
|
|
5044
|
+
return path14.basename(projectRoot);
|
|
5947
5045
|
}
|
|
5948
5046
|
}
|
|
5949
5047
|
async function ensureGitignore(projectRoot) {
|
|
5950
|
-
const gitignorePath =
|
|
5048
|
+
const gitignorePath = path14.join(projectRoot, ".gitignore");
|
|
5951
5049
|
let contents = "";
|
|
5952
5050
|
try {
|
|
5953
|
-
contents = await
|
|
5051
|
+
contents = await readFile9(gitignorePath, "utf8");
|
|
5954
5052
|
} catch (error) {
|
|
5955
5053
|
if (error.code !== "ENOENT") throw error;
|
|
5956
5054
|
}
|
|
@@ -5965,21 +5063,21 @@ async function ensureGitignore(projectRoot) {
|
|
|
5965
5063
|
return true;
|
|
5966
5064
|
}
|
|
5967
5065
|
async function initializeProject(input) {
|
|
5968
|
-
const projectRoot =
|
|
5066
|
+
const projectRoot = path14.resolve(input.projectRoot);
|
|
5969
5067
|
const existingConfig = await findChecksConfigFile(projectRoot);
|
|
5970
5068
|
if (existingConfig) {
|
|
5971
5069
|
throw new CliError("CONFIG_EXISTS", `${existingConfig} already exists.`, {
|
|
5972
5070
|
hint: "Edit the existing file or run `siteos pulse validate`."
|
|
5973
5071
|
});
|
|
5974
5072
|
}
|
|
5975
|
-
const configPath =
|
|
5073
|
+
const configPath = path14.join(projectRoot, CONFIG_FILE);
|
|
5976
5074
|
const created = [];
|
|
5977
5075
|
const updated = [];
|
|
5978
5076
|
const testsDir = input.testsDir ?? "tests/siteos";
|
|
5979
5077
|
const packageName2 = await detectPackageName(projectRoot);
|
|
5980
5078
|
const projectName = projectDisplayName(input.project ?? packageName2);
|
|
5981
5079
|
const checkSlug = projectSlug(input.suite ?? "homepage");
|
|
5982
|
-
const exampleTest =
|
|
5080
|
+
const exampleTest = path14.posix.join(
|
|
5983
5081
|
testsDir.replaceAll("\\", "/"),
|
|
5984
5082
|
`${checkSlug}.spec.ts`
|
|
5985
5083
|
);
|
|
@@ -5992,7 +5090,6 @@ async function initializeProject(input) {
|
|
|
5992
5090
|
monitoringEnabled: true
|
|
5993
5091
|
},
|
|
5994
5092
|
testsDir,
|
|
5995
|
-
apiUrl: DEFAULT_SITEOS_PULSE_API_URL,
|
|
5996
5093
|
playwrightConfig: SITEOS_PLAYWRIGHT_CONFIG,
|
|
5997
5094
|
checks: [
|
|
5998
5095
|
{
|
|
@@ -6017,11 +5114,11 @@ async function initializeProject(input) {
|
|
|
6017
5114
|
baseUrl: input.baseUrl
|
|
6018
5115
|
});
|
|
6019
5116
|
created.push(SITEOS_PLAYWRIGHT_CONFIG);
|
|
6020
|
-
const testDirectory =
|
|
5117
|
+
const testDirectory = path14.join(projectRoot, testsDir);
|
|
6021
5118
|
await mkdir4(testDirectory, { recursive: true });
|
|
6022
|
-
if (!await exists(
|
|
5119
|
+
if (!await exists(path14.join(projectRoot, exampleTest))) {
|
|
6023
5120
|
await writeFile6(
|
|
6024
|
-
|
|
5121
|
+
path14.join(projectRoot, exampleTest),
|
|
6025
5122
|
`import { expect, test } from "@playwright/test";
|
|
6026
5123
|
|
|
6027
5124
|
test(${JSON.stringify(`${projectDisplayName(input.suite ?? "homepage")} is reachable`)}, async ({ page }) => {
|
|
@@ -6047,14 +5144,14 @@ test(${JSON.stringify(`${projectDisplayName(input.suite ?? "homepage")} is reach
|
|
|
6047
5144
|
import fg4 from "fast-glob";
|
|
6048
5145
|
|
|
6049
5146
|
// src/pulse/interactive/discovery.ts
|
|
6050
|
-
import { readFile as
|
|
5147
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
6051
5148
|
import { createRequire } from "module";
|
|
6052
|
-
import
|
|
5149
|
+
import path16 from "path";
|
|
6053
5150
|
import fg2 from "fast-glob";
|
|
6054
5151
|
|
|
6055
5152
|
// src/pulse/interactive/playwright-config.ts
|
|
6056
|
-
import { readFile as
|
|
6057
|
-
import
|
|
5153
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
5154
|
+
import path15 from "path";
|
|
6058
5155
|
|
|
6059
5156
|
// src/pulse/interactive/discovery.ts
|
|
6060
5157
|
var PLAYWRIGHT_SPEC_PATTERN = "**/*.{spec,test}.{js,cjs,mjs,ts,cts,mts,jsx,tsx}";
|
|
@@ -6099,11 +5196,11 @@ async function discoverPlaywrightSelectorMatches(projectRoot, selectors, testsDi
|
|
|
6099
5196
|
}
|
|
6100
5197
|
|
|
6101
5198
|
// src/pulse/sync-plan.ts
|
|
6102
|
-
import
|
|
5199
|
+
import path17 from "path";
|
|
6103
5200
|
import fg3 from "fast-glob";
|
|
6104
5201
|
var PLAYWRIGHT_SPEC_FILE = /\.(?:spec|test)\.(?:[cm]?[jt]sx?)$/;
|
|
6105
5202
|
function defaultNameFromSpec(specPath) {
|
|
6106
|
-
const basename =
|
|
5203
|
+
const basename = path17.posix.basename(specPath).replace(/\.(?:spec|test)\.[^.]+$/, "");
|
|
6107
5204
|
return basename.split(/[^A-Za-z0-9]+/).filter(Boolean).map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(" ") || "Smoke";
|
|
6108
5205
|
}
|
|
6109
5206
|
function normalizedPaths(paths) {
|
|
@@ -6161,8 +5258,8 @@ function buildSyncPlan(input) {
|
|
|
6161
5258
|
|
|
6162
5259
|
// src/pulse/test-imports.ts
|
|
6163
5260
|
import { builtinModules } from "module";
|
|
6164
|
-
import { readFile as
|
|
6165
|
-
import
|
|
5261
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
5262
|
+
import path18 from "path";
|
|
6166
5263
|
import { build } from "esbuild";
|
|
6167
5264
|
var ALLOWED_PACKAGES = /* @__PURE__ */ new Set(["@playwright/test"]);
|
|
6168
5265
|
var BUILTINS = /* @__PURE__ */ new Set([
|
|
@@ -6176,9 +5273,9 @@ function packageName(importPath) {
|
|
|
6176
5273
|
return importPath.split("/")[0] ?? importPath;
|
|
6177
5274
|
}
|
|
6178
5275
|
function normalizedRelativePath(projectRoot, inputPath) {
|
|
6179
|
-
const absolute =
|
|
6180
|
-
const relative =
|
|
6181
|
-
if (!relative || relative.startsWith("../") ||
|
|
5276
|
+
const absolute = path18.isAbsolute(inputPath) ? inputPath : path18.resolve(projectRoot, inputPath);
|
|
5277
|
+
const relative = path18.relative(projectRoot, absolute).replaceAll("\\", "/");
|
|
5278
|
+
if (!relative || relative.startsWith("../") || path18.isAbsolute(relative)) {
|
|
6182
5279
|
throw new CliError(
|
|
6183
5280
|
"IMPORT_OUTSIDE_PROJECT",
|
|
6184
5281
|
`A selected test imports outside the project: ${inputPath}`
|
|
@@ -6187,7 +5284,7 @@ function normalizedRelativePath(projectRoot, inputPath) {
|
|
|
6187
5284
|
return relative;
|
|
6188
5285
|
}
|
|
6189
5286
|
async function analyzeTestImports(input) {
|
|
6190
|
-
const projectRoot =
|
|
5287
|
+
const projectRoot = path18.resolve(input.projectRoot);
|
|
6191
5288
|
const entryFiles = [
|
|
6192
5289
|
...new Set(
|
|
6193
5290
|
input.entryFiles.map((file) => normalizedRelativePath(projectRoot, file))
|
|
@@ -6246,7 +5343,7 @@ async function analyzeTestImports(input) {
|
|
|
6246
5343
|
const compatibilityIssues = /* @__PURE__ */ new Set();
|
|
6247
5344
|
await Promise.all(
|
|
6248
5345
|
inputs.map(async (file) => {
|
|
6249
|
-
const source = await
|
|
5346
|
+
const source = await readFile12(path18.join(projectRoot, file), "utf8").catch(
|
|
6250
5347
|
() => ""
|
|
6251
5348
|
);
|
|
6252
5349
|
for (const match of source.matchAll(ENVIRONMENT_PATTERN)) {
|
|
@@ -6689,12 +5786,12 @@ async function runSyncCli(input) {
|
|
|
6689
5786
|
// src/pulse/playwright.ts
|
|
6690
5787
|
import { spawn as spawn3 } from "child_process";
|
|
6691
5788
|
import { createRequire as createRequire2 } from "module";
|
|
6692
|
-
import
|
|
5789
|
+
import path20 from "path";
|
|
6693
5790
|
|
|
6694
5791
|
// src/pulse/package-manager.ts
|
|
6695
5792
|
import { spawn as spawn2 } from "child_process";
|
|
6696
|
-
import { access as access2, readFile as
|
|
6697
|
-
import
|
|
5793
|
+
import { access as access2, readFile as readFile13 } from "fs/promises";
|
|
5794
|
+
import path19 from "path";
|
|
6698
5795
|
var LOCKFILES = [
|
|
6699
5796
|
{ packageManager: "pnpm", filenames: ["pnpm-lock.yaml"] },
|
|
6700
5797
|
{ packageManager: "yarn", filenames: ["yarn.lock"] },
|
|
@@ -6716,7 +5813,7 @@ async function fileExists2(filePath) {
|
|
|
6716
5813
|
async function declaredPackageManager(projectRoot) {
|
|
6717
5814
|
let contents;
|
|
6718
5815
|
try {
|
|
6719
|
-
contents = await
|
|
5816
|
+
contents = await readFile13(path19.join(projectRoot, "package.json"), "utf8");
|
|
6720
5817
|
} catch (error) {
|
|
6721
5818
|
if (error.code === "ENOENT") return null;
|
|
6722
5819
|
throw error;
|
|
@@ -6753,7 +5850,7 @@ async function declaredPackageManager(projectRoot) {
|
|
|
6753
5850
|
);
|
|
6754
5851
|
}
|
|
6755
5852
|
async function detectPackageManager(projectRoot) {
|
|
6756
|
-
const root =
|
|
5853
|
+
const root = path19.resolve(projectRoot);
|
|
6757
5854
|
const declared = await declaredPackageManager(root);
|
|
6758
5855
|
if (declared) return declared;
|
|
6759
5856
|
const matches = (await Promise.all(
|
|
@@ -6762,7 +5859,7 @@ async function detectPackageManager(projectRoot) {
|
|
|
6762
5859
|
filenames: (await Promise.all(
|
|
6763
5860
|
filenames2.map(async (filename) => ({
|
|
6764
5861
|
filename,
|
|
6765
|
-
exists: await fileExists2(
|
|
5862
|
+
exists: await fileExists2(path19.join(root, filename))
|
|
6766
5863
|
}))
|
|
6767
5864
|
)).filter((entry) => entry.exists).map((entry) => entry.filename)
|
|
6768
5865
|
}))
|
|
@@ -6823,12 +5920,12 @@ function isMissingBrowserDiagnostic(output) {
|
|
|
6823
5920
|
function resolvePlaywrightCli(projectRoot) {
|
|
6824
5921
|
try {
|
|
6825
5922
|
const requireFromProject = createRequire2(
|
|
6826
|
-
|
|
5923
|
+
path20.join(projectRoot, "package.json")
|
|
6827
5924
|
);
|
|
6828
5925
|
const packageJson = requireFromProject.resolve(
|
|
6829
5926
|
"@playwright/test/package.json"
|
|
6830
5927
|
);
|
|
6831
|
-
return
|
|
5928
|
+
return path20.join(path20.dirname(packageJson), "cli.js");
|
|
6832
5929
|
} catch {
|
|
6833
5930
|
throw new CliError(
|
|
6834
5931
|
"PLAYWRIGHT_NOT_INSTALLED",
|
|
@@ -6840,7 +5937,7 @@ function resolvePlaywrightCli(projectRoot) {
|
|
|
6840
5937
|
}
|
|
6841
5938
|
}
|
|
6842
5939
|
async function runProjectTests(input) {
|
|
6843
|
-
const projectRoot =
|
|
5940
|
+
const projectRoot = path20.resolve(input.projectRoot);
|
|
6844
5941
|
const config = await loadChecksConfig(projectRoot);
|
|
6845
5942
|
const report = await discoverProjectFiles(projectRoot, config);
|
|
6846
5943
|
if (!report.valid) {
|
|
@@ -6897,9 +5994,9 @@ async function runProjectTests(input) {
|
|
|
6897
5994
|
}
|
|
6898
5995
|
|
|
6899
5996
|
// src/pulse/validate.ts
|
|
6900
|
-
import
|
|
5997
|
+
import path21 from "path";
|
|
6901
5998
|
async function validateProject(projectRoot) {
|
|
6902
|
-
const root =
|
|
5999
|
+
const root = path21.resolve(projectRoot);
|
|
6903
6000
|
const config = await loadChecksConfig(root);
|
|
6904
6001
|
return discoverProjectFiles(root, config);
|
|
6905
6002
|
}
|
|
@@ -6908,10 +6005,6 @@ async function validateProject(projectRoot) {
|
|
|
6908
6005
|
var HELP_FLAGS3 = /* @__PURE__ */ new Set(["--help", "-h"]);
|
|
6909
6006
|
var PULSE_SCOPE = "pulse:workspace:write";
|
|
6910
6007
|
var PULSE_HELP = `Usage:
|
|
6911
|
-
siteos pulse project list [--json]
|
|
6912
|
-
siteos pulse project create --slug <slug> --name <name> [--json]
|
|
6913
|
-
siteos pulse project use <slug> [--replace] [--json]
|
|
6914
|
-
siteos pulse project status [--json]
|
|
6915
6008
|
siteos pulse init [--project <slug>] [--suite <slug>] [--tests-dir <path>] [--base-url <url>]
|
|
6916
6009
|
siteos pulse validate [--json]
|
|
6917
6010
|
siteos pulse sync [--check] [--json]
|
|
@@ -6925,8 +6018,6 @@ async function runPulseCommand(options) {
|
|
|
6925
6018
|
}
|
|
6926
6019
|
try {
|
|
6927
6020
|
const [command2, ...args2] = options.args;
|
|
6928
|
-
if (command2 === "project")
|
|
6929
|
-
return await runProjectCommand2({ ...options, args: args2 });
|
|
6930
6021
|
if (command2 === "init") return await runInitCommand(options, args2);
|
|
6931
6022
|
if (command2 === "validate") return await runValidateCommand(options, args2);
|
|
6932
6023
|
if (command2 === "sync") return await runSyncCommand(options, args2);
|
|
@@ -6937,130 +6028,6 @@ async function runPulseCommand(options) {
|
|
|
6937
6028
|
return formatPulseError(error, options.args.includes("--json"));
|
|
6938
6029
|
}
|
|
6939
6030
|
}
|
|
6940
|
-
async function runProjectCommand2(options) {
|
|
6941
|
-
const [action, ...args2] = options.args;
|
|
6942
|
-
if (!action || !["create", "list", "status", "use"].includes(action)) {
|
|
6943
|
-
throw usageError3("Unknown SiteOS Pulse project command.");
|
|
6944
|
-
}
|
|
6945
|
-
const parsed = parseProjectArguments(action, args2);
|
|
6946
|
-
const cwd = options.cwd ?? process.cwd();
|
|
6947
|
-
const root = action === "list" ? null : await findRepositoryRoot(cwd);
|
|
6948
|
-
const apiOrigin = await resolvePulseApiOrigin({
|
|
6949
|
-
cwd: root ?? cwd,
|
|
6950
|
-
env: options.env,
|
|
6951
|
-
requireConfig: action !== "list"
|
|
6952
|
-
});
|
|
6953
|
-
const grant = await acquirePulseGrant(options);
|
|
6954
|
-
const client = createPulseApiClient({
|
|
6955
|
-
apiOrigin,
|
|
6956
|
-
fetchImpl: options.fetchImpl
|
|
6957
|
-
});
|
|
6958
|
-
if (action === "list") {
|
|
6959
|
-
const projects = await client.listProjects({ grant: grant.accessToken });
|
|
6960
|
-
return success(
|
|
6961
|
-
parsed.json,
|
|
6962
|
-
{ apiOrigin, organizationId: grant.grant.organizationId, projects },
|
|
6963
|
-
formatProjectList(projects)
|
|
6964
|
-
);
|
|
6965
|
-
}
|
|
6966
|
-
const repositoryRoot = root;
|
|
6967
|
-
const snapshot = await loadChecksConfigSnapshot(repositoryRoot);
|
|
6968
|
-
if (action === "create") {
|
|
6969
|
-
const baseUrl = snapshot.config.project.baseUrl;
|
|
6970
|
-
if (!baseUrl) {
|
|
6971
|
-
throw new CliError(
|
|
6972
|
-
"PULSE_PROJECT_BASE_URL_REQUIRED",
|
|
6973
|
-
"Set project.baseUrl in siteos.config.json before creating the Pulse Project."
|
|
6974
|
-
);
|
|
6975
|
-
}
|
|
6976
|
-
const project = await client.createProject({
|
|
6977
|
-
baseUrl,
|
|
6978
|
-
grant: grant.accessToken,
|
|
6979
|
-
monitoringEnabled: snapshot.config.project.monitoringEnabled,
|
|
6980
|
-
name: parsed.name,
|
|
6981
|
-
slug: parsed.slug
|
|
6982
|
-
});
|
|
6983
|
-
return success(
|
|
6984
|
-
parsed.json,
|
|
6985
|
-
{ apiOrigin, project },
|
|
6986
|
-
[
|
|
6987
|
-
"SiteOS Pulse Project created.",
|
|
6988
|
-
`Project: ${project.slug}`,
|
|
6989
|
-
`Name: ${project.name}`,
|
|
6990
|
-
`Run \`siteos pulse project use ${project.slug}\` to select it for this repository.`
|
|
6991
|
-
].join("\n")
|
|
6992
|
-
);
|
|
6993
|
-
}
|
|
6994
|
-
const store = projectBindingStore2(options);
|
|
6995
|
-
const locator = { apiOrigin, repositoryRoot, service: "pulse" };
|
|
6996
|
-
if (action === "use") {
|
|
6997
|
-
const projects = await client.listProjects({ grant: grant.accessToken });
|
|
6998
|
-
const project = uniqueProjectBySlug(projects, parsed.slug);
|
|
6999
|
-
const previous = await store.read(locator);
|
|
7000
|
-
const replacing = snapshot.config.project.slug !== project.slug || previous !== null && previous.project.id !== project.id;
|
|
7001
|
-
if (replacing && !parsed.replace) {
|
|
7002
|
-
throw new CliError(
|
|
7003
|
-
"PULSE_PROJECT_REFERENCE_CONFLICT",
|
|
7004
|
-
"A different Pulse Project is already selected. Use --replace to replace it."
|
|
7005
|
-
);
|
|
7006
|
-
}
|
|
7007
|
-
await store.write({
|
|
7008
|
-
...locator,
|
|
7009
|
-
organizationId: grant.grant.organizationId,
|
|
7010
|
-
project: { id: project.id, slug: project.slug }
|
|
7011
|
-
});
|
|
7012
|
-
try {
|
|
7013
|
-
await reconcileProjectSlug(repositoryRoot, project.slug, {
|
|
7014
|
-
expectedChecksum: snapshot.checksum
|
|
7015
|
-
});
|
|
7016
|
-
} catch (error) {
|
|
7017
|
-
if (previous) await store.write(previous);
|
|
7018
|
-
else await store.remove(locator);
|
|
7019
|
-
throw error;
|
|
7020
|
-
}
|
|
7021
|
-
return success(
|
|
7022
|
-
parsed.json,
|
|
7023
|
-
{
|
|
7024
|
-
apiOrigin,
|
|
7025
|
-
organizationId: grant.grant.organizationId,
|
|
7026
|
-
project,
|
|
7027
|
-
referencePath: path25.join(repositoryRoot, CONFIG_FILE)
|
|
7028
|
-
},
|
|
7029
|
-
[
|
|
7030
|
-
"SiteOS Pulse Project selected.",
|
|
7031
|
-
`Project: ${project.slug}`,
|
|
7032
|
-
`Reference: ${path25.join(repositoryRoot, CONFIG_FILE)}`
|
|
7033
|
-
].join("\n")
|
|
7034
|
-
);
|
|
7035
|
-
}
|
|
7036
|
-
const selected = await requireSelectedProject({
|
|
7037
|
-
options,
|
|
7038
|
-
apiOrigin,
|
|
7039
|
-
client,
|
|
7040
|
-
grant,
|
|
7041
|
-
legacyBindingsPath: options.legacyBindingsPath,
|
|
7042
|
-
projectBindingStore: store,
|
|
7043
|
-
projectSlug: snapshot.config.project.slug,
|
|
7044
|
-
repositoryRoot
|
|
7045
|
-
});
|
|
7046
|
-
return success(
|
|
7047
|
-
parsed.json,
|
|
7048
|
-
{
|
|
7049
|
-
apiOrigin,
|
|
7050
|
-
connected: true,
|
|
7051
|
-
migration: selected.migration,
|
|
7052
|
-
organizationId: grant.grant.organizationId,
|
|
7053
|
-
project: selected.project,
|
|
7054
|
-
repositoryRoot
|
|
7055
|
-
},
|
|
7056
|
-
[
|
|
7057
|
-
"SiteOS Pulse Project connection is valid.",
|
|
7058
|
-
`Project: ${selected.project.slug}`,
|
|
7059
|
-
`Organization: ${grant.grant.organizationId}`,
|
|
7060
|
-
`API: ${apiOrigin}`
|
|
7061
|
-
].join("\n")
|
|
7062
|
-
);
|
|
7063
|
-
}
|
|
7064
6031
|
async function runInitCommand(options, args2) {
|
|
7065
6032
|
const { values } = parseArgs({
|
|
7066
6033
|
args: args2,
|
|
@@ -7179,7 +6146,7 @@ async function runDeployCommand(options, args2) {
|
|
|
7179
6146
|
},
|
|
7180
6147
|
strict: true
|
|
7181
6148
|
});
|
|
7182
|
-
const projectRoot =
|
|
6149
|
+
const projectRoot = path22.resolve(options.cwd ?? process.cwd());
|
|
7183
6150
|
const repositoryRoot = await findRepositoryRoot(projectRoot);
|
|
7184
6151
|
const common = await commonServiceContext(options, "pulse");
|
|
7185
6152
|
if (common && (!common.environmentBinding?.slug || !common.environment.url))
|
|
@@ -7203,18 +6170,19 @@ async function runDeployCommand(options, args2) {
|
|
|
7203
6170
|
values.json,
|
|
7204
6171
|
{ dryRun: true, manifest },
|
|
7205
6172
|
[
|
|
7206
|
-
`Bundle: ${
|
|
6173
|
+
`Bundle: ${path22.relative(projectRoot, manifest.archivePath)}`,
|
|
7207
6174
|
`Checksum: ${manifest.checksum}`,
|
|
7208
6175
|
`Files: ${manifest.fileCount}`,
|
|
7209
6176
|
"Dry run complete; nothing was uploaded."
|
|
7210
6177
|
].join("\n")
|
|
7211
6178
|
);
|
|
7212
6179
|
}
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
6180
|
+
if (!common)
|
|
6181
|
+
throw new CliError(
|
|
6182
|
+
"PROJECT_REQUIRED",
|
|
6183
|
+
"Select a Project with `siteos project use <id-or-slug>` before deploying."
|
|
6184
|
+
);
|
|
6185
|
+
const apiOrigin = common.api.origin;
|
|
7218
6186
|
const grant = await acquirePulseGrant(options);
|
|
7219
6187
|
const client = createPulseApiClient({
|
|
7220
6188
|
apiOrigin,
|
|
@@ -7226,8 +6194,6 @@ async function runDeployCommand(options, args2) {
|
|
|
7226
6194
|
apiOrigin,
|
|
7227
6195
|
client,
|
|
7228
6196
|
grant,
|
|
7229
|
-
legacyBindingsPath: options.legacyBindingsPath,
|
|
7230
|
-
projectBindingStore: projectBindingStore2(options),
|
|
7231
6197
|
projectSlug: snapshot.config.project.slug,
|
|
7232
6198
|
repositoryRoot
|
|
7233
6199
|
});
|
|
@@ -7246,7 +6212,7 @@ async function runDeployCommand(options, args2) {
|
|
|
7246
6212
|
values.json,
|
|
7247
6213
|
{ deployment, dryRun: false, manifest },
|
|
7248
6214
|
[
|
|
7249
|
-
`Bundle: ${
|
|
6215
|
+
`Bundle: ${path22.relative(projectRoot, manifest.archivePath)}`,
|
|
7250
6216
|
`Checksum: ${manifest.checksum}`,
|
|
7251
6217
|
`Files: ${manifest.fileCount}`,
|
|
7252
6218
|
`Project ${deployment.projectId} deployed.`,
|
|
@@ -7280,124 +6246,22 @@ async function requireSelectedProject(input) {
|
|
|
7280
6246
|
"The selected Project and Pulse deployment origin or organization do not match."
|
|
7281
6247
|
);
|
|
7282
6248
|
}
|
|
7283
|
-
const
|
|
6249
|
+
const project = await input.client.getProject({
|
|
7284
6250
|
grant: input.grant.accessToken,
|
|
7285
6251
|
projectId: common.resourceId
|
|
7286
6252
|
});
|
|
7287
|
-
if (
|
|
6253
|
+
if (project.slug !== input.projectSlug && common.overview.project.slug !== input.projectSlug)
|
|
7288
6254
|
throw new CliError(
|
|
7289
6255
|
"PULSE_PROJECT_BINDING_INVALID",
|
|
7290
6256
|
`Set project.slug in siteos.config.json to ${common.overview.project.slug} before deploying checks to this Project.`
|
|
7291
6257
|
);
|
|
7292
|
-
return {
|
|
7293
|
-
}
|
|
7294
|
-
const migration = await migrateLegacyPulseBinding({
|
|
7295
|
-
apiOrigin: input.apiOrigin,
|
|
7296
|
-
legacyBindingsPath: input.legacyBindingsPath,
|
|
7297
|
-
organizationId: input.grant.grant.organizationId,
|
|
7298
|
-
projectBindingStore: input.projectBindingStore,
|
|
7299
|
-
projectSlug: input.projectSlug,
|
|
7300
|
-
repositoryRoot: input.repositoryRoot
|
|
7301
|
-
});
|
|
7302
|
-
const binding = migration.binding;
|
|
7303
|
-
if (!binding) {
|
|
7304
|
-
throw new CliError(
|
|
7305
|
-
"PULSE_PROJECT_BINDING_REQUIRED",
|
|
7306
|
-
"Select a Pulse Project for this repository first.",
|
|
7307
|
-
{ hint: `Run \`siteos pulse project use ${input.projectSlug}\`.` }
|
|
7308
|
-
);
|
|
7309
|
-
}
|
|
7310
|
-
if (binding.organizationId !== input.grant.grant.organizationId || binding.project.slug !== input.projectSlug) {
|
|
7311
|
-
throw new CliError(
|
|
7312
|
-
"PULSE_PROJECT_BINDING_INVALID",
|
|
7313
|
-
"The Pulse Project configuration and private binding do not match.",
|
|
7314
|
-
{
|
|
7315
|
-
hint: `Run \`siteos pulse project use ${input.projectSlug} --replace\`.`
|
|
7316
|
-
}
|
|
7317
|
-
);
|
|
7318
|
-
}
|
|
7319
|
-
const project = await input.client.getProject({
|
|
7320
|
-
grant: input.grant.accessToken,
|
|
7321
|
-
projectId: binding.project.id
|
|
7322
|
-
});
|
|
7323
|
-
if (project.slug !== binding.project.slug) {
|
|
7324
|
-
throw new CliError(
|
|
7325
|
-
"PULSE_PROJECT_BINDING_STALE",
|
|
7326
|
-
"The selected Pulse Project is no longer valid.",
|
|
7327
|
-
{
|
|
7328
|
-
hint: `Run \`siteos pulse project use ${input.projectSlug} --replace\`.`
|
|
7329
|
-
}
|
|
7330
|
-
);
|
|
7331
|
-
}
|
|
7332
|
-
return { migration: migration.status, project };
|
|
7333
|
-
}
|
|
7334
|
-
async function resolvePulseApiOrigin(input) {
|
|
7335
|
-
const configured = input.env?.SITEOS_PULSE_API_URL?.trim();
|
|
7336
|
-
if (configured) return normalizeApiUrl(configured);
|
|
7337
|
-
try {
|
|
7338
|
-
const config = await loadChecksConfigFile(input.cwd);
|
|
7339
|
-
if (config.apiUrl) return normalizeApiUrl(config.apiUrl);
|
|
7340
|
-
} catch (error) {
|
|
7341
|
-
if (input.requireConfig || !(error instanceof CliError) || error.code !== "CONFIG_NOT_FOUND") {
|
|
7342
|
-
throw error;
|
|
7343
|
-
}
|
|
6258
|
+
return { project };
|
|
7344
6259
|
}
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
return options.projectBindingStore ?? new NodeProjectBindingStore(
|
|
7349
|
-
path25.join(
|
|
7350
|
-
resolveSiteOSConfigHome({ env: options.env, homeDir: options.homeDir }),
|
|
7351
|
-
"project-bindings.json"
|
|
7352
|
-
)
|
|
6260
|
+
throw new CliError(
|
|
6261
|
+
"PROJECT_REQUIRED",
|
|
6262
|
+
"Select a Project with `siteos project use <id-or-slug>` before deploying."
|
|
7353
6263
|
);
|
|
7354
6264
|
}
|
|
7355
|
-
function parseProjectArguments(action, args2) {
|
|
7356
|
-
const { positionals, values } = parseArgs({
|
|
7357
|
-
allowPositionals: true,
|
|
7358
|
-
args: args2,
|
|
7359
|
-
options: {
|
|
7360
|
-
json: { default: false, type: "boolean" },
|
|
7361
|
-
...action === "create" ? {
|
|
7362
|
-
name: { type: "string" },
|
|
7363
|
-
slug: { type: "string" }
|
|
7364
|
-
} : {},
|
|
7365
|
-
...action === "use" ? { replace: { default: false, type: "boolean" } } : {}
|
|
7366
|
-
},
|
|
7367
|
-
strict: true
|
|
7368
|
-
});
|
|
7369
|
-
if (action === "create" && (!values.slug || !values.name || positionals.length > 0)) {
|
|
7370
|
-
throw usageError3(
|
|
7371
|
-
"Usage: siteos pulse project create --slug <slug> --name <name> [--json]"
|
|
7372
|
-
);
|
|
7373
|
-
}
|
|
7374
|
-
if (action === "use" && (positionals.length !== 1 || !positionals[0])) {
|
|
7375
|
-
throw usageError3(
|
|
7376
|
-
"Usage: siteos pulse project use <slug> [--replace] [--json]"
|
|
7377
|
-
);
|
|
7378
|
-
}
|
|
7379
|
-
if ((action === "list" || action === "status") && positionals.length > 0) {
|
|
7380
|
-
throw usageError3(
|
|
7381
|
-
`siteos pulse project ${action} does not accept positional arguments.`
|
|
7382
|
-
);
|
|
7383
|
-
}
|
|
7384
|
-
return {
|
|
7385
|
-
json: Boolean(values.json),
|
|
7386
|
-
name: typeof values.name === "string" ? values.name : void 0,
|
|
7387
|
-
replace: Boolean(values.replace),
|
|
7388
|
-
slug: action === "use" ? positionals[0] : typeof values.slug === "string" ? values.slug : void 0
|
|
7389
|
-
};
|
|
7390
|
-
}
|
|
7391
|
-
function uniqueProjectBySlug(projects, slug2) {
|
|
7392
|
-
const matches = projects.filter((project) => project.slug === slug2);
|
|
7393
|
-
if (matches.length !== 1) {
|
|
7394
|
-
throw new CliError(
|
|
7395
|
-
matches.length === 0 ? "PULSE_PROJECT_NOT_FOUND" : "API_INVALID_RESPONSE",
|
|
7396
|
-
matches.length === 0 ? "The Pulse Project was not found." : "SiteOS Pulse returned an ambiguous Project list."
|
|
7397
|
-
);
|
|
7398
|
-
}
|
|
7399
|
-
return matches[0];
|
|
7400
|
-
}
|
|
7401
6265
|
function formatValidation(report) {
|
|
7402
6266
|
return [
|
|
7403
6267
|
report.valid ? "SiteOS Pulse project is valid." : "SiteOS Pulse project is invalid.",
|
|
@@ -7426,15 +6290,6 @@ function formatSyncReport(report) {
|
|
|
7426
6290
|
...report.blockers.map((blocker) => `Blocker: ${blocker.message}`)
|
|
7427
6291
|
].join("\n");
|
|
7428
6292
|
}
|
|
7429
|
-
function formatProjectList(projects) {
|
|
7430
|
-
return [
|
|
7431
|
-
"SiteOS Pulse Projects.",
|
|
7432
|
-
`Projects: ${projects.length}`,
|
|
7433
|
-
...projects.map(
|
|
7434
|
-
(project) => `- ${project.slug}: ${project.name} (${project.checkCount} Check${project.checkCount === 1 ? "" : "s"})`
|
|
7435
|
-
)
|
|
7436
|
-
].join("\n");
|
|
7437
|
-
}
|
|
7438
6293
|
function success(json, value, text) {
|
|
7439
6294
|
return {
|
|
7440
6295
|
exitCode: CLI_EXIT_CODE.success,
|
|
@@ -7496,92 +6351,64 @@ function exitCodeForPulseError(error) {
|
|
|
7496
6351
|
return CLI_EXIT_CODE.internal;
|
|
7497
6352
|
}
|
|
7498
6353
|
|
|
7499
|
-
// src/search-command.ts
|
|
7500
|
-
import path27 from "path";
|
|
7501
|
-
|
|
7502
6354
|
// src/siteos-search-api.ts
|
|
7503
|
-
import { z as
|
|
7504
|
-
var
|
|
7505
|
-
var
|
|
7506
|
-
var
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
updatedAt: z13.string().datetime({ offset: true })
|
|
7515
|
-
}).strict();
|
|
7516
|
-
var searchProjectListResponseSchema = z13.object({ projects: z13.array(searchProjectSchema), success: z13.literal(true) }).strict();
|
|
7517
|
-
var searchProjectResponseSchema = z13.object({ project: searchProjectSchema, success: z13.literal(true) }).strict();
|
|
7518
|
-
var searchEnvironmentSchema = z13.object({
|
|
7519
|
-
createdAt: z13.string().datetime({ offset: true }),
|
|
7520
|
-
id: z13.string().trim().min(1).max(255),
|
|
7521
|
-
name: z13.string().trim().min(1).max(255),
|
|
7522
|
-
projectId: z13.string().trim().min(1).max(255),
|
|
7523
|
-
slug: environmentSlugSchema,
|
|
7524
|
-
updatedAt: z13.string().datetime({ offset: true })
|
|
7525
|
-
}).strict();
|
|
7526
|
-
var searchEnvironmentListResponseSchema = z13.object({
|
|
7527
|
-
environments: z13.array(searchEnvironmentSchema),
|
|
7528
|
-
success: z13.literal(true)
|
|
7529
|
-
}).strict();
|
|
7530
|
-
var searchEnvironmentResponseSchema = z13.object({ environment: searchEnvironmentSchema, success: z13.literal(true) }).passthrough();
|
|
7531
|
-
var searchCredentialMetadataSchema = z13.object({
|
|
7532
|
-
createdAt: z13.string().datetime({ offset: true }),
|
|
7533
|
-
id: z13.string().trim().min(1).max(255),
|
|
7534
|
-
lastUsedAt: z13.string().datetime({ offset: true }).nullable(),
|
|
7535
|
-
name: z13.string().trim().min(1).max(255),
|
|
7536
|
-
projectEnvironmentId: z13.string().trim().min(1).max(255),
|
|
7537
|
-
revokedAt: z13.string().datetime({ offset: true }).nullable(),
|
|
7538
|
-
status: z13.enum(["active", "revoked"])
|
|
6355
|
+
import { z as z10 } from "zod";
|
|
6356
|
+
var permissiveObjectSchema = z10.record(z10.unknown());
|
|
6357
|
+
var environmentSlugSchema = z10.string().min(2).max(30).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
|
|
6358
|
+
var searchCredentialMetadataSchema = z10.object({
|
|
6359
|
+
createdAt: z10.string().datetime({ offset: true }),
|
|
6360
|
+
id: z10.string().trim().min(1).max(255),
|
|
6361
|
+
lastUsedAt: z10.string().datetime({ offset: true }).nullable(),
|
|
6362
|
+
name: z10.string().trim().min(1).max(255),
|
|
6363
|
+
projectEnvironmentId: z10.string().trim().min(1).max(255),
|
|
6364
|
+
revokedAt: z10.string().datetime({ offset: true }).nullable(),
|
|
6365
|
+
status: z10.enum(["active", "revoked"])
|
|
7539
6366
|
}).strict();
|
|
7540
|
-
var searchCredentialListResponseSchema =
|
|
6367
|
+
var searchCredentialListResponseSchema = z10.object({
|
|
7541
6368
|
environmentSlug: environmentSlugSchema,
|
|
7542
|
-
success:
|
|
7543
|
-
tokens:
|
|
6369
|
+
success: z10.literal(true),
|
|
6370
|
+
tokens: z10.array(searchCredentialMetadataSchema)
|
|
7544
6371
|
}).strict();
|
|
7545
|
-
var searchCredentialExchangeResponseSchema =
|
|
6372
|
+
var searchCredentialExchangeResponseSchema = z10.object({
|
|
7546
6373
|
environmentSlug: environmentSlugSchema,
|
|
7547
|
-
success:
|
|
6374
|
+
success: z10.literal(true),
|
|
7548
6375
|
token: searchCredentialMetadataSchema.extend({
|
|
7549
|
-
token:
|
|
6376
|
+
token: z10.string().regex(/^psq_[A-Za-z0-9_-]{22}$/)
|
|
7550
6377
|
})
|
|
7551
6378
|
}).strict();
|
|
7552
|
-
var searchCredentialRevokeResponseSchema =
|
|
6379
|
+
var searchCredentialRevokeResponseSchema = z10.object({
|
|
7553
6380
|
environmentSlug: environmentSlugSchema,
|
|
7554
|
-
success:
|
|
6381
|
+
success: z10.literal(true),
|
|
7555
6382
|
token: searchCredentialMetadataSchema
|
|
7556
6383
|
}).strict();
|
|
7557
|
-
var searchIndexingCredentialListResponseSchema =
|
|
7558
|
-
credentials:
|
|
6384
|
+
var searchIndexingCredentialListResponseSchema = z10.object({
|
|
6385
|
+
credentials: z10.array(searchCredentialMetadataSchema),
|
|
7559
6386
|
environmentSlug: environmentSlugSchema,
|
|
7560
|
-
success:
|
|
6387
|
+
success: z10.literal(true)
|
|
7561
6388
|
}).strict();
|
|
7562
|
-
var searchIndexingCredentialExchangeResponseSchema =
|
|
6389
|
+
var searchIndexingCredentialExchangeResponseSchema = z10.object({
|
|
7563
6390
|
credential: searchCredentialMetadataSchema.extend({
|
|
7564
|
-
credential:
|
|
6391
|
+
credential: z10.string().regex(/^psi_[A-Za-z0-9_-]{22}$/)
|
|
7565
6392
|
}).strict(),
|
|
7566
6393
|
environmentSlug: environmentSlugSchema,
|
|
7567
|
-
success:
|
|
6394
|
+
success: z10.literal(true)
|
|
7568
6395
|
}).strict();
|
|
7569
|
-
var searchIndexingCredentialRevokeResponseSchema =
|
|
6396
|
+
var searchIndexingCredentialRevokeResponseSchema = z10.object({
|
|
7570
6397
|
credential: searchCredentialMetadataSchema,
|
|
7571
6398
|
environmentSlug: environmentSlugSchema,
|
|
7572
|
-
success:
|
|
6399
|
+
success: z10.literal(true)
|
|
7573
6400
|
}).strict();
|
|
7574
|
-
var nestedApiErrorResponseSchema =
|
|
7575
|
-
error:
|
|
7576
|
-
code:
|
|
7577
|
-
message:
|
|
7578
|
-
nextActions:
|
|
6401
|
+
var nestedApiErrorResponseSchema = z10.object({
|
|
6402
|
+
error: z10.object({
|
|
6403
|
+
code: z10.string().trim().min(1).optional(),
|
|
6404
|
+
message: z10.string().trim().min(1),
|
|
6405
|
+
nextActions: z10.array(z10.string()).optional()
|
|
7579
6406
|
})
|
|
7580
6407
|
}).passthrough();
|
|
7581
|
-
var directApiErrorResponseSchema =
|
|
7582
|
-
code:
|
|
7583
|
-
message:
|
|
7584
|
-
status:
|
|
6408
|
+
var directApiErrorResponseSchema = z10.object({
|
|
6409
|
+
code: z10.string().trim().min(1).optional(),
|
|
6410
|
+
message: z10.string().trim().min(1).optional(),
|
|
6411
|
+
status: z10.number().int().optional()
|
|
7585
6412
|
}).passthrough();
|
|
7586
6413
|
var SiteOSSearchApiError = class extends Error {
|
|
7587
6414
|
code;
|
|
@@ -7595,90 +6422,8 @@ var SiteOSSearchApiError = class extends Error {
|
|
|
7595
6422
|
this.status = options.status;
|
|
7596
6423
|
}
|
|
7597
6424
|
};
|
|
7598
|
-
function resolveSiteOSSearchBaseUrl(env = process.env) {
|
|
7599
|
-
return normalizeSearchOrigin(
|
|
7600
|
-
env[SITEOS_SEARCH_BASE_URL_ENV]?.trim() || DEFAULT_SITEOS_SEARCH_BASE_URL
|
|
7601
|
-
);
|
|
7602
|
-
}
|
|
7603
6425
|
function createSiteOSSearchApiClient(options) {
|
|
7604
6426
|
return {
|
|
7605
|
-
createProject: async (input) => {
|
|
7606
|
-
const response = await requestJson3({
|
|
7607
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
7608
|
-
authToken: input.token,
|
|
7609
|
-
body: { name: input.name, slug: input.slug },
|
|
7610
|
-
fetchImpl: options.fetchImpl,
|
|
7611
|
-
method: "POST",
|
|
7612
|
-
path: "/api/v1/search/projects",
|
|
7613
|
-
responseSchema: searchProjectResponseSchema
|
|
7614
|
-
});
|
|
7615
|
-
return response.project;
|
|
7616
|
-
},
|
|
7617
|
-
listProjects: async (input) => {
|
|
7618
|
-
const response = await requestJson3({
|
|
7619
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
7620
|
-
authToken: input.token,
|
|
7621
|
-
fetchImpl: options.fetchImpl,
|
|
7622
|
-
method: "GET",
|
|
7623
|
-
path: "/api/v1/search/projects",
|
|
7624
|
-
responseSchema: searchProjectListResponseSchema
|
|
7625
|
-
});
|
|
7626
|
-
return response.projects;
|
|
7627
|
-
},
|
|
7628
|
-
listEnvironments: async (input) => {
|
|
7629
|
-
const response = await requestJson3({
|
|
7630
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
7631
|
-
authToken: input.token,
|
|
7632
|
-
fetchImpl: options.fetchImpl,
|
|
7633
|
-
method: "GET",
|
|
7634
|
-
path: environmentCollectionPath2(input.projectId),
|
|
7635
|
-
responseSchema: searchEnvironmentListResponseSchema
|
|
7636
|
-
});
|
|
7637
|
-
return response.environments;
|
|
7638
|
-
},
|
|
7639
|
-
createEnvironment: async (input) => {
|
|
7640
|
-
const response = await requestJson3({
|
|
7641
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
7642
|
-
authToken: input.token,
|
|
7643
|
-
body: { slug: input.slug, name: input.name },
|
|
7644
|
-
fetchImpl: options.fetchImpl,
|
|
7645
|
-
method: "POST",
|
|
7646
|
-
path: environmentCollectionPath2(input.projectId),
|
|
7647
|
-
responseSchema: searchEnvironmentResponseSchema
|
|
7648
|
-
});
|
|
7649
|
-
return response.environment;
|
|
7650
|
-
},
|
|
7651
|
-
updateEnvironment: async (input) => {
|
|
7652
|
-
const response = await requestJson3({
|
|
7653
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
7654
|
-
authToken: input.token,
|
|
7655
|
-
body: { name: input.name },
|
|
7656
|
-
fetchImpl: options.fetchImpl,
|
|
7657
|
-
method: "PATCH",
|
|
7658
|
-
path: environmentPath(input.projectId, input.environmentSlug),
|
|
7659
|
-
responseSchema: searchEnvironmentResponseSchema
|
|
7660
|
-
});
|
|
7661
|
-
return response.environment;
|
|
7662
|
-
},
|
|
7663
|
-
forkEnvironment: async (input) => {
|
|
7664
|
-
const response = await requestJson3({
|
|
7665
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
7666
|
-
authToken: input.token,
|
|
7667
|
-
body: { slug: input.slug, name: input.name },
|
|
7668
|
-
fetchImpl: options.fetchImpl,
|
|
7669
|
-
method: "POST",
|
|
7670
|
-
path: `${environmentPath(input.projectId, input.sourceEnvironmentSlug)}/actions/fork`,
|
|
7671
|
-
responseSchema: searchEnvironmentResponseSchema
|
|
7672
|
-
});
|
|
7673
|
-
return response.environment;
|
|
7674
|
-
},
|
|
7675
|
-
deleteEnvironment: (input) => requestJson3({
|
|
7676
|
-
apiBaseUrl: options.apiBaseUrl,
|
|
7677
|
-
authToken: input.token,
|
|
7678
|
-
fetchImpl: options.fetchImpl,
|
|
7679
|
-
method: "DELETE",
|
|
7680
|
-
path: environmentPath(input.projectId, input.environmentSlug)
|
|
7681
|
-
}),
|
|
7682
6427
|
analytics: (input) => requestJson3({
|
|
7683
6428
|
apiBaseUrl: options.apiBaseUrl,
|
|
7684
6429
|
authToken: input.token,
|
|
@@ -7926,36 +6671,19 @@ function buildApiUrl2(options) {
|
|
|
7926
6671
|
}
|
|
7927
6672
|
return url.toString();
|
|
7928
6673
|
}
|
|
7929
|
-
function normalizeSearchOrigin(value) {
|
|
7930
|
-
try {
|
|
7931
|
-
const url = new URL(value);
|
|
7932
|
-
const loopback = ["localhost", "127.0.0.1", "[::1]", "::1"].includes(
|
|
7933
|
-
url.hostname
|
|
7934
|
-
);
|
|
7935
|
-
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
|
|
7936
|
-
throw new Error("invalid Search origin");
|
|
7937
|
-
}
|
|
7938
|
-
return url.origin;
|
|
7939
|
-
} catch {
|
|
7940
|
-
throw new SiteOSSearchApiError({
|
|
7941
|
-
code: "INVALID_SEARCH_BASE_URL",
|
|
7942
|
-
message: "The SiteOS Search URL is invalid."
|
|
7943
|
-
});
|
|
7944
|
-
}
|
|
7945
|
-
}
|
|
7946
6674
|
|
|
7947
6675
|
// src/siteos-search-credential.ts
|
|
7948
6676
|
import { spawn as spawn4 } from "child_process";
|
|
7949
6677
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
7950
6678
|
import {
|
|
7951
6679
|
chmod as chmod4,
|
|
7952
|
-
lstat as
|
|
7953
|
-
readFile as
|
|
6680
|
+
lstat as lstat6,
|
|
6681
|
+
readFile as readFile14,
|
|
7954
6682
|
rename as rename6,
|
|
7955
6683
|
rm as rm5,
|
|
7956
6684
|
writeFile as writeFile7
|
|
7957
6685
|
} from "fs/promises";
|
|
7958
|
-
import
|
|
6686
|
+
import path23 from "path";
|
|
7959
6687
|
var SITEOS_SEARCH_QUERY_CREDENTIAL_ENV = "SITEOS_SEARCH_TOKEN";
|
|
7960
6688
|
var SITEOS_SEARCH_ENVIRONMENT_ENV = "SITEOS_SEARCH_ENV";
|
|
7961
6689
|
var SITEOS_SEARCH_INDEXING_CREDENTIAL_ENV = "SITEOS_SEARCH_INDEXING_CREDENTIAL";
|
|
@@ -7973,8 +6701,8 @@ var SiteOSSearchCredentialStorageError = class extends Error {
|
|
|
7973
6701
|
}
|
|
7974
6702
|
};
|
|
7975
6703
|
async function prepareSiteOSSearchCredentialInstallation(options) {
|
|
7976
|
-
const projectRoot =
|
|
7977
|
-
const dotenvPath =
|
|
6704
|
+
const projectRoot = path23.resolve(options.projectRoot);
|
|
6705
|
+
const dotenvPath = path23.join(projectRoot, ".env");
|
|
7978
6706
|
try {
|
|
7979
6707
|
await assertSafeProjectRoot2(projectRoot);
|
|
7980
6708
|
if (!await isDotenvIgnored2(projectRoot)) {
|
|
@@ -8032,8 +6760,8 @@ async function prepareSiteOSSearchCredentialInstallation(options) {
|
|
|
8032
6760
|
}
|
|
8033
6761
|
}
|
|
8034
6762
|
async function prepareSiteOSSearchIndexingCredentialInstallation(options) {
|
|
8035
|
-
const projectRoot =
|
|
8036
|
-
const dotenvPath =
|
|
6763
|
+
const projectRoot = path23.resolve(options.projectRoot);
|
|
6764
|
+
const dotenvPath = path23.join(projectRoot, ".env");
|
|
8037
6765
|
try {
|
|
8038
6766
|
await assertSafeProjectRoot2(projectRoot);
|
|
8039
6767
|
if (!await isDotenvIgnored2(projectRoot)) {
|
|
@@ -8092,7 +6820,7 @@ async function prepareSiteOSSearchIndexingCredentialInstallation(options) {
|
|
|
8092
6820
|
}
|
|
8093
6821
|
}
|
|
8094
6822
|
async function assertSafeProjectRoot2(projectRoot) {
|
|
8095
|
-
const projectStats = await
|
|
6823
|
+
const projectStats = await lstat6(projectRoot);
|
|
8096
6824
|
if (!projectStats.isDirectory() || projectStats.isSymbolicLink()) {
|
|
8097
6825
|
throw new SiteOSSearchCredentialStorageError(
|
|
8098
6826
|
"SEARCH_CREDENTIAL_STORAGE_INVALID"
|
|
@@ -8100,7 +6828,7 @@ async function assertSafeProjectRoot2(projectRoot) {
|
|
|
8100
6828
|
}
|
|
8101
6829
|
}
|
|
8102
6830
|
async function readSafeDotenv2(dotenvPath, managedEnvironmentNames) {
|
|
8103
|
-
const dotenvStats = await
|
|
6831
|
+
const dotenvStats = await lstat6(dotenvPath).catch((error) => {
|
|
8104
6832
|
if (isNodeErrorCode5(error, "ENOENT")) return void 0;
|
|
8105
6833
|
throw error;
|
|
8106
6834
|
});
|
|
@@ -8109,7 +6837,7 @@ async function readSafeDotenv2(dotenvPath, managedEnvironmentNames) {
|
|
|
8109
6837
|
"SEARCH_CREDENTIAL_STORAGE_INVALID"
|
|
8110
6838
|
);
|
|
8111
6839
|
}
|
|
8112
|
-
const content = dotenvStats ? await
|
|
6840
|
+
const content = dotenvStats ? await readFile14(dotenvPath, "utf8") : "";
|
|
8113
6841
|
if (managedEnvironmentNames.some(
|
|
8114
6842
|
(name) => countManagedEntries(content, name) > 1
|
|
8115
6843
|
)) {
|
|
@@ -8120,7 +6848,7 @@ async function readSafeDotenv2(dotenvPath, managedEnvironmentNames) {
|
|
|
8120
6848
|
return content;
|
|
8121
6849
|
}
|
|
8122
6850
|
async function writeCredentialAtomically2(options) {
|
|
8123
|
-
const temporaryPath =
|
|
6851
|
+
const temporaryPath = path23.join(
|
|
8124
6852
|
options.projectRoot,
|
|
8125
6853
|
`.siteos-search-credential.${process.pid}.${randomUUID5()}.tmp`
|
|
8126
6854
|
);
|
|
@@ -8199,19 +6927,7 @@ var ENVIRONMENT_FLAG2 = "--environment";
|
|
|
8199
6927
|
var CREDENTIAL_FLAG2 = "--credential";
|
|
8200
6928
|
var INSTALL_FLAG2 = "--install";
|
|
8201
6929
|
var NAME_FLAG2 = "--name";
|
|
8202
|
-
var SLUG_FLAG2 = "--slug";
|
|
8203
|
-
var SOURCE_FLAG = "--source";
|
|
8204
|
-
var REPLACE_FLAG2 = "--replace";
|
|
8205
6930
|
var SEARCH_HELP = `Usage:
|
|
8206
|
-
siteos search project list [--json]
|
|
8207
|
-
siteos search project create --slug <slug> --name <name> [--json]
|
|
8208
|
-
siteos search project use <slug> [--replace] [--json]
|
|
8209
|
-
siteos search project status [--json]
|
|
8210
|
-
siteos search environment list [--json]
|
|
8211
|
-
siteos search environment create --slug <slug> --name <name> [--json]
|
|
8212
|
-
siteos search environment update --environment <slug> --name <name> [--json]
|
|
8213
|
-
siteos search environment fork --source <slug> --slug <slug> --name <name> [--json]
|
|
8214
|
-
siteos search environment delete --environment <slug> [--json]
|
|
8215
6931
|
siteos search analytics --environment <slug> [--json]
|
|
8216
6932
|
siteos search diagnostics --environment <slug> [--json]
|
|
8217
6933
|
siteos search doctor --environment <slug> [--json]
|
|
@@ -8233,13 +6949,27 @@ async function runSearchCommand(options) {
|
|
|
8233
6949
|
if (options.args.some((arg) => splitFlag2(arg)[0] === "--env")) {
|
|
8234
6950
|
return usageError4("Use --environment for SiteOS search environments.");
|
|
8235
6951
|
}
|
|
8236
|
-
|
|
6952
|
+
const environmentFlags = options.args.flatMap(
|
|
6953
|
+
(arg) => arg.startsWith("--environment=") ? ["--environment", arg.slice(14)] : [arg]
|
|
6954
|
+
);
|
|
6955
|
+
const environmentIndex = environmentFlags.indexOf("--environment");
|
|
6956
|
+
options = {
|
|
6957
|
+
...options,
|
|
6958
|
+
selectedEnvironment: environmentIndex >= 0 ? environmentFlags[environmentIndex + 1] : void 0
|
|
6959
|
+
};
|
|
6960
|
+
if (["project", "environment"].includes(options.args[0] ?? ""))
|
|
6961
|
+
return usageError4(
|
|
6962
|
+
"Use `siteos project` to manage Projects and environments."
|
|
6963
|
+
);
|
|
6964
|
+
{
|
|
8237
6965
|
try {
|
|
8238
6966
|
options = {
|
|
8239
6967
|
...options,
|
|
8240
6968
|
args: await commonEnvironmentArguments(options, "search", options.args)
|
|
8241
6969
|
};
|
|
8242
6970
|
} catch (error) {
|
|
6971
|
+
if (error instanceof SiteOSAuthApiError)
|
|
6972
|
+
return formatAuthError2(error).error;
|
|
8243
6973
|
return {
|
|
8244
6974
|
exitCode: 1,
|
|
8245
6975
|
stderr: error instanceof Error ? error.message : "Environment could not be selected."
|
|
@@ -8247,12 +6977,6 @@ async function runSearchCommand(options) {
|
|
|
8247
6977
|
}
|
|
8248
6978
|
}
|
|
8249
6979
|
const [subcommand, ...args2] = options.args;
|
|
8250
|
-
if (subcommand === "project") {
|
|
8251
|
-
return runProjectCommand3({ ...options, args: args2 });
|
|
8252
|
-
}
|
|
8253
|
-
if (subcommand === "environment") {
|
|
8254
|
-
return runEnvironmentCommand2({ ...options, args: args2 });
|
|
8255
|
-
}
|
|
8256
6980
|
if (subcommand === "credential") {
|
|
8257
6981
|
return runCredentialCommand2({ ...options, args: args2, credentialKind: "query" });
|
|
8258
6982
|
}
|
|
@@ -8268,269 +6992,6 @@ async function runSearchCommand(options) {
|
|
|
8268
6992
|
}
|
|
8269
6993
|
return usageError4("Unknown SiteOS search command.");
|
|
8270
6994
|
}
|
|
8271
|
-
async function runProjectCommand3(options) {
|
|
8272
|
-
const action = options.args[0];
|
|
8273
|
-
if (!action || !["create", "list", "status", "use"].includes(action)) {
|
|
8274
|
-
return usageError4("Unknown SiteOS search project command.");
|
|
8275
|
-
}
|
|
8276
|
-
const parsed = parseProjectFlags2(action, options.args.slice(1));
|
|
8277
|
-
if (!parsed.ok) return parsed.error;
|
|
8278
|
-
if (!options.fetchImpl) {
|
|
8279
|
-
return {
|
|
8280
|
-
exitCode: 1,
|
|
8281
|
-
stderr: "SiteOS API access is unavailable in this runtime."
|
|
8282
|
-
};
|
|
8283
|
-
}
|
|
8284
|
-
try {
|
|
8285
|
-
const apiBaseUrl = resolveSiteOSSearchBaseUrl(options.env);
|
|
8286
|
-
const grant = await serviceGrantProvider2(options).acquire({
|
|
8287
|
-
audience: "siteos-search",
|
|
8288
|
-
scopes: ["search:workspace:write"]
|
|
8289
|
-
});
|
|
8290
|
-
requireGrant2(grant, "search:workspace:write");
|
|
8291
|
-
const client = createSiteOSSearchApiClient({
|
|
8292
|
-
apiBaseUrl,
|
|
8293
|
-
fetchImpl: options.fetchImpl
|
|
8294
|
-
});
|
|
8295
|
-
if (action === "list") {
|
|
8296
|
-
const projects2 = await client.listProjects({ token: grant.accessToken });
|
|
8297
|
-
requireProjectOrganization2(projects2, grant.grant.organizationId);
|
|
8298
|
-
return {
|
|
8299
|
-
exitCode: 0,
|
|
8300
|
-
stdout: parsed.json ? stringifySafeJson2({ projects: projects2 }) : formatProjectListOutput2(projects2)
|
|
8301
|
-
};
|
|
8302
|
-
}
|
|
8303
|
-
if (action === "create") {
|
|
8304
|
-
const project2 = await client.createProject({
|
|
8305
|
-
name: parsed.name,
|
|
8306
|
-
slug: parsed.slug,
|
|
8307
|
-
token: grant.accessToken
|
|
8308
|
-
});
|
|
8309
|
-
requireProjectOrganization2([project2], grant.grant.organizationId);
|
|
8310
|
-
return {
|
|
8311
|
-
exitCode: 0,
|
|
8312
|
-
stdout: parsed.json ? stringifySafeJson2({ project: project2 }) : [
|
|
8313
|
-
"SiteOS Search Project created.",
|
|
8314
|
-
`Project: ${project2.slug}`,
|
|
8315
|
-
`Name: ${project2.name}`,
|
|
8316
|
-
`Run \`siteos search project use ${project2.slug}\` to select it for this repository.`
|
|
8317
|
-
].join("\n")
|
|
8318
|
-
};
|
|
8319
|
-
}
|
|
8320
|
-
const reference = await inspectSearchProjectReference(
|
|
8321
|
-
options.cwd ?? process.cwd()
|
|
8322
|
-
);
|
|
8323
|
-
const store = projectBindingStore3(options);
|
|
8324
|
-
const locator = {
|
|
8325
|
-
apiOrigin: apiBaseUrl,
|
|
8326
|
-
repositoryRoot: reference.rootDir,
|
|
8327
|
-
service: "search"
|
|
8328
|
-
};
|
|
8329
|
-
if (action === "use") {
|
|
8330
|
-
const projects2 = await client.listProjects({ token: grant.accessToken });
|
|
8331
|
-
requireProjectOrganization2(projects2, grant.grant.organizationId);
|
|
8332
|
-
const matches = projects2.filter(
|
|
8333
|
-
(project3) => project3.slug === parsed.slug
|
|
8334
|
-
);
|
|
8335
|
-
if (matches.length !== 1) {
|
|
8336
|
-
throw new SiteOSSearchApiError({
|
|
8337
|
-
code: matches.length === 0 ? "PROJECT_NOT_FOUND" : "INVALID_RESPONSE",
|
|
8338
|
-
message: matches.length === 0 ? "The Search Project was not found." : "SiteOS Search returned an invalid response.",
|
|
8339
|
-
status: matches.length === 0 ? 404 : void 0
|
|
8340
|
-
});
|
|
8341
|
-
}
|
|
8342
|
-
const project2 = matches[0];
|
|
8343
|
-
if (reference.status === "loaded" && reference.reference.project.slug !== project2.slug && !parsed.replace) {
|
|
8344
|
-
throw new SearchProjectReferenceError(
|
|
8345
|
-
"SEARCH_PROJECT_REFERENCE_CONFLICT",
|
|
8346
|
-
"A different Search Project is already selected. Use --replace to replace it."
|
|
8347
|
-
);
|
|
8348
|
-
}
|
|
8349
|
-
const previousBinding = await store.read(locator);
|
|
8350
|
-
await store.write({
|
|
8351
|
-
...locator,
|
|
8352
|
-
organizationId: grant.grant.organizationId,
|
|
8353
|
-
project: { id: project2.id, slug: project2.slug }
|
|
8354
|
-
});
|
|
8355
|
-
try {
|
|
8356
|
-
await writeSearchProjectReference({
|
|
8357
|
-
expectedChecksum: reference.status === "loaded" ? reference.checksum : null,
|
|
8358
|
-
project: { name: project2.name, slug: project2.slug },
|
|
8359
|
-
rootDir: reference.rootDir
|
|
8360
|
-
});
|
|
8361
|
-
} catch (error) {
|
|
8362
|
-
if (previousBinding) await store.write(previousBinding);
|
|
8363
|
-
else await store.remove(locator);
|
|
8364
|
-
throw error;
|
|
8365
|
-
}
|
|
8366
|
-
const output2 = {
|
|
8367
|
-
apiOrigin: apiBaseUrl,
|
|
8368
|
-
organizationId: grant.grant.organizationId,
|
|
8369
|
-
project: project2,
|
|
8370
|
-
referencePath: path27.join(
|
|
8371
|
-
reference.rootDir,
|
|
8372
|
-
".siteos",
|
|
8373
|
-
"search",
|
|
8374
|
-
"project.json"
|
|
8375
|
-
)
|
|
8376
|
-
};
|
|
8377
|
-
return {
|
|
8378
|
-
exitCode: 0,
|
|
8379
|
-
stdout: parsed.json ? stringifySafeJson2(output2) : [
|
|
8380
|
-
"SiteOS Search Project selected.",
|
|
8381
|
-
`Project: ${project2.slug}`,
|
|
8382
|
-
`Reference: ${output2.referencePath}`
|
|
8383
|
-
].join("\n")
|
|
8384
|
-
};
|
|
8385
|
-
}
|
|
8386
|
-
if (reference.status === "missing") {
|
|
8387
|
-
throw new SearchProjectReferenceError(
|
|
8388
|
-
"SEARCH_PROJECT_REFERENCE_REQUIRED",
|
|
8389
|
-
"Select a Search Project for this repository first."
|
|
8390
|
-
);
|
|
8391
|
-
}
|
|
8392
|
-
const binding = await store.read(locator);
|
|
8393
|
-
if (!binding || binding.organizationId !== grant.grant.organizationId || binding.project.slug !== reference.reference.project.slug) {
|
|
8394
|
-
throw new SearchProjectReferenceError(
|
|
8395
|
-
binding ? "SEARCH_PROJECT_REFERENCE_INVALID" : "SEARCH_PROJECT_REFERENCE_REQUIRED",
|
|
8396
|
-
binding ? "The Search Project reference and private binding do not match." : "Select a Search Project for this repository first."
|
|
8397
|
-
);
|
|
8398
|
-
}
|
|
8399
|
-
const projects = await client.listProjects({ token: grant.accessToken });
|
|
8400
|
-
requireProjectOrganization2(projects, grant.grant.organizationId);
|
|
8401
|
-
const project = projects.find(
|
|
8402
|
-
(candidate) => candidate.id === binding.project.id
|
|
8403
|
-
);
|
|
8404
|
-
if (!project || project.slug !== binding.project.slug) {
|
|
8405
|
-
throw new SiteOSSearchApiError({
|
|
8406
|
-
code: "PROJECT_NOT_FOUND",
|
|
8407
|
-
message: "The Search Project was not found.",
|
|
8408
|
-
status: 404
|
|
8409
|
-
});
|
|
8410
|
-
}
|
|
8411
|
-
const output = {
|
|
8412
|
-
apiOrigin: apiBaseUrl,
|
|
8413
|
-
connected: true,
|
|
8414
|
-
organizationId: binding.organizationId,
|
|
8415
|
-
project,
|
|
8416
|
-
repositoryRoot: reference.rootDir
|
|
8417
|
-
};
|
|
8418
|
-
return {
|
|
8419
|
-
exitCode: 0,
|
|
8420
|
-
stdout: parsed.json ? stringifySafeJson2(output) : [
|
|
8421
|
-
"SiteOS Search Project connection is valid.",
|
|
8422
|
-
`Project: ${project.slug}`,
|
|
8423
|
-
`Organization: ${binding.organizationId}`,
|
|
8424
|
-
`API: ${apiBaseUrl}`
|
|
8425
|
-
].join("\n")
|
|
8426
|
-
};
|
|
8427
|
-
} catch (error) {
|
|
8428
|
-
return formatProjectError2(error);
|
|
8429
|
-
}
|
|
8430
|
-
}
|
|
8431
|
-
async function runEnvironmentCommand2(options) {
|
|
8432
|
-
const [action, ...args2] = options.args;
|
|
8433
|
-
if (!action || !["list", "create", "update", "fork", "delete"].includes(action)) {
|
|
8434
|
-
return usageError4("Unknown SiteOS search environment command.");
|
|
8435
|
-
}
|
|
8436
|
-
const parsed = parseEnvironmentFlags2(action, args2);
|
|
8437
|
-
if (!parsed.ok) return parsed.error;
|
|
8438
|
-
return runWithSearchClient(options, async ({ client, context }) => {
|
|
8439
|
-
const authorization = {
|
|
8440
|
-
projectId: context.projectId,
|
|
8441
|
-
token: context.credential
|
|
8442
|
-
};
|
|
8443
|
-
if (action === "list") {
|
|
8444
|
-
const environments = await client.listEnvironments(authorization);
|
|
8445
|
-
return {
|
|
8446
|
-
exitCode: 0,
|
|
8447
|
-
stdout: parsed.json ? stringifySafeJson2({ environments }) : [
|
|
8448
|
-
"SiteOS Search Environments.",
|
|
8449
|
-
`Environments: ${environments.length}`,
|
|
8450
|
-
...environments.map(({ slug: slug2, name }) => `- ${slug2}: ${name}`)
|
|
8451
|
-
].join("\n")
|
|
8452
|
-
};
|
|
8453
|
-
}
|
|
8454
|
-
const environment = action === "create" ? await client.createEnvironment({
|
|
8455
|
-
...authorization,
|
|
8456
|
-
slug: parsed.slug,
|
|
8457
|
-
name: parsed.name
|
|
8458
|
-
}) : action === "update" ? await client.updateEnvironment({
|
|
8459
|
-
...authorization,
|
|
8460
|
-
environmentSlug: parsed.environmentSlug,
|
|
8461
|
-
name: parsed.name
|
|
8462
|
-
}) : action === "fork" ? await client.forkEnvironment({
|
|
8463
|
-
...authorization,
|
|
8464
|
-
sourceEnvironmentSlug: parsed.sourceSlug,
|
|
8465
|
-
slug: parsed.slug,
|
|
8466
|
-
name: parsed.name
|
|
8467
|
-
}) : void 0;
|
|
8468
|
-
if (action === "delete") {
|
|
8469
|
-
const result = await client.deleteEnvironment({
|
|
8470
|
-
...authorization,
|
|
8471
|
-
environmentSlug: parsed.environmentSlug
|
|
8472
|
-
});
|
|
8473
|
-
return {
|
|
8474
|
-
exitCode: 0,
|
|
8475
|
-
stdout: parsed.json ? stringifySafeJson2({ environment: parsed.environmentSlug, result }) : `SiteOS Search Environment ${parsed.environmentSlug} deleted.`
|
|
8476
|
-
};
|
|
8477
|
-
}
|
|
8478
|
-
return {
|
|
8479
|
-
exitCode: 0,
|
|
8480
|
-
stdout: parsed.json ? stringifySafeJson2({ environment }) : `SiteOS Search Environment ${environment.slug} ${action === "fork" ? "forked" : action === "create" ? "created" : "updated"}.`
|
|
8481
|
-
};
|
|
8482
|
-
});
|
|
8483
|
-
}
|
|
8484
|
-
function parseEnvironmentFlags2(action, args2) {
|
|
8485
|
-
const required = action === "create" ? [SLUG_FLAG2, NAME_FLAG2] : action === "update" ? [ENVIRONMENT_FLAG2, NAME_FLAG2] : action === "fork" ? [SOURCE_FLAG, SLUG_FLAG2, NAME_FLAG2] : action === "delete" ? [ENVIRONMENT_FLAG2] : [];
|
|
8486
|
-
const allowed = /* @__PURE__ */ new Set([JSON_FLAG2, ...required]);
|
|
8487
|
-
const flags = /* @__PURE__ */ new Map();
|
|
8488
|
-
for (let index = 0; index < args2.length; index += 1) {
|
|
8489
|
-
const [flag, inlineValue] = splitFlag2(args2[index]);
|
|
8490
|
-
if (!allowed.has(flag) || flags.has(flag)) {
|
|
8491
|
-
return { error: usageError4(`Unexpected argument: ${flag}`), ok: false };
|
|
8492
|
-
}
|
|
8493
|
-
if (flag === JSON_FLAG2) {
|
|
8494
|
-
if (inlineValue !== void 0) {
|
|
8495
|
-
return {
|
|
8496
|
-
error: usageError4("--json does not accept a value."),
|
|
8497
|
-
ok: false
|
|
8498
|
-
};
|
|
8499
|
-
}
|
|
8500
|
-
flags.set(flag, true);
|
|
8501
|
-
continue;
|
|
8502
|
-
}
|
|
8503
|
-
const value = inlineValue ?? args2[index + 1];
|
|
8504
|
-
if (!value || value.startsWith("--")) {
|
|
8505
|
-
return { error: usageError4(`${flag} requires a value.`), ok: false };
|
|
8506
|
-
}
|
|
8507
|
-
flags.set(flag, value.trim());
|
|
8508
|
-
if (inlineValue === void 0) index += 1;
|
|
8509
|
-
}
|
|
8510
|
-
for (const flag of required) {
|
|
8511
|
-
if (!flags.has(flag))
|
|
8512
|
-
return { error: usageError4(`${flag} is required.`), ok: false };
|
|
8513
|
-
}
|
|
8514
|
-
const environmentSlug = readCredentialStringFlag(flags, ENVIRONMENT_FLAG2);
|
|
8515
|
-
const sourceSlug = readCredentialStringFlag(flags, SOURCE_FLAG);
|
|
8516
|
-
const slug2 = readCredentialStringFlag(flags, SLUG_FLAG2);
|
|
8517
|
-
if ([environmentSlug, sourceSlug, slug2].some(
|
|
8518
|
-
(value) => value && !isValidEnvironmentSlug(value)
|
|
8519
|
-
)) {
|
|
8520
|
-
return { error: usageError4("Environment slugs must be valid."), ok: false };
|
|
8521
|
-
}
|
|
8522
|
-
const name = readCredentialStringFlag(flags, NAME_FLAG2);
|
|
8523
|
-
if (name && name.length > 255)
|
|
8524
|
-
return { error: usageError4("--name is invalid."), ok: false };
|
|
8525
|
-
return {
|
|
8526
|
-
...environmentSlug ? { environmentSlug } : {},
|
|
8527
|
-
json: flags.has(JSON_FLAG2),
|
|
8528
|
-
...name ? { name } : {},
|
|
8529
|
-
ok: true,
|
|
8530
|
-
...slug2 ? { slug: slug2 } : {},
|
|
8531
|
-
...sourceSlug ? { sourceSlug } : {}
|
|
8532
|
-
};
|
|
8533
|
-
}
|
|
8534
6995
|
async function runCredentialCommand2(options) {
|
|
8535
6996
|
const action = options.args[0];
|
|
8536
6997
|
if (!action || !["issue", "list", "revoke", "rotate"].includes(action)) {
|
|
@@ -8703,18 +7164,12 @@ async function completeCredentialInstallation(options) {
|
|
|
8703
7164
|
async function loadCredentialManagementContext2(options) {
|
|
8704
7165
|
try {
|
|
8705
7166
|
const local = await readLocalCommonProject(options);
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
);
|
|
8711
|
-
|
|
8712
|
-
throw new SearchProjectReferenceError(
|
|
8713
|
-
"SEARCH_PROJECT_REFERENCE_REQUIRED",
|
|
8714
|
-
"Select a Search Project for this repository first."
|
|
8715
|
-
);
|
|
8716
|
-
rootDir = reference.rootDir;
|
|
8717
|
-
}
|
|
7167
|
+
if (!local)
|
|
7168
|
+
throw new SiteOSAuthApiError({
|
|
7169
|
+
code: "PROJECT_REQUIRED",
|
|
7170
|
+
message: "Select a Project with `siteos project use <id-or-slug>`."
|
|
7171
|
+
});
|
|
7172
|
+
const rootDir = local.rootDir;
|
|
8718
7173
|
const installation = options.install ? await (options.credentialKind === "query" ? options.prepareCredentialInstallation ?? prepareSiteOSSearchCredentialInstallation : options.prepareIndexingCredentialInstallation ?? prepareSiteOSSearchIndexingCredentialInstallation)({ projectRoot: rootDir }) : void 0;
|
|
8719
7174
|
const context = await loadSearchContext(options, "search:credential:issue");
|
|
8720
7175
|
if (!context.ok) return context;
|
|
@@ -8806,21 +7261,30 @@ async function loadSearchContext(options, requiredScope = "search:workspace:writ
|
|
|
8806
7261
|
};
|
|
8807
7262
|
}
|
|
8808
7263
|
try {
|
|
8809
|
-
const common = await commonServiceContext(
|
|
8810
|
-
|
|
8811
|
-
|
|
7264
|
+
const common = await commonServiceContext(
|
|
7265
|
+
options,
|
|
7266
|
+
"search",
|
|
7267
|
+
options.selectedEnvironment
|
|
7268
|
+
);
|
|
7269
|
+
if (!common)
|
|
7270
|
+
throw new SiteOSAuthApiError({
|
|
7271
|
+
code: "PROJECT_REQUIRED",
|
|
7272
|
+
message: "Select a Project with `siteos project use <id-or-slug>`."
|
|
7273
|
+
});
|
|
7274
|
+
{
|
|
7275
|
+
const grant = await serviceGrantProvider2(options).acquire({
|
|
8812
7276
|
audience: "siteos-search",
|
|
8813
7277
|
scopes: [requiredScope]
|
|
8814
7278
|
});
|
|
8815
|
-
requireGrant2(
|
|
8816
|
-
if (
|
|
7279
|
+
requireGrant2(grant, requiredScope);
|
|
7280
|
+
if (grant.grant.organizationId !== common.overview.project.organizationId)
|
|
8817
7281
|
throw new SiteOSAuthApiError({
|
|
8818
7282
|
code: "PROJECT_ORGANIZATION_MISMATCH",
|
|
8819
7283
|
message: "The Project and service grant belong to different organizations."
|
|
8820
7284
|
});
|
|
8821
7285
|
return {
|
|
8822
7286
|
apiBaseUrl: common.api.origin,
|
|
8823
|
-
credential:
|
|
7287
|
+
credential: grant.accessToken,
|
|
8824
7288
|
ok: true,
|
|
8825
7289
|
project: {
|
|
8826
7290
|
id: common.resourceId,
|
|
@@ -8831,53 +7295,9 @@ async function loadSearchContext(options, requiredScope = "search:workspace:writ
|
|
|
8831
7295
|
rootDir: common.rootDir
|
|
8832
7296
|
};
|
|
8833
7297
|
}
|
|
8834
|
-
const reference = await inspectSearchProjectReference(
|
|
8835
|
-
options.cwd ?? process.cwd()
|
|
8836
|
-
);
|
|
8837
|
-
if (reference.status === "missing") {
|
|
8838
|
-
throw new SearchProjectReferenceError(
|
|
8839
|
-
"SEARCH_PROJECT_REFERENCE_REQUIRED",
|
|
8840
|
-
"Select a Search Project for this repository first."
|
|
8841
|
-
);
|
|
8842
|
-
}
|
|
8843
|
-
const apiBaseUrl = resolveSiteOSSearchBaseUrl(options.env);
|
|
8844
|
-
const binding = await projectBindingStore3(options).read({
|
|
8845
|
-
apiOrigin: apiBaseUrl,
|
|
8846
|
-
repositoryRoot: reference.rootDir,
|
|
8847
|
-
service: "search"
|
|
8848
|
-
});
|
|
8849
|
-
if (!binding) {
|
|
8850
|
-
throw new SearchProjectReferenceError(
|
|
8851
|
-
"SEARCH_PROJECT_REFERENCE_REQUIRED",
|
|
8852
|
-
"Select a Search Project for this repository first."
|
|
8853
|
-
);
|
|
8854
|
-
}
|
|
8855
|
-
const grant = await serviceGrantProvider2(options).acquire({
|
|
8856
|
-
audience: "siteos-search",
|
|
8857
|
-
scopes: [requiredScope]
|
|
8858
|
-
});
|
|
8859
|
-
requireGrant2(grant, requiredScope);
|
|
8860
|
-
if (grant.grant.organizationId !== binding.organizationId || binding.project.slug !== reference.reference.project.slug) {
|
|
8861
|
-
throw new SearchProjectReferenceError(
|
|
8862
|
-
"SEARCH_PROJECT_REFERENCE_INVALID",
|
|
8863
|
-
"The Search Project reference, private binding, and Auth Organization do not match."
|
|
8864
|
-
);
|
|
8865
|
-
}
|
|
8866
|
-
return {
|
|
8867
|
-
apiBaseUrl,
|
|
8868
|
-
credential: grant.accessToken,
|
|
8869
|
-
ok: true,
|
|
8870
|
-
project: {
|
|
8871
|
-
id: binding.project.id,
|
|
8872
|
-
name: reference.reference.project.name,
|
|
8873
|
-
slug: binding.project.slug
|
|
8874
|
-
},
|
|
8875
|
-
projectId: binding.project.id,
|
|
8876
|
-
rootDir: reference.rootDir
|
|
8877
|
-
};
|
|
8878
7298
|
} catch (error) {
|
|
8879
7299
|
if (error instanceof SiteOSAuthApiError) return formatAuthError2(error);
|
|
8880
|
-
return { error:
|
|
7300
|
+
return { error: formatProjectError(error), ok: false };
|
|
8881
7301
|
}
|
|
8882
7302
|
}
|
|
8883
7303
|
function formatAuthError2(error) {
|
|
@@ -8903,92 +7323,6 @@ function formatAuthError2(error) {
|
|
|
8903
7323
|
ok: false
|
|
8904
7324
|
};
|
|
8905
7325
|
}
|
|
8906
|
-
function parseProjectFlags2(action, args2) {
|
|
8907
|
-
const flags = /* @__PURE__ */ new Map();
|
|
8908
|
-
const positionals = [];
|
|
8909
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
8910
|
-
JSON_FLAG2,
|
|
8911
|
-
...action === "create" ? [NAME_FLAG2, SLUG_FLAG2] : [],
|
|
8912
|
-
...action === "use" ? [REPLACE_FLAG2] : []
|
|
8913
|
-
]);
|
|
8914
|
-
const boolean = /* @__PURE__ */ new Set([JSON_FLAG2, REPLACE_FLAG2]);
|
|
8915
|
-
for (let index = 0; index < args2.length; index += 1) {
|
|
8916
|
-
const arg = args2[index];
|
|
8917
|
-
if (!arg.startsWith("--")) {
|
|
8918
|
-
positionals.push(arg);
|
|
8919
|
-
continue;
|
|
8920
|
-
}
|
|
8921
|
-
const [flag, inlineValue] = splitFlag2(arg);
|
|
8922
|
-
if (!allowed.has(flag) || flags.has(flag)) {
|
|
8923
|
-
return { error: usageError4(`Unexpected argument: ${flag}`), ok: false };
|
|
8924
|
-
}
|
|
8925
|
-
if (boolean.has(flag)) {
|
|
8926
|
-
if (inlineValue !== void 0) {
|
|
8927
|
-
return {
|
|
8928
|
-
error: usageError4(`${flag} does not accept a value.`),
|
|
8929
|
-
ok: false
|
|
8930
|
-
};
|
|
8931
|
-
}
|
|
8932
|
-
flags.set(flag, true);
|
|
8933
|
-
continue;
|
|
8934
|
-
}
|
|
8935
|
-
const value = inlineValue ?? args2[index + 1];
|
|
8936
|
-
if (!value || value.startsWith("--")) {
|
|
8937
|
-
return { error: usageError4(`${flag} requires a value.`), ok: false };
|
|
8938
|
-
}
|
|
8939
|
-
flags.set(flag, value.trim());
|
|
8940
|
-
if (inlineValue === void 0) index += 1;
|
|
8941
|
-
}
|
|
8942
|
-
if (action === "use") {
|
|
8943
|
-
if (positionals.length !== 1 || !isValidProjectSlug(positionals[0])) {
|
|
8944
|
-
return {
|
|
8945
|
-
error: usageError4(
|
|
8946
|
-
"Project use requires exactly one valid Project slug."
|
|
8947
|
-
),
|
|
8948
|
-
ok: false
|
|
8949
|
-
};
|
|
8950
|
-
}
|
|
8951
|
-
return {
|
|
8952
|
-
json: flags.has(JSON_FLAG2),
|
|
8953
|
-
ok: true,
|
|
8954
|
-
replace: flags.has(REPLACE_FLAG2),
|
|
8955
|
-
slug: positionals[0]
|
|
8956
|
-
};
|
|
8957
|
-
}
|
|
8958
|
-
if (positionals.length > 0) {
|
|
8959
|
-
return {
|
|
8960
|
-
error: usageError4(`Unexpected argument: ${positionals[0]}`),
|
|
8961
|
-
ok: false
|
|
8962
|
-
};
|
|
8963
|
-
}
|
|
8964
|
-
if (action !== "create") {
|
|
8965
|
-
return { json: flags.has(JSON_FLAG2), ok: true, replace: false };
|
|
8966
|
-
}
|
|
8967
|
-
const slug2 = readCredentialStringFlag(flags, SLUG_FLAG2);
|
|
8968
|
-
const name = readCredentialStringFlag(flags, NAME_FLAG2);
|
|
8969
|
-
if (!slug2 || !isValidProjectSlug(slug2)) {
|
|
8970
|
-
return {
|
|
8971
|
-
error: usageError4("--slug is required and must be valid."),
|
|
8972
|
-
ok: false
|
|
8973
|
-
};
|
|
8974
|
-
}
|
|
8975
|
-
if (!name || name.length > 255) {
|
|
8976
|
-
return {
|
|
8977
|
-
error: usageError4("--name is required and must be valid."),
|
|
8978
|
-
ok: false
|
|
8979
|
-
};
|
|
8980
|
-
}
|
|
8981
|
-
return {
|
|
8982
|
-
json: flags.has(JSON_FLAG2),
|
|
8983
|
-
name,
|
|
8984
|
-
ok: true,
|
|
8985
|
-
replace: false,
|
|
8986
|
-
slug: slug2
|
|
8987
|
-
};
|
|
8988
|
-
}
|
|
8989
|
-
function isValidProjectSlug(value) {
|
|
8990
|
-
return value.length >= 1 && value.length <= 120 && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);
|
|
8991
|
-
}
|
|
8992
7326
|
function parseCredentialFlags2(action, args2, credentialKind) {
|
|
8993
7327
|
const installs = action === "issue" || action === "rotate";
|
|
8994
7328
|
const revokes = action === "revoke";
|
|
@@ -9120,7 +7454,7 @@ function formatCredentialError2(error) {
|
|
|
9120
7454
|
stderr: "SiteOS Search credential request failed."
|
|
9121
7455
|
};
|
|
9122
7456
|
}
|
|
9123
|
-
function
|
|
7457
|
+
function formatProjectError(error) {
|
|
9124
7458
|
if (error instanceof SiteOSAuthApiError) return formatAuthError2(error).error;
|
|
9125
7459
|
if (error instanceof SiteOSSearchApiError) {
|
|
9126
7460
|
return {
|
|
@@ -9132,7 +7466,7 @@ function formatProjectError2(error) {
|
|
|
9132
7466
|
].filter((line) => Boolean(line)).join("\n")
|
|
9133
7467
|
};
|
|
9134
7468
|
}
|
|
9135
|
-
if (error instanceof
|
|
7469
|
+
if (error instanceof ProjectBindingStoreError || error instanceof RepositoryRootError) {
|
|
9136
7470
|
return {
|
|
9137
7471
|
exitCode: 1,
|
|
9138
7472
|
stderr: [
|
|
@@ -9150,14 +7484,6 @@ function serviceGrantProvider2(options) {
|
|
|
9150
7484
|
fetchImpl: options.fetchImpl
|
|
9151
7485
|
});
|
|
9152
7486
|
}
|
|
9153
|
-
function projectBindingStore3(options) {
|
|
9154
|
-
return options.projectBindingStore ?? new NodeProjectBindingStore(
|
|
9155
|
-
path27.join(
|
|
9156
|
-
resolveSiteOSConfigHome({ env: options.env }),
|
|
9157
|
-
"project-bindings.json"
|
|
9158
|
-
)
|
|
9159
|
-
);
|
|
9160
|
-
}
|
|
9161
7487
|
function requireGrant2(grant, scope) {
|
|
9162
7488
|
if (grant.grant.audience !== "siteos-search" || grant.grant.scopes.length !== 1 || grant.grant.scopes[0] !== scope) {
|
|
9163
7489
|
throw new SiteOSAuthApiError({
|
|
@@ -9166,23 +7492,6 @@ function requireGrant2(grant, scope) {
|
|
|
9166
7492
|
});
|
|
9167
7493
|
}
|
|
9168
7494
|
}
|
|
9169
|
-
function requireProjectOrganization2(projects, organizationId) {
|
|
9170
|
-
if (projects.some((project) => project.organizationId !== organizationId)) {
|
|
9171
|
-
throw new SiteOSSearchApiError({
|
|
9172
|
-
code: "INVALID_RESPONSE",
|
|
9173
|
-
message: "SiteOS Search returned an invalid response."
|
|
9174
|
-
});
|
|
9175
|
-
}
|
|
9176
|
-
}
|
|
9177
|
-
function formatProjectListOutput2(projects) {
|
|
9178
|
-
return [
|
|
9179
|
-
"SiteOS Search Projects.",
|
|
9180
|
-
`Projects: ${projects.length}`,
|
|
9181
|
-
...projects.map(
|
|
9182
|
-
(project) => `- ${project.slug}: ${project.name} (${project.id})`
|
|
9183
|
-
)
|
|
9184
|
-
].join("\n");
|
|
9185
|
-
}
|
|
9186
7495
|
function formatCredentialListOutput2(input) {
|
|
9187
7496
|
return [
|
|
9188
7497
|
`SiteOS Search ${credentialKindLabel(input.credentialKind)} credentials.`,
|
|
@@ -9254,7 +7563,7 @@ var PROJECT_HELP = `One Project for your website and all its services.
|
|
|
9254
7563
|
Usage:
|
|
9255
7564
|
siteos project list [--json]
|
|
9256
7565
|
siteos project create --name <name> --slug <slug> [--url <url>] [--domain <domain>] [--json]
|
|
9257
|
-
siteos project use <id-or-slug> [--json]
|
|
7566
|
+
siteos project use <id-or-slug> [--environment <slug>] [--json]
|
|
9258
7567
|
siteos project update [--name <name>] [--slug <slug>] [--url <production-url>] [--json]
|
|
9259
7568
|
siteos project status [--json]
|
|
9260
7569
|
siteos project connect <pulse|cookie|forms|search|trace|seo|analytics> [--resource <id>] [--json]
|
|
@@ -9268,13 +7577,13 @@ Usage:
|
|
|
9268
7577
|
Select a Project once per repository. Service commands use its configured resources.
|
|
9269
7578
|
Connect creates a draft workspace, or explicitly attaches an existing resource.
|
|
9270
7579
|
It does not publish a banner, install a script, send a notification or deploy checks.`;
|
|
9271
|
-
async function
|
|
7580
|
+
async function runProjectCommand(options) {
|
|
9272
7581
|
if (!options.args.length || options.args.some((arg) => arg === "--help" || arg === "-h"))
|
|
9273
7582
|
return { exitCode: 0, stdout: PROJECT_HELP };
|
|
9274
7583
|
try {
|
|
9275
7584
|
const [action, ...args2] = options.args;
|
|
9276
7585
|
if (action === "environment")
|
|
9277
|
-
return await
|
|
7586
|
+
return await runEnvironmentCommand({ ...options, args: args2 });
|
|
9278
7587
|
if (!["list", "create", "use", "status", "connect", "update"].includes(
|
|
9279
7588
|
action
|
|
9280
7589
|
))
|
|
@@ -9285,6 +7594,7 @@ async function runProjectCommand4(options) {
|
|
|
9285
7594
|
strict: true,
|
|
9286
7595
|
options: {
|
|
9287
7596
|
json: { type: "boolean" },
|
|
7597
|
+
...action === "use" ? { environment: { type: "string" } } : {},
|
|
9288
7598
|
...action === "create" || action === "update" ? {
|
|
9289
7599
|
name: { type: "string" },
|
|
9290
7600
|
slug: { type: "string" },
|
|
@@ -9324,15 +7634,23 @@ Select it with \`siteos project use ${project.slug}\`.`;
|
|
|
9324
7634
|
matches.length ? "Use the exact Project ID to disambiguate this selection." : "Project not found in the active organization."
|
|
9325
7635
|
);
|
|
9326
7636
|
const project = matches[0];
|
|
7637
|
+
const environment = project.environments.find(
|
|
7638
|
+
(item) => item.slug === (parsed.values.environment ?? "production")
|
|
7639
|
+
);
|
|
7640
|
+
if (!environment)
|
|
7641
|
+
throw new Error(
|
|
7642
|
+
"Select an available Project environment with --environment <slug>."
|
|
7643
|
+
);
|
|
9327
7644
|
await store.write({
|
|
9328
7645
|
apiOrigin: api.origin,
|
|
9329
7646
|
repositoryRoot: await findRepositoryRoot(options.cwd ?? process.cwd()),
|
|
9330
7647
|
service: "project",
|
|
9331
7648
|
organizationId: project.organizationId,
|
|
9332
|
-
project: { id: project.id, slug: project.slug }
|
|
7649
|
+
project: { id: project.id, slug: project.slug },
|
|
7650
|
+
environmentSlug: environment.slug
|
|
9333
7651
|
});
|
|
9334
|
-
result = { project };
|
|
9335
|
-
message = `Selected ${project.name} for this repository.
|
|
7652
|
+
result = { project, environment };
|
|
7653
|
+
message = `Selected ${project.name} / ${environment.name} for this repository.
|
|
9336
7654
|
Run \`siteos project status\` to inspect its services.`;
|
|
9337
7655
|
} else {
|
|
9338
7656
|
const context = await readCommonProject(options);
|
|
@@ -9388,7 +7706,7 @@ ${overview.services.map((service) => `${service.service}: ${service.observation?
|
|
|
9388
7706
|
function projectLabel(project) {
|
|
9389
7707
|
return `${project.name} (${project.slug})`;
|
|
9390
7708
|
}
|
|
9391
|
-
async function
|
|
7709
|
+
async function runEnvironmentCommand(options) {
|
|
9392
7710
|
const [action, ...args2] = options.args;
|
|
9393
7711
|
if (!["list", "create", "connect", "resources", "use", "update"].includes(
|
|
9394
7712
|
action
|
|
@@ -9424,7 +7742,7 @@ async function runEnvironmentCommand3(options) {
|
|
|
9424
7742
|
throw new Error("Choose a Project environment with --environment <slug>.");
|
|
9425
7743
|
const context = await readCommonProject(
|
|
9426
7744
|
options,
|
|
9427
|
-
action === "use" ?
|
|
7745
|
+
action === "use" ? positionals[0] : void 0
|
|
9428
7746
|
);
|
|
9429
7747
|
if (!context)
|
|
9430
7748
|
throw new Error("Select a Project with `siteos project use` first.");
|
|
@@ -9501,13 +7819,13 @@ async function runEnvironmentCommand3(options) {
|
|
|
9501
7819
|
}
|
|
9502
7820
|
|
|
9503
7821
|
// src/services/service-command.ts
|
|
9504
|
-
import { readFile as
|
|
9505
|
-
import
|
|
7822
|
+
import { readFile as readFile15, stat } from "fs/promises";
|
|
7823
|
+
import path24 from "path";
|
|
9506
7824
|
import { parseArgs as parseArgs3 } from "util";
|
|
9507
|
-
import { z as
|
|
7825
|
+
import { z as z13 } from "zod";
|
|
9508
7826
|
|
|
9509
7827
|
// src/services/trace-explorer-command.ts
|
|
9510
|
-
import { z as
|
|
7828
|
+
import { z as z11 } from "zod";
|
|
9511
7829
|
var filters = [
|
|
9512
7830
|
"environment",
|
|
9513
7831
|
"provider",
|
|
@@ -9530,8 +7848,8 @@ var TRACE_EXPLORER_FLAGS = {
|
|
|
9530
7848
|
"issue show": ["environment", "id", "cursor"],
|
|
9531
7849
|
"observation show": ["environment", "batch-id", "event-id"]
|
|
9532
7850
|
};
|
|
9533
|
-
var FilterValues =
|
|
9534
|
-
provider:
|
|
7851
|
+
var FilterValues = z11.object({
|
|
7852
|
+
provider: z11.enum([
|
|
9535
7853
|
"siteos_analytics",
|
|
9536
7854
|
"ga4",
|
|
9537
7855
|
"google_ads",
|
|
@@ -9539,11 +7857,11 @@ var FilterValues = z14.object({
|
|
|
9539
7857
|
"meta",
|
|
9540
7858
|
"custom"
|
|
9541
7859
|
]).optional(),
|
|
9542
|
-
event:
|
|
9543
|
-
property:
|
|
9544
|
-
"page-view":
|
|
9545
|
-
search:
|
|
9546
|
-
state:
|
|
7860
|
+
event: z11.string().min(1).max(160).optional(),
|
|
7861
|
+
property: z11.string().min(1).max(160).optional(),
|
|
7862
|
+
"page-view": z11.string().uuid().optional(),
|
|
7863
|
+
search: z11.string().max(160).optional(),
|
|
7864
|
+
state: z11.enum([
|
|
9547
7865
|
"all",
|
|
9548
7866
|
"active",
|
|
9549
7867
|
"snoozed",
|
|
@@ -9553,8 +7871,8 @@ var FilterValues = z14.object({
|
|
|
9553
7871
|
"tracked",
|
|
9554
7872
|
"ignored"
|
|
9555
7873
|
]).optional(),
|
|
9556
|
-
rule:
|
|
9557
|
-
kind:
|
|
7874
|
+
rule: z11.string().min(1).max(80).optional(),
|
|
7875
|
+
kind: z11.enum([
|
|
9558
7876
|
"data_layer",
|
|
9559
7877
|
"fetch",
|
|
9560
7878
|
"xhr",
|
|
@@ -9564,8 +7882,8 @@ var FilterValues = z14.object({
|
|
|
9564
7882
|
"heartbeat",
|
|
9565
7883
|
"runtime_diagnostic"
|
|
9566
7884
|
]).optional(),
|
|
9567
|
-
period:
|
|
9568
|
-
cursor:
|
|
7885
|
+
period: z11.enum(["24h", "7d"]).optional(),
|
|
7886
|
+
cursor: z11.string().min(1).max(4096).optional()
|
|
9569
7887
|
});
|
|
9570
7888
|
function traceExplorerSuffix(route, values) {
|
|
9571
7889
|
if (!TRACE_EXPLORER_FLAGS[route]) return null;
|
|
@@ -9573,11 +7891,11 @@ function traceExplorerSuffix(route, values) {
|
|
|
9573
7891
|
if (route === "issue show" || route === "observation show") {
|
|
9574
7892
|
const keys = route === "issue show" ? ["id"] : ["batch-id", "event-id"];
|
|
9575
7893
|
for (const key of keys) {
|
|
9576
|
-
if (!
|
|
7894
|
+
if (!z11.string().uuid().safeParse(values[key]).success)
|
|
9577
7895
|
throw new Error(`Use --${key} with the UUID returned by Trace.`);
|
|
9578
7896
|
}
|
|
9579
7897
|
if (values.cursor !== void 0) {
|
|
9580
|
-
if (!
|
|
7898
|
+
if (!z11.string().uuid().safeParse(values.cursor).success)
|
|
9581
7899
|
throw new Error(
|
|
9582
7900
|
"Use --cursor with the nextCursor returned by this issue."
|
|
9583
7901
|
);
|
|
@@ -9814,8 +8132,8 @@ async function runServiceCommand(service, options) {
|
|
|
9814
8132
|
);
|
|
9815
8133
|
const result2 = await response.json();
|
|
9816
8134
|
if (!response.ok) {
|
|
9817
|
-
const error =
|
|
9818
|
-
error:
|
|
8135
|
+
const error = z13.object({
|
|
8136
|
+
error: z13.object({ code: z13.string(), message: z13.string().max(500) })
|
|
9819
8137
|
}).safeParse(result2);
|
|
9820
8138
|
throw new SiteOSAuthApiError({
|
|
9821
8139
|
code: error.success ? error.data.error.code : "SERVICE_REQUEST_FAILED",
|
|
@@ -9828,11 +8146,11 @@ async function runServiceCommand(service, options) {
|
|
|
9828
8146
|
async function inputFile() {
|
|
9829
8147
|
if (!values.input)
|
|
9830
8148
|
throw new Error("This operation requires --input <json-file>.");
|
|
9831
|
-
const filename =
|
|
8149
|
+
const filename = path24.resolve(options.cwd ?? process.cwd(), values.input);
|
|
9832
8150
|
const info = await stat(filename);
|
|
9833
8151
|
if (!info.isFile() || info.size > 512 * 1024)
|
|
9834
8152
|
throw new Error("Use a JSON file smaller than 512 KB.");
|
|
9835
|
-
return JSON.parse(await
|
|
8153
|
+
return JSON.parse(await readFile15(filename, "utf8"));
|
|
9836
8154
|
}
|
|
9837
8155
|
const site = common ? `/sites/${encodeURIComponent(common.resourceId)}` : "";
|
|
9838
8156
|
let result;
|
|
@@ -9852,9 +8170,9 @@ async function runServiceCommand(service, options) {
|
|
|
9852
8170
|
await inputFile(),
|
|
9853
8171
|
"cookie:workspace:read"
|
|
9854
8172
|
);
|
|
9855
|
-
const validation =
|
|
9856
|
-
valid:
|
|
9857
|
-
draftVersionMatches:
|
|
8173
|
+
const validation = z13.object({
|
|
8174
|
+
valid: z13.boolean(),
|
|
8175
|
+
draftVersionMatches: z13.boolean().optional()
|
|
9858
8176
|
}).parse(result);
|
|
9859
8177
|
if (!validation.valid || validation.draftVersionMatches === false)
|
|
9860
8178
|
return { exitCode: 2, stdout: JSON.stringify(result, null, 2) };
|
|
@@ -9893,11 +8211,11 @@ async function runServiceCommand(service, options) {
|
|
|
9893
8211
|
} else if (action === "installation")
|
|
9894
8212
|
result = await request(`${site}/installation`);
|
|
9895
8213
|
else if (action === "draft" && subaction === "get" && positionals.length === 2) {
|
|
9896
|
-
const response =
|
|
9897
|
-
name:
|
|
9898
|
-
hostname:
|
|
9899
|
-
draftVersion:
|
|
9900
|
-
draft:
|
|
8214
|
+
const response = z13.object({
|
|
8215
|
+
name: z13.string(),
|
|
8216
|
+
hostname: z13.string(),
|
|
8217
|
+
draftVersion: z13.number(),
|
|
8218
|
+
draft: z13.unknown()
|
|
9901
8219
|
}).parse(await request(site));
|
|
9902
8220
|
result = {
|
|
9903
8221
|
name: response.name,
|
|
@@ -9929,9 +8247,9 @@ async function runServiceCommand(service, options) {
|
|
|
9929
8247
|
else if (action === "environments" && positionals.length === 1)
|
|
9930
8248
|
result = await request(`${site}/environments`);
|
|
9931
8249
|
else if (action === "report" || action === "installation" || action === "tracking-plan" || explorerSuffix !== null) {
|
|
9932
|
-
const response =
|
|
9933
|
-
environments:
|
|
9934
|
-
|
|
8250
|
+
const response = z13.object({
|
|
8251
|
+
environments: z13.array(
|
|
8252
|
+
z13.object({ id: z13.string(), slug: z13.string() })
|
|
9935
8253
|
)
|
|
9936
8254
|
}).parse(await request(`${site}/environments`));
|
|
9937
8255
|
const environment = common.overview.project.environments.find(
|
|
@@ -9958,11 +8276,11 @@ async function runServiceCommand(service, options) {
|
|
|
9958
8276
|
if (explorerSuffix !== null) {
|
|
9959
8277
|
result = await request(`${base}${explorerSuffix}`);
|
|
9960
8278
|
} else if (action === "report" && positionals.length === 1) {
|
|
9961
|
-
const detail =
|
|
9962
|
-
site:
|
|
9963
|
-
id:
|
|
9964
|
-
environments:
|
|
9965
|
-
|
|
8279
|
+
const detail = z13.object({
|
|
8280
|
+
site: z13.object({
|
|
8281
|
+
id: z13.literal(common.resourceId),
|
|
8282
|
+
environments: z13.array(
|
|
8283
|
+
z13.object({ id: z13.string(), evidence: z13.unknown() })
|
|
9966
8284
|
)
|
|
9967
8285
|
})
|
|
9968
8286
|
}).parse(await request(site));
|
|
@@ -10020,16 +8338,16 @@ async function runServiceCommand(service, options) {
|
|
|
10020
8338
|
} catch (cause) {
|
|
10021
8339
|
return {
|
|
10022
8340
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
10023
|
-
stderr: cause instanceof SiteOSAuthApiError || !(cause instanceof
|
|
8341
|
+
stderr: cause instanceof SiteOSAuthApiError || !(cause instanceof z13.ZodError) && cause instanceof Error ? cause.message : "The service returned an invalid response."
|
|
10024
8342
|
};
|
|
10025
8343
|
}
|
|
10026
8344
|
}
|
|
10027
8345
|
|
|
10028
8346
|
// src/services/analytics-command.ts
|
|
10029
|
-
import { readFile as
|
|
10030
|
-
import
|
|
8347
|
+
import { readFile as readFile16, stat as stat2 } from "fs/promises";
|
|
8348
|
+
import path25 from "path";
|
|
10031
8349
|
import { parseArgs as parseArgs4 } from "util";
|
|
10032
|
-
import { z as
|
|
8350
|
+
import { z as z14 } from "zod";
|
|
10033
8351
|
var ANALYTICS_HELP = `Set up website Analytics in the selected Project environment.
|
|
10034
8352
|
|
|
10035
8353
|
Usage:
|
|
@@ -10060,27 +8378,27 @@ Settings require an owner/admin, the current revision and at least one change.
|
|
|
10060
8378
|
Catalog files are bounded JSON using the documented event/campaign/goal/funnel contracts.
|
|
10061
8379
|
Monitoring preparation creates a Trace draft only; publication remains a separate operation.
|
|
10062
8380
|
Analytics is Unlimited during early access. No synthetic events are sent by these commands.`;
|
|
10063
|
-
var EventInput =
|
|
10064
|
-
name:
|
|
10065
|
-
label:
|
|
10066
|
-
properties:
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
|
|
8381
|
+
var EventInput = z14.object({
|
|
8382
|
+
name: z14.string().regex(/^[a-z][a-z0-9_]{0,63}$/u).refine((v) => v !== "pageview" && !v.startsWith("cookie_")),
|
|
8383
|
+
label: z14.string().trim().min(1).max(80),
|
|
8384
|
+
properties: z14.record(
|
|
8385
|
+
z14.string().regex(/^[a-z][a-z0-9_]{0,39}$/u),
|
|
8386
|
+
z14.array(
|
|
8387
|
+
z14.string().min(1).max(80).regex(/^[a-zA-Z0-9 _./:-]+$/u)
|
|
10070
8388
|
).min(1).max(20)
|
|
10071
8389
|
).refine((v) => Object.keys(v).length <= 8)
|
|
10072
8390
|
}).strict();
|
|
10073
|
-
var Resource =
|
|
10074
|
-
id:
|
|
10075
|
-
organizationId:
|
|
10076
|
-
name:
|
|
10077
|
-
slug:
|
|
10078
|
-
origin:
|
|
10079
|
-
publicKey:
|
|
10080
|
-
revision:
|
|
10081
|
-
enabled:
|
|
10082
|
-
cookieEvents:
|
|
10083
|
-
minimalRealtime:
|
|
8391
|
+
var Resource = z14.object({
|
|
8392
|
+
id: z14.string(),
|
|
8393
|
+
organizationId: z14.string(),
|
|
8394
|
+
name: z14.string(),
|
|
8395
|
+
slug: z14.string(),
|
|
8396
|
+
origin: z14.string().url(),
|
|
8397
|
+
publicKey: z14.string(),
|
|
8398
|
+
revision: z14.number().int().positive(),
|
|
8399
|
+
enabled: z14.boolean(),
|
|
8400
|
+
cookieEvents: z14.boolean(),
|
|
8401
|
+
minimalRealtime: z14.boolean()
|
|
10084
8402
|
});
|
|
10085
8403
|
var readKeys = [
|
|
10086
8404
|
"days",
|
|
@@ -10210,7 +8528,7 @@ async function runAnalyticsCommand(options) {
|
|
|
10210
8528
|
throw new Error("Use --days 1, 7 or 28.");
|
|
10211
8529
|
if (values.country && !/^(?:[A-Z]{2}|unknown)$/u.test(values.country))
|
|
10212
8530
|
throw new Error("Use an uppercase ISO country code or unknown.");
|
|
10213
|
-
if (values.campaign)
|
|
8531
|
+
if (values.campaign) z14.string().uuid().parse(values.campaign);
|
|
10214
8532
|
const setting = route === "settings set", creating = positionals[1] === "create", archive = positionals[1] === "archive";
|
|
10215
8533
|
let body;
|
|
10216
8534
|
if (setting) {
|
|
@@ -10234,10 +8552,10 @@ async function runAnalyticsCommand(options) {
|
|
|
10234
8552
|
} else if (creating) {
|
|
10235
8553
|
if (!values.file)
|
|
10236
8554
|
throw new Error("Creation requires --file with a JSON definition.");
|
|
10237
|
-
const filename =
|
|
8555
|
+
const filename = path25.resolve(options.cwd ?? process.cwd(), values.file);
|
|
10238
8556
|
if ((await stat2(filename)).size > 16384)
|
|
10239
8557
|
throw new Error("The definition must not exceed 16 KiB.");
|
|
10240
|
-
const text = await
|
|
8558
|
+
const text = await readFile16(filename, "utf8");
|
|
10241
8559
|
if (Buffer.byteLength(text) > 16384)
|
|
10242
8560
|
throw new Error("The definition must not exceed 16 KiB.");
|
|
10243
8561
|
let definition;
|
|
@@ -10246,9 +8564,9 @@ async function runAnalyticsCommand(options) {
|
|
|
10246
8564
|
} catch {
|
|
10247
8565
|
throw new Error("The definition must contain valid JSON.");
|
|
10248
8566
|
}
|
|
10249
|
-
body =
|
|
8567
|
+
body = z14.record(z14.unknown()).parse(definition);
|
|
10250
8568
|
if (action === "events") body = EventInput.parse(body);
|
|
10251
|
-
} else if (archive) body = { id:
|
|
8569
|
+
} else if (archive) body = { id: z14.string().uuid().parse(positionals[2]) };
|
|
10252
8570
|
const context = await commonServiceContext(
|
|
10253
8571
|
options,
|
|
10254
8572
|
"analytics",
|
|
@@ -10295,8 +8613,8 @@ async function runAnalyticsCommand(options) {
|
|
|
10295
8613
|
);
|
|
10296
8614
|
const value = await response.json();
|
|
10297
8615
|
if (!response.ok) {
|
|
10298
|
-
const error =
|
|
10299
|
-
error:
|
|
8616
|
+
const error = z14.object({
|
|
8617
|
+
error: z14.object({ code: z14.string(), message: z14.string().max(500) })
|
|
10300
8618
|
}).safeParse(value);
|
|
10301
8619
|
throw new SiteOSAuthApiError({
|
|
10302
8620
|
code: error.success ? error.data.error.code : "ANALYTICS_REQUEST_FAILED",
|
|
@@ -10304,9 +8622,9 @@ async function runAnalyticsCommand(options) {
|
|
|
10304
8622
|
status: response.status
|
|
10305
8623
|
});
|
|
10306
8624
|
}
|
|
10307
|
-
const record =
|
|
10308
|
-
contractVersion:
|
|
10309
|
-
resourceId:
|
|
8625
|
+
const record = z14.object({
|
|
8626
|
+
contractVersion: z14.literal(1),
|
|
8627
|
+
resourceId: z14.literal(context.resourceId)
|
|
10310
8628
|
}).passthrough().parse(value);
|
|
10311
8629
|
let output;
|
|
10312
8630
|
if (setting) {
|
|
@@ -10325,16 +8643,16 @@ async function runAnalyticsCommand(options) {
|
|
|
10325
8643
|
throw new Error("The saved event does not match this definition.");
|
|
10326
8644
|
} else
|
|
10327
8645
|
output = {
|
|
10328
|
-
id:
|
|
8646
|
+
id: z14.string().uuid().parse(record.id),
|
|
10329
8647
|
...pick(
|
|
10330
8648
|
record,
|
|
10331
8649
|
action === "campaigns" ? ["label", "source", "medium", "campaign"] : action === "goals" ? ["label", "match"] : ["label", "steps"]
|
|
10332
8650
|
)
|
|
10333
8651
|
};
|
|
10334
8652
|
} else if (archive)
|
|
10335
|
-
output = { archived:
|
|
8653
|
+
output = { archived: z14.literal(true).parse(record.archived) };
|
|
10336
8654
|
else if (route === "monitoring prepare")
|
|
10337
|
-
output = { state:
|
|
8655
|
+
output = { state: z14.literal("prepared").parse(record.state) };
|
|
10338
8656
|
else if (action === "realtime") output = pick(record, liveKeys);
|
|
10339
8657
|
else {
|
|
10340
8658
|
const resource = Resource.parse(record.resource);
|
|
@@ -10346,8 +8664,8 @@ async function runAnalyticsCommand(options) {
|
|
|
10346
8664
|
output = {
|
|
10347
8665
|
resource,
|
|
10348
8666
|
lastReceivedAt: record.lastReceivedAt,
|
|
10349
|
-
consentSource:
|
|
10350
|
-
consentSource:
|
|
8667
|
+
consentSource: z14.object({
|
|
8668
|
+
consentSource: z14.enum([
|
|
10351
8669
|
"cookie",
|
|
10352
8670
|
"external",
|
|
10353
8671
|
"waiting_for_cookie",
|
|
@@ -10359,11 +8677,11 @@ async function runAnalyticsCommand(options) {
|
|
|
10359
8677
|
else if (action === "installation")
|
|
10360
8678
|
output = {
|
|
10361
8679
|
resource,
|
|
10362
|
-
installation:
|
|
8680
|
+
installation: z14.string().parse(record.installation),
|
|
10363
8681
|
configuration: record.configuration
|
|
10364
8682
|
};
|
|
10365
8683
|
else if (action === "events") {
|
|
10366
|
-
const definitions =
|
|
8684
|
+
const definitions = z14.array(EventInput).parse(record.definitions);
|
|
10367
8685
|
if (route === "events snippet") {
|
|
10368
8686
|
const definition = definitions.find((d) => d.name === positionals[2]);
|
|
10369
8687
|
if (!definition)
|
|
@@ -10377,13 +8695,13 @@ async function runAnalyticsCommand(options) {
|
|
|
10377
8695
|
};
|
|
10378
8696
|
} else output = { definitions, eventCounts: record.eventCounts };
|
|
10379
8697
|
} else
|
|
10380
|
-
output = action === "report" ? pick(record, readKeys) : { [action]:
|
|
8698
|
+
output = action === "report" ? pick(record, readKeys) : { [action]: z14.array(z14.unknown()).parse(record[action]) };
|
|
10381
8699
|
}
|
|
10382
8700
|
return { exitCode: 0, stdout: JSON.stringify(output, null, 2) };
|
|
10383
8701
|
} catch (cause) {
|
|
10384
8702
|
const error = cause instanceof SiteOSAuthApiError ? { code: cause.code, message: cause.message } : {
|
|
10385
8703
|
code: "ANALYTICS_COMMAND_FAILED",
|
|
10386
|
-
message: cause instanceof
|
|
8704
|
+
message: cause instanceof z14.ZodError ? "The Analytics input or response does not match the supported contract." : cause instanceof Error ? cause.message : "The Analytics command failed."
|
|
10387
8705
|
};
|
|
10388
8706
|
return {
|
|
10389
8707
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
@@ -10394,20 +8712,20 @@ async function runAnalyticsCommand(options) {
|
|
|
10394
8712
|
|
|
10395
8713
|
// src/services/seo-command.ts
|
|
10396
8714
|
import { writeFile as writeFile10 } from "fs/promises";
|
|
10397
|
-
import
|
|
8715
|
+
import path28 from "path";
|
|
10398
8716
|
import { parseArgs as parseArgs8 } from "util";
|
|
10399
|
-
import { z as
|
|
8717
|
+
import { z as z19 } from "zod";
|
|
10400
8718
|
|
|
10401
8719
|
// src/services/seo-research-command.ts
|
|
10402
8720
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
10403
8721
|
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
10404
8722
|
import { isDeepStrictEqual, parseArgs as parseArgs5 } from "util";
|
|
10405
|
-
import { z as
|
|
8723
|
+
import { z as z16 } from "zod";
|
|
10406
8724
|
|
|
10407
8725
|
// src/services/seo-report-client.ts
|
|
10408
8726
|
import { open, writeFile as writeFile8 } from "fs/promises";
|
|
10409
|
-
import
|
|
10410
|
-
import { z as
|
|
8727
|
+
import path26 from "path";
|
|
8728
|
+
import { z as z15 } from "zod";
|
|
10411
8729
|
async function seoReportClient(options, environment) {
|
|
10412
8730
|
const context = await commonServiceContext(options, "seo", environment);
|
|
10413
8731
|
if (!context)
|
|
@@ -10442,8 +8760,8 @@ async function seoReportClient(options, environment) {
|
|
|
10442
8760
|
}
|
|
10443
8761
|
);
|
|
10444
8762
|
if (!response.ok) {
|
|
10445
|
-
const result =
|
|
10446
|
-
error:
|
|
8763
|
+
const result = z15.object({
|
|
8764
|
+
error: z15.object({ code: z15.string(), message: z15.string().max(500) })
|
|
10447
8765
|
}).safeParse(await response.json());
|
|
10448
8766
|
throw new SiteOSAuthApiError({
|
|
10449
8767
|
code: result.success ? result.data.error.code : "SEO_REQUEST_FAILED",
|
|
@@ -10457,9 +8775,9 @@ async function seoReportClient(options, environment) {
|
|
|
10457
8775
|
}
|
|
10458
8776
|
};
|
|
10459
8777
|
}
|
|
10460
|
-
var versionedReport =
|
|
8778
|
+
var versionedReport = z15.object({ contractVersion: z15.literal(1) }).passthrough();
|
|
10461
8779
|
async function readSeoInput(cwd, filename) {
|
|
10462
|
-
const file = await open(
|
|
8780
|
+
const file = await open(path26.resolve(cwd ?? process.cwd(), filename), "r");
|
|
10463
8781
|
try {
|
|
10464
8782
|
const stat3 = await file.stat();
|
|
10465
8783
|
if (!stat3.isFile() || stat3.size > 32e3)
|
|
@@ -10483,14 +8801,14 @@ async function readSeoInput(cwd, filename) {
|
|
|
10483
8801
|
}
|
|
10484
8802
|
}
|
|
10485
8803
|
async function writeSeoReport(options, filename, content) {
|
|
10486
|
-
const output =
|
|
8804
|
+
const output = path26.resolve(options.cwd ?? process.cwd(), filename);
|
|
10487
8805
|
await writeFile8(output, content, { flag: "wx", mode: 384 });
|
|
10488
8806
|
return output;
|
|
10489
8807
|
}
|
|
10490
8808
|
function seoReportFailure(cause, json, idempotencyKey) {
|
|
10491
8809
|
const error = {
|
|
10492
8810
|
code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
|
|
10493
|
-
message: cause instanceof
|
|
8811
|
+
message: cause instanceof z15.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The SEO command failed."
|
|
10494
8812
|
};
|
|
10495
8813
|
return {
|
|
10496
8814
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
@@ -10546,11 +8864,11 @@ var kinds = [
|
|
|
10546
8864
|
"brand",
|
|
10547
8865
|
"ai-visibility"
|
|
10548
8866
|
];
|
|
10549
|
-
var requestSchema =
|
|
10550
|
-
kind:
|
|
10551
|
-
target:
|
|
8867
|
+
var requestSchema = z16.object({
|
|
8868
|
+
kind: z16.enum(["domain", ...kinds]).transform((kind) => kind === "domain" ? "competitors" : kind),
|
|
8869
|
+
target: z16.string().min(1).max(253)
|
|
10552
8870
|
}).passthrough();
|
|
10553
|
-
var runStates =
|
|
8871
|
+
var runStates = z16.enum([
|
|
10554
8872
|
"queued",
|
|
10555
8873
|
"running",
|
|
10556
8874
|
"completed",
|
|
@@ -10647,26 +8965,26 @@ async function runSeoResearchCommand(options) {
|
|
|
10647
8965
|
);
|
|
10648
8966
|
}
|
|
10649
8967
|
const client = await seoReportClient(options, values.environment);
|
|
10650
|
-
const resourceSchema =
|
|
10651
|
-
id:
|
|
10652
|
-
organizationId:
|
|
8968
|
+
const resourceSchema = z16.object({
|
|
8969
|
+
id: z16.literal(client.resourceId),
|
|
8970
|
+
organizationId: z16.literal(client.organizationId)
|
|
10653
8971
|
}).passthrough();
|
|
10654
|
-
const runSchema =
|
|
10655
|
-
id:
|
|
10656
|
-
resourceId:
|
|
10657
|
-
organizationId:
|
|
10658
|
-
websiteUrl:
|
|
8972
|
+
const runSchema = z16.object({
|
|
8973
|
+
id: z16.string(),
|
|
8974
|
+
resourceId: z16.literal(client.resourceId),
|
|
8975
|
+
organizationId: z16.literal(client.organizationId),
|
|
8976
|
+
websiteUrl: z16.string(),
|
|
10659
8977
|
request: requestSchema,
|
|
10660
8978
|
state: runStates,
|
|
10661
|
-
createdAt:
|
|
10662
|
-
finishedAt:
|
|
10663
|
-
parts:
|
|
10664
|
-
|
|
10665
|
-
key:
|
|
10666
|
-
state:
|
|
10667
|
-
error:
|
|
10668
|
-
dataset:
|
|
10669
|
-
observedAt:
|
|
8979
|
+
createdAt: z16.string(),
|
|
8980
|
+
finishedAt: z16.string().nullable(),
|
|
8981
|
+
parts: z16.array(
|
|
8982
|
+
z16.object({
|
|
8983
|
+
key: z16.string(),
|
|
8984
|
+
state: z16.enum(["completed", "failed"]),
|
|
8985
|
+
error: z16.string().nullable(),
|
|
8986
|
+
dataset: z16.record(z16.unknown()).nullable(),
|
|
8987
|
+
observedAt: z16.string()
|
|
10670
8988
|
}).passthrough()
|
|
10671
8989
|
)
|
|
10672
8990
|
}).passthrough();
|
|
@@ -10680,36 +8998,36 @@ async function runSeoResearchCommand(options) {
|
|
|
10680
8998
|
const query = `?kind=${encodeURIComponent(values.kind ?? "rankings")}`;
|
|
10681
8999
|
let record;
|
|
10682
9000
|
if (action.startsWith("serp ")) {
|
|
10683
|
-
const snapshotSchema =
|
|
10684
|
-
id:
|
|
10685
|
-
organizationId:
|
|
10686
|
-
resourceId:
|
|
10687
|
-
sourceRunId:
|
|
9001
|
+
const snapshotSchema = z16.object({
|
|
9002
|
+
id: z16.string(),
|
|
9003
|
+
organizationId: z16.literal(client.organizationId),
|
|
9004
|
+
resourceId: z16.literal(client.resourceId),
|
|
9005
|
+
sourceRunId: z16.literal(id),
|
|
10688
9006
|
request: requestSchema,
|
|
10689
|
-
keywordKey:
|
|
9007
|
+
keywordKey: z16.literal(
|
|
10690
9008
|
values.keyword.normalize("NFKC").trim().toLowerCase().replace(/\s+/gu, " ")
|
|
10691
9009
|
),
|
|
10692
|
-
state:
|
|
9010
|
+
state: z16.enum([
|
|
10693
9011
|
"queued",
|
|
10694
9012
|
"running",
|
|
10695
9013
|
"completed",
|
|
10696
9014
|
"failed",
|
|
10697
9015
|
"cancelled"
|
|
10698
9016
|
]),
|
|
10699
|
-
dataset:
|
|
10700
|
-
type:
|
|
10701
|
-
keyword:
|
|
10702
|
-
country:
|
|
10703
|
-
language:
|
|
10704
|
-
device:
|
|
10705
|
-
observedAt:
|
|
10706
|
-
rows:
|
|
10707
|
-
|
|
10708
|
-
position:
|
|
10709
|
-
title:
|
|
10710
|
-
url:
|
|
10711
|
-
domain:
|
|
10712
|
-
description:
|
|
9017
|
+
dataset: z16.object({
|
|
9018
|
+
type: z16.literal("serp"),
|
|
9019
|
+
keyword: z16.string(),
|
|
9020
|
+
country: z16.string(),
|
|
9021
|
+
language: z16.string(),
|
|
9022
|
+
device: z16.enum(["desktop", "mobile"]),
|
|
9023
|
+
observedAt: z16.string(),
|
|
9024
|
+
rows: z16.array(
|
|
9025
|
+
z16.object({
|
|
9026
|
+
position: z16.number(),
|
|
9027
|
+
title: z16.string(),
|
|
9028
|
+
url: z16.string(),
|
|
9029
|
+
domain: z16.string(),
|
|
9030
|
+
description: z16.string()
|
|
10713
9031
|
})
|
|
10714
9032
|
)
|
|
10715
9033
|
}).nullable()
|
|
@@ -10802,9 +9120,9 @@ async function runSeoResearchCommand(options) {
|
|
|
10802
9120
|
name: values.name.trim(),
|
|
10803
9121
|
...values.id ? { id: values.id } : {}
|
|
10804
9122
|
});
|
|
10805
|
-
const saved =
|
|
10806
|
-
id:
|
|
10807
|
-
name:
|
|
9123
|
+
const saved = z16.object({
|
|
9124
|
+
id: z16.string(),
|
|
9125
|
+
name: z16.literal(values.name.trim()),
|
|
10808
9126
|
request: requestSchema
|
|
10809
9127
|
}).parse(record.saved);
|
|
10810
9128
|
if (values.id && saved.id !== values.id || !isDeepStrictEqual(saved.request, plan.request))
|
|
@@ -10818,23 +9136,23 @@ async function runSeoResearchCommand(options) {
|
|
|
10818
9136
|
action === "cancel" ? "run" : "write",
|
|
10819
9137
|
{}
|
|
10820
9138
|
);
|
|
10821
|
-
|
|
9139
|
+
z16.literal(true).parse(
|
|
10822
9140
|
record[action === "cancel" ? "cancelled" : "removed"]
|
|
10823
9141
|
);
|
|
10824
9142
|
} else if (action === "summary") {
|
|
10825
9143
|
record = await get("/summary");
|
|
10826
9144
|
resourceSchema.parse(record.resource);
|
|
10827
|
-
|
|
9145
|
+
z16.array(z16.object({ kind: z16.enum(kinds), summary: z16.unknown() })).parse(
|
|
10828
9146
|
record.checks
|
|
10829
9147
|
);
|
|
10830
9148
|
} else if (["status", "history", "saved list"].includes(action)) {
|
|
10831
9149
|
const view = await get(query);
|
|
10832
9150
|
resourceSchema.parse(view.resource);
|
|
10833
|
-
const runs =
|
|
10834
|
-
const saved =
|
|
10835
|
-
|
|
10836
|
-
id:
|
|
10837
|
-
name:
|
|
9151
|
+
const runs = z16.array(runSchema).parse(view.runs);
|
|
9152
|
+
const saved = z16.array(
|
|
9153
|
+
z16.object({
|
|
9154
|
+
id: z16.string(),
|
|
9155
|
+
name: z16.string(),
|
|
10838
9156
|
request: requestSchema
|
|
10839
9157
|
}).passthrough()
|
|
10840
9158
|
).parse(view.saved);
|
|
@@ -10951,7 +9269,7 @@ async function runSeoResearchCommand(options) {
|
|
|
10951
9269
|
|
|
10952
9270
|
// src/services/seo-gsc-command.ts
|
|
10953
9271
|
import { parseArgs as parseArgs6 } from "util";
|
|
10954
|
-
import { z as
|
|
9272
|
+
import { z as z17 } from "zod";
|
|
10955
9273
|
var GSC_HELP = `
|
|
10956
9274
|
siteos seo gsc status [--environment <slug>] [--json]
|
|
10957
9275
|
siteos seo gsc report [--dataset <pages|queries>] [--query <text>] [--filter <all|issues|declining>] [--sort <clicks|change|impressions>] [--page <number>] [--url <page-url>] [--environment <slug>] [--json]
|
|
@@ -11051,13 +9369,13 @@ async function runSeoGscCommand(options) {
|
|
|
11051
9369
|
`seo:search:${action === "sync" ? "sync" : writing ? "write" : "read"}`,
|
|
11052
9370
|
body
|
|
11053
9371
|
);
|
|
11054
|
-
const runSchema =
|
|
11055
|
-
id:
|
|
11056
|
-
resourceId:
|
|
11057
|
-
organizationId:
|
|
11058
|
-
websiteUrl:
|
|
11059
|
-
siteUrl:
|
|
11060
|
-
state:
|
|
9372
|
+
const runSchema = z17.object({
|
|
9373
|
+
id: z17.string(),
|
|
9374
|
+
resourceId: z17.literal(client.resourceId),
|
|
9375
|
+
organizationId: z17.literal(client.organizationId),
|
|
9376
|
+
websiteUrl: z17.string(),
|
|
9377
|
+
siteUrl: z17.string(),
|
|
9378
|
+
state: z17.enum([
|
|
11061
9379
|
"queued",
|
|
11062
9380
|
"running",
|
|
11063
9381
|
"completed",
|
|
@@ -11065,32 +9383,32 @@ async function runSeoGscCommand(options) {
|
|
|
11065
9383
|
"failed",
|
|
11066
9384
|
"cancelled"
|
|
11067
9385
|
]),
|
|
11068
|
-
dates:
|
|
9386
|
+
dates: z17.unknown()
|
|
11069
9387
|
}).passthrough();
|
|
11070
|
-
const bindingSchema =
|
|
11071
|
-
resourceId:
|
|
11072
|
-
organizationId:
|
|
11073
|
-
websiteUrl:
|
|
11074
|
-
siteUrl:
|
|
11075
|
-
revision:
|
|
9388
|
+
const bindingSchema = z17.object({
|
|
9389
|
+
resourceId: z17.literal(client.resourceId),
|
|
9390
|
+
organizationId: z17.literal(client.organizationId),
|
|
9391
|
+
websiteUrl: z17.string(),
|
|
9392
|
+
siteUrl: z17.string(),
|
|
9393
|
+
revision: z17.number().int().positive()
|
|
11076
9394
|
}).passthrough();
|
|
11077
|
-
const metrics =
|
|
11078
|
-
clicks:
|
|
11079
|
-
impressions:
|
|
11080
|
-
ctr:
|
|
11081
|
-
position:
|
|
9395
|
+
const metrics = z17.object({
|
|
9396
|
+
clicks: z17.number(),
|
|
9397
|
+
impressions: z17.number(),
|
|
9398
|
+
ctr: z17.number(),
|
|
9399
|
+
position: z17.number()
|
|
11082
9400
|
}).passthrough().nullable();
|
|
11083
9401
|
const validateView = (data) => {
|
|
11084
9402
|
const record2 = versionedReport.parse(data);
|
|
11085
|
-
|
|
9403
|
+
z17.literal(client.resourceId).parse(record2.resourceId);
|
|
11086
9404
|
bindingSchema.nullable().parse(record2.binding);
|
|
11087
9405
|
runSchema.nullable().parse(record2.latest);
|
|
11088
9406
|
runSchema.nullable().parse(record2.report);
|
|
11089
|
-
|
|
11090
|
-
|
|
9407
|
+
z17.array(
|
|
9408
|
+
z17.object({ key: z17.string(), current: metrics, previous: metrics }).passthrough()
|
|
11091
9409
|
).parse(record2.rows);
|
|
11092
|
-
|
|
11093
|
-
|
|
9410
|
+
z17.number().int().nonnegative().parse(record2.total);
|
|
9411
|
+
z17.literal(values.dataset ?? "pages").parse(record2.dataset);
|
|
11094
9412
|
return record2;
|
|
11095
9413
|
};
|
|
11096
9414
|
if (action === "export") {
|
|
@@ -11106,9 +9424,9 @@ async function runSeoGscCommand(options) {
|
|
|
11106
9424
|
const text = await response.text();
|
|
11107
9425
|
if (values.format === "json") {
|
|
11108
9426
|
const report = validateView(JSON.parse(text));
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
|
|
9427
|
+
z17.literal(reportId).parse(runSchema.parse(report.report).id);
|
|
9428
|
+
z17.array(z17.unknown()).length(rows).parse(report.rows);
|
|
9429
|
+
z17.literal(truncated === "true").parse(report.truncated);
|
|
11112
9430
|
}
|
|
11113
9431
|
const output = await writeSeoReport(options, values.output, text);
|
|
11114
9432
|
return {
|
|
@@ -11129,7 +9447,7 @@ async function runSeoGscCommand(options) {
|
|
|
11129
9447
|
};
|
|
11130
9448
|
}
|
|
11131
9449
|
const record = versionedReport.parse(await response.json());
|
|
11132
|
-
if (action === "disconnect")
|
|
9450
|
+
if (action === "disconnect") z17.literal(true).parse(record.unbound);
|
|
11133
9451
|
else if (writing) {
|
|
11134
9452
|
runSchema.parse(record.run);
|
|
11135
9453
|
if (action === "bind") {
|
|
@@ -11149,10 +9467,10 @@ async function runSeoGscCommand(options) {
|
|
|
11149
9467
|
// src/services/seo-performance-command.ts
|
|
11150
9468
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
11151
9469
|
import { writeFile as writeFile9 } from "fs/promises";
|
|
11152
|
-
import
|
|
9470
|
+
import path27 from "path";
|
|
11153
9471
|
import { setTimeout as setTimeout3 } from "timers/promises";
|
|
11154
9472
|
import { parseArgs as parseArgs7 } from "util";
|
|
11155
|
-
import { z as
|
|
9473
|
+
import { z as z18 } from "zod";
|
|
11156
9474
|
var PERFORMANCE_HELP = `
|
|
11157
9475
|
siteos seo performance run --audit <id> --url <url> [--url <url>...] [--device <mobile|desktop>] [--idempotency-key <key>] [--environment <slug>] [--json]
|
|
11158
9476
|
siteos seo performance list [--device <mobile|desktop>] [--environment <slug>] [--json]
|
|
@@ -11240,12 +9558,12 @@ async function runSeoPerformanceCommand(options) {
|
|
|
11240
9558
|
const runtime = commonProjectRuntime(options);
|
|
11241
9559
|
const writing = ["run", "cancel"].includes(action);
|
|
11242
9560
|
const scope = writing ? "seo:audits:write" : "seo:workspace:read";
|
|
11243
|
-
const batchSchema =
|
|
11244
|
-
id:
|
|
11245
|
-
resourceId:
|
|
11246
|
-
organizationId:
|
|
11247
|
-
sourceAuditId:
|
|
11248
|
-
state:
|
|
9561
|
+
const batchSchema = z18.object({
|
|
9562
|
+
id: z18.string(),
|
|
9563
|
+
resourceId: z18.literal(context.resourceId),
|
|
9564
|
+
organizationId: z18.literal(context.overview.project.organizationId),
|
|
9565
|
+
sourceAuditId: z18.string(),
|
|
9566
|
+
state: z18.enum([
|
|
11249
9567
|
"queued",
|
|
11250
9568
|
"running",
|
|
11251
9569
|
"completed",
|
|
@@ -11253,8 +9571,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
11253
9571
|
"failed",
|
|
11254
9572
|
"cancelled"
|
|
11255
9573
|
]),
|
|
11256
|
-
device:
|
|
11257
|
-
urls:
|
|
9574
|
+
device: z18.enum(["mobile", "desktop"]),
|
|
9575
|
+
urls: z18.array(z18.string()).min(1).max(10)
|
|
11258
9576
|
}).passthrough();
|
|
11259
9577
|
const query = new URLSearchParams();
|
|
11260
9578
|
if (values.device) query.set("device", values.device);
|
|
@@ -11302,17 +9620,17 @@ async function runSeoPerformanceCommand(options) {
|
|
|
11302
9620
|
);
|
|
11303
9621
|
const text = await response.text();
|
|
11304
9622
|
if (values.format === "json") {
|
|
11305
|
-
const parsed =
|
|
11306
|
-
contractVersion:
|
|
9623
|
+
const parsed = z18.object({
|
|
9624
|
+
contractVersion: z18.literal(1),
|
|
11307
9625
|
batch: batchSchema,
|
|
11308
|
-
pages:
|
|
9626
|
+
pages: z18.array(z18.unknown())
|
|
11309
9627
|
}).parse(JSON.parse(text));
|
|
11310
9628
|
if (parsed.batch.id !== id)
|
|
11311
9629
|
throw new Error(
|
|
11312
9630
|
"The export response does not match the selected check."
|
|
11313
9631
|
);
|
|
11314
9632
|
}
|
|
11315
|
-
const output =
|
|
9633
|
+
const output = path27.resolve(
|
|
11316
9634
|
options.cwd ?? process.cwd(),
|
|
11317
9635
|
values.output
|
|
11318
9636
|
);
|
|
@@ -11328,8 +9646,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
11328
9646
|
}
|
|
11329
9647
|
const data = await response.json();
|
|
11330
9648
|
if (!response.ok) {
|
|
11331
|
-
const error =
|
|
11332
|
-
error:
|
|
9649
|
+
const error = z18.object({
|
|
9650
|
+
error: z18.object({ code: z18.string(), message: z18.string().max(500) })
|
|
11333
9651
|
}).safeParse(data);
|
|
11334
9652
|
throw new SiteOSAuthApiError({
|
|
11335
9653
|
code: error.success ? error.data.error.code : "SEO_REQUEST_FAILED",
|
|
@@ -11337,8 +9655,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
11337
9655
|
status: response.status
|
|
11338
9656
|
});
|
|
11339
9657
|
}
|
|
11340
|
-
const record =
|
|
11341
|
-
if (action === "cancel")
|
|
9658
|
+
const record = z18.object({ contractVersion: z18.literal(1) }).passthrough().parse(data);
|
|
9659
|
+
if (action === "cancel") z18.literal(true).parse(record.cancelled);
|
|
11342
9660
|
else if (action === "run") {
|
|
11343
9661
|
const accepted = batchSchema.parse(record.batch);
|
|
11344
9662
|
const normalize = (url) => {
|
|
@@ -11351,8 +9669,8 @@ async function runSeoPerformanceCommand(options) {
|
|
|
11351
9669
|
"The queued check does not match the requested source, device and URLs."
|
|
11352
9670
|
);
|
|
11353
9671
|
} else {
|
|
11354
|
-
|
|
11355
|
-
|
|
9672
|
+
z18.literal(context.resourceId).parse(record.resourceId);
|
|
9673
|
+
z18.array(batchSchema).parse(record.batches);
|
|
11356
9674
|
const selected = batchSchema.nullable().parse(record.batch);
|
|
11357
9675
|
if (id && selected?.id !== id)
|
|
11358
9676
|
throw new Error(
|
|
@@ -11379,7 +9697,7 @@ async function runSeoPerformanceCommand(options) {
|
|
|
11379
9697
|
} catch (cause) {
|
|
11380
9698
|
const error = {
|
|
11381
9699
|
code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
|
|
11382
|
-
message: cause instanceof
|
|
9700
|
+
message: cause instanceof z18.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The performance command failed."
|
|
11383
9701
|
};
|
|
11384
9702
|
return {
|
|
11385
9703
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
@@ -11659,17 +9977,17 @@ async function runSeoCommand(options) {
|
|
|
11659
9977
|
);
|
|
11660
9978
|
const text = await response.text();
|
|
11661
9979
|
if (values.format === "json")
|
|
11662
|
-
|
|
11663
|
-
contractVersion:
|
|
11664
|
-
audit:
|
|
11665
|
-
id:
|
|
11666
|
-
resourceId:
|
|
9980
|
+
z19.object({
|
|
9981
|
+
contractVersion: z19.literal(1),
|
|
9982
|
+
audit: z19.object({
|
|
9983
|
+
id: z19.literal(values.audit),
|
|
9984
|
+
resourceId: z19.literal(context.resourceId)
|
|
11667
9985
|
}),
|
|
11668
|
-
kind:
|
|
11669
|
-
totalRows:
|
|
11670
|
-
rows:
|
|
9986
|
+
kind: z19.literal(values.kind),
|
|
9987
|
+
totalRows: z19.literal(rows),
|
|
9988
|
+
rows: z19.array(z19.unknown()).length(rows)
|
|
11671
9989
|
}).parse(JSON.parse(text));
|
|
11672
|
-
const output =
|
|
9990
|
+
const output = path28.resolve(options.cwd ?? process.cwd(), values.output);
|
|
11673
9991
|
await writeFile10(output, text, { flag: "wx", mode: 384 });
|
|
11674
9992
|
return {
|
|
11675
9993
|
exitCode: 0,
|
|
@@ -11688,8 +10006,8 @@ async function runSeoCommand(options) {
|
|
|
11688
10006
|
}
|
|
11689
10007
|
const data = await response.json();
|
|
11690
10008
|
if (!response.ok) {
|
|
11691
|
-
const result =
|
|
11692
|
-
error:
|
|
10009
|
+
const result = z19.object({
|
|
10010
|
+
error: z19.object({ code: z19.string(), message: z19.string().max(500) })
|
|
11693
10011
|
}).safeParse(data);
|
|
11694
10012
|
throw new SiteOSAuthApiError({
|
|
11695
10013
|
code: result.success ? result.data.error.code : "SEO_REQUEST_FAILED",
|
|
@@ -11697,34 +10015,34 @@ async function runSeoCommand(options) {
|
|
|
11697
10015
|
status: response.status
|
|
11698
10016
|
});
|
|
11699
10017
|
}
|
|
11700
|
-
const record =
|
|
10018
|
+
const record = z19.object({ contractVersion: z19.literal(1) }).passthrough().parse(data);
|
|
11701
10019
|
if (automation) {
|
|
11702
|
-
|
|
11703
|
-
const schedule =
|
|
11704
|
-
enabled:
|
|
11705
|
-
weekday:
|
|
11706
|
-
time:
|
|
11707
|
-
timeZone:
|
|
11708
|
-
revision:
|
|
11709
|
-
nextRunAt:
|
|
10020
|
+
z19.literal(context.resourceId).parse(record.resourceId);
|
|
10021
|
+
const schedule = z19.object({
|
|
10022
|
+
enabled: z19.boolean(),
|
|
10023
|
+
weekday: z19.number().int().min(1).max(7),
|
|
10024
|
+
time: z19.string(),
|
|
10025
|
+
timeZone: z19.string(),
|
|
10026
|
+
revision: z19.number().int().min(0),
|
|
10027
|
+
nextRunAt: z19.string().nullable()
|
|
11710
10028
|
});
|
|
11711
|
-
const notificationRoute =
|
|
11712
|
-
enabled:
|
|
11713
|
-
minimumSeverity:
|
|
11714
|
-
includeFailures:
|
|
11715
|
-
revision:
|
|
11716
|
-
destinationId:
|
|
10029
|
+
const notificationRoute = z19.object({
|
|
10030
|
+
enabled: z19.boolean(),
|
|
10031
|
+
minimumSeverity: z19.enum(["error", "warning"]),
|
|
10032
|
+
includeFailures: z19.boolean(),
|
|
10033
|
+
revision: z19.number().int().min(0),
|
|
10034
|
+
destinationId: z19.string().nullable()
|
|
11717
10035
|
});
|
|
11718
10036
|
if (retryNotification) {
|
|
11719
|
-
|
|
11720
|
-
|
|
10037
|
+
z19.literal(true).parse(record.retryQueued);
|
|
10038
|
+
z19.literal(positionals[2]).parse(record.notificationId);
|
|
11721
10039
|
} else if (route === "notifications destinations")
|
|
11722
|
-
|
|
11723
|
-
candidates:
|
|
11724
|
-
|
|
11725
|
-
candidateId:
|
|
11726
|
-
label:
|
|
11727
|
-
availability:
|
|
10040
|
+
z19.object({
|
|
10041
|
+
candidates: z19.array(
|
|
10042
|
+
z19.object({
|
|
10043
|
+
candidateId: z19.string(),
|
|
10044
|
+
label: z19.string(),
|
|
10045
|
+
availability: z19.literal("available")
|
|
11728
10046
|
})
|
|
11729
10047
|
)
|
|
11730
10048
|
}).parse(record);
|
|
@@ -11737,46 +10055,46 @@ async function runSeoCommand(options) {
|
|
|
11737
10055
|
notificationRoute.parse(record.route);
|
|
11738
10056
|
}
|
|
11739
10057
|
} else if (!writing) {
|
|
11740
|
-
const validated =
|
|
11741
|
-
resource:
|
|
11742
|
-
id:
|
|
11743
|
-
organizationId:
|
|
10058
|
+
const validated = z19.object({
|
|
10059
|
+
resource: z19.object({
|
|
10060
|
+
id: z19.literal(context.resourceId),
|
|
10061
|
+
organizationId: z19.literal(context.overview.project.organizationId)
|
|
11744
10062
|
}),
|
|
11745
|
-
audits:
|
|
11746
|
-
audit:
|
|
11747
|
-
id:
|
|
11748
|
-
resourceId:
|
|
10063
|
+
audits: z19.array(z19.object({ id: z19.string() }).passthrough()),
|
|
10064
|
+
audit: z19.object({
|
|
10065
|
+
id: z19.string(),
|
|
10066
|
+
resourceId: z19.literal(context.resourceId)
|
|
11749
10067
|
}).passthrough().nullable(),
|
|
11750
|
-
pages:
|
|
11751
|
-
issues:
|
|
11752
|
-
changes:
|
|
11753
|
-
totalChanges:
|
|
11754
|
-
dispositions:
|
|
10068
|
+
pages: z19.array(z19.unknown()),
|
|
10069
|
+
issues: z19.array(z19.unknown()),
|
|
10070
|
+
changes: z19.array(z19.unknown()),
|
|
10071
|
+
totalChanges: z19.number(),
|
|
10072
|
+
dispositions: z19.array(z19.unknown())
|
|
11755
10073
|
}).passthrough().parse(record);
|
|
11756
10074
|
const selected = query.get("audit");
|
|
11757
10075
|
if (selected && validated.audit?.id !== selected)
|
|
11758
10076
|
throw new Error("The SEO response does not match the requested audit.");
|
|
11759
10077
|
} else if (record.audit)
|
|
11760
|
-
|
|
11761
|
-
id:
|
|
11762
|
-
resourceId:
|
|
11763
|
-
organizationId:
|
|
11764
|
-
state:
|
|
10078
|
+
z19.object({
|
|
10079
|
+
id: z19.string(),
|
|
10080
|
+
resourceId: z19.literal(context.resourceId),
|
|
10081
|
+
organizationId: z19.literal(context.overview.project.organizationId),
|
|
10082
|
+
state: z19.literal("queued")
|
|
11765
10083
|
}).parse(record.audit);
|
|
11766
|
-
else if (route === "audit cancel")
|
|
10084
|
+
else if (route === "audit cancel") z19.literal(true).parse(record.cancelled);
|
|
11767
10085
|
else if (action === "issue")
|
|
11768
|
-
|
|
11769
|
-
url:
|
|
11770
|
-
ruleId:
|
|
11771
|
-
ignored:
|
|
11772
|
-
revision:
|
|
10086
|
+
z19.object({
|
|
10087
|
+
url: z19.literal(values.url),
|
|
10088
|
+
ruleId: z19.literal(values.rule),
|
|
10089
|
+
ignored: z19.literal(positionals[1] === "ignore"),
|
|
10090
|
+
revision: z19.literal(Number(values.revision) + 1)
|
|
11773
10091
|
}).parse(record.disposition);
|
|
11774
10092
|
else throw new Error("The SEO service returned an invalid response.");
|
|
11775
10093
|
return { exitCode: 0, stdout: JSON.stringify(record, null, 2) };
|
|
11776
10094
|
} catch (cause) {
|
|
11777
10095
|
const error = {
|
|
11778
10096
|
code: cause instanceof SiteOSAuthApiError ? cause.code : "SEO_COMMAND_FAILED",
|
|
11779
|
-
message: cause instanceof
|
|
10097
|
+
message: cause instanceof z19.ZodError ? "The SEO service returned an invalid response." : cause instanceof Error ? cause.message : "The SEO command failed."
|
|
11780
10098
|
};
|
|
11781
10099
|
return {
|
|
11782
10100
|
exitCode: cause instanceof SiteOSAuthApiError ? 1 : 2,
|
|
@@ -11831,7 +10149,7 @@ function rootCommandRegistry() {
|
|
|
11831
10149
|
fetchImpl: globalThis.fetch
|
|
11832
10150
|
}),
|
|
11833
10151
|
"health-check": runHealthCheck,
|
|
11834
|
-
project: (args2) =>
|
|
10152
|
+
project: (args2) => runProjectCommand({
|
|
11835
10153
|
args: args2,
|
|
11836
10154
|
cwd: process.cwd(),
|
|
11837
10155
|
env: process.env,
|