@privos_ai/app-server 0.8.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -1
- package/dist/cli/commands/lint.d.ts +8 -0
- package/dist/cli/commands/lint.d.ts.map +1 -0
- package/dist/cli/commands/lint.js +24 -0
- package/dist/cli/commands/lint.js.map +1 -0
- package/dist/cli/commands/publish.d.ts +20 -0
- package/dist/cli/commands/publish.d.ts.map +1 -0
- package/dist/cli/commands/publish.js +365 -0
- package/dist/cli/commands/publish.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +36 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/lib/authorize.d.ts +80 -0
- package/dist/cli/lib/authorize.d.ts.map +1 -0
- package/dist/cli/lib/authorize.js +86 -0
- package/dist/cli/lib/authorize.js.map +1 -0
- package/dist/cli/lib/manifest.d.ts +30 -0
- package/dist/cli/lib/manifest.d.ts.map +1 -0
- package/dist/cli/lib/manifest.js +61 -0
- package/dist/cli/lib/manifest.js.map +1 -0
- package/dist/cli/lib/output.d.ts +66 -0
- package/dist/cli/lib/output.d.ts.map +1 -0
- package/dist/cli/lib/output.js +61 -0
- package/dist/cli/lib/output.js.map +1 -0
- package/dist/cli/lib/package-source.d.ts +63 -0
- package/dist/cli/lib/package-source.d.ts.map +1 -0
- package/dist/cli/lib/package-source.js +219 -0
- package/dist/cli/lib/package-source.js.map +1 -0
- package/dist/cli/lib/portal-client.d.ts +38 -0
- package/dist/cli/lib/portal-client.d.ts.map +1 -0
- package/dist/cli/lib/portal-client.js +87 -0
- package/dist/cli/lib/portal-client.js.map +1 -0
- package/dist/cli/lib/upload.d.ts +54 -0
- package/dist/cli/lib/upload.d.ts.map +1 -0
- package/dist/cli/lib/upload.js +75 -0
- package/dist/cli/lib/upload.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/manifest-lint-cli.js +5 -16
- package/dist/manifest-lint-cli.js.map +1 -1
- package/dist/relay/relay-client.d.ts.map +1 -1
- package/dist/relay/relay-client.js +25 -5
- package/dist/relay/relay-client.js.map +1 -1
- package/dist/runtime.d.ts +38 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +92 -5
- package/dist/runtime.js.map +1 -1
- package/dist/ui/asset-filename-rule.d.ts +18 -0
- package/dist/ui/asset-filename-rule.d.ts.map +1 -0
- package/dist/ui/asset-filename-rule.js +39 -0
- package/dist/ui/asset-filename-rule.js.map +1 -0
- package/dist/ui/assets-manifest.d.ts +19 -0
- package/dist/ui/assets-manifest.d.ts.map +1 -0
- package/dist/ui/assets-manifest.js +128 -0
- package/dist/ui/assets-manifest.js.map +1 -0
- package/dist/ui/serve-built-ui.d.ts +28 -0
- package/dist/ui/serve-built-ui.d.ts.map +1 -0
- package/dist/ui/serve-built-ui.js +131 -0
- package/dist/ui/serve-built-ui.js.map +1 -0
- package/dist/ui/shell-watchdog.d.ts +12 -0
- package/dist/ui/shell-watchdog.d.ts.map +1 -0
- package/dist/ui/shell-watchdog.js +25 -0
- package/dist/ui/shell-watchdog.js.map +1 -0
- package/package.json +3 -1
- package/skill/README.md +14 -0
- package/skill/SKILL.md +124 -0
- package/skill/references/errors.md +68 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { PortalClient } from './portal-client.js';
|
|
2
|
+
/**
|
|
3
|
+
* A publish grant as returned by the Portal — `pvg_<authorizationId>.<mac>`,
|
|
4
|
+
* used verbatim as `Authorization: Bearer <value>`. Never composed
|
|
5
|
+
* client-side; the CLI only ever forwards the Portal's own string.
|
|
6
|
+
*/
|
|
7
|
+
export type PublishGrant = Readonly<{
|
|
8
|
+
value: string;
|
|
9
|
+
expiresAt: string;
|
|
10
|
+
listingId: string;
|
|
11
|
+
listingSlug: string;
|
|
12
|
+
}>;
|
|
13
|
+
export type AuthorizationRequest = Readonly<{
|
|
14
|
+
manifestName: string;
|
|
15
|
+
semver: string;
|
|
16
|
+
archiveSha256: string;
|
|
17
|
+
archiveBytes: number;
|
|
18
|
+
cliVersion: string;
|
|
19
|
+
listingSlug?: string;
|
|
20
|
+
machineLabel?: string;
|
|
21
|
+
}>;
|
|
22
|
+
export type AuthorizationOutcome = Readonly<{
|
|
23
|
+
kind: 'grant';
|
|
24
|
+
grant: PublishGrant;
|
|
25
|
+
listing: {
|
|
26
|
+
id: string;
|
|
27
|
+
slug: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
};
|
|
30
|
+
}> | Readonly<{
|
|
31
|
+
kind: 'device';
|
|
32
|
+
deviceCode: string;
|
|
33
|
+
userCode: string;
|
|
34
|
+
verificationUrl: string;
|
|
35
|
+
expiresIn: number;
|
|
36
|
+
interval: number;
|
|
37
|
+
}>;
|
|
38
|
+
export type PollOutcome = Readonly<{
|
|
39
|
+
state: 'PENDING';
|
|
40
|
+
}> | Readonly<{
|
|
41
|
+
state: 'APPROVED';
|
|
42
|
+
grant: PublishGrant;
|
|
43
|
+
}> | Readonly<{
|
|
44
|
+
state: 'DENIED';
|
|
45
|
+
}> | Readonly<{
|
|
46
|
+
state: 'EXPIRED';
|
|
47
|
+
}> | Readonly<{
|
|
48
|
+
state: 'CONSUMED';
|
|
49
|
+
}>;
|
|
50
|
+
/** The states {@link waitForApproval} can resolve to — `PENDING` is a polling-loop-internal state only. */
|
|
51
|
+
export type TerminalPollOutcome = Exclude<PollOutcome, Readonly<{
|
|
52
|
+
state: 'PENDING';
|
|
53
|
+
}>>;
|
|
54
|
+
/**
|
|
55
|
+
* `POST /publish-authorizations` — anonymous (interactive/device flow) or
|
|
56
|
+
* bearer `pvp_…` (publisher token, CI). A token whose scope covers the
|
|
57
|
+
* resolved listing and whose `manifestName` is already bound returns
|
|
58
|
+
* `{ grant, listing }` inline (`kind: 'grant'`); otherwise the Portal issues
|
|
59
|
+
* a device code (`kind: 'device'`). `409 LISTING_NOT_BOUND` / `409
|
|
60
|
+
* LISTING_UNRESOLVED` surface as {@link PortalError} for the caller to map
|
|
61
|
+
* to the documented exit codes and remediation text.
|
|
62
|
+
*/
|
|
63
|
+
export declare function createAuthorization(client: PortalClient, request: AuthorizationRequest, token?: string): Promise<AuthorizationOutcome>;
|
|
64
|
+
/** `POST /publish-authorizations/token` — RFC 8628 polling; a `slow_down` error surfaces as a `PortalError` with that code. */
|
|
65
|
+
export declare function pollAuthorization(client: PortalClient, deviceCode: string): Promise<PollOutcome>;
|
|
66
|
+
export type WaitForApprovalOptions = Readonly<{
|
|
67
|
+
intervalMs: number;
|
|
68
|
+
expiresInMs: number;
|
|
69
|
+
onPending?: (elapsedMs: number) => void;
|
|
70
|
+
sleepImpl?: (ms: number) => Promise<void>;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Polls until a terminal state, honoring `slow_down` by backing off (RFC
|
|
74
|
+
* 8628 §3.5) and stopping once the authorization's own `expiresIn` window
|
|
75
|
+
* elapses. While `APPROVED`, the Portal returns the same grant on every
|
|
76
|
+
* poll, so a lost response mid-poll is recoverable by design — this loop
|
|
77
|
+
* simply returns on the first non-`PENDING` state it observes.
|
|
78
|
+
*/
|
|
79
|
+
export declare function waitForApproval(client: PortalClient, deviceCode: string, options: WaitForApprovalOptions): Promise<TerminalPollOutcome>;
|
|
80
|
+
//# sourceMappingURL=authorize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/authorize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,oBAAoB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAC7B,QAAQ,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC,GACtG,QAAQ,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEpI,MAAM,MAAM,WAAW,GACpB,QAAQ,CAAC;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC,GAC9B,QAAQ,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC,GACpD,QAAQ,CAAC;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC,GAC7B,QAAQ,CAAC;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC,GAC9B,QAAQ,CAAC;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC;AAEnC,2GAA2G;AAC3G,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC,CAAC;AAWvF;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,oBAAoB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA0B5I;AAED,+HAA+H;AAC/H,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAOtG;AAED,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqB7I"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { PortalError } from './portal-client.js';
|
|
2
|
+
function normalizeGrant(raw) {
|
|
3
|
+
return {
|
|
4
|
+
value: String(raw.token),
|
|
5
|
+
expiresAt: String(raw.expiresAt),
|
|
6
|
+
listingId: String(raw.listingId),
|
|
7
|
+
listingSlug: String(raw.listingSlug),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `POST /publish-authorizations` — anonymous (interactive/device flow) or
|
|
12
|
+
* bearer `pvp_…` (publisher token, CI). A token whose scope covers the
|
|
13
|
+
* resolved listing and whose `manifestName` is already bound returns
|
|
14
|
+
* `{ grant, listing }` inline (`kind: 'grant'`); otherwise the Portal issues
|
|
15
|
+
* a device code (`kind: 'device'`). `409 LISTING_NOT_BOUND` / `409
|
|
16
|
+
* LISTING_UNRESOLVED` surface as {@link PortalError} for the caller to map
|
|
17
|
+
* to the documented exit codes and remediation text.
|
|
18
|
+
*/
|
|
19
|
+
export async function createAuthorization(client, request, token) {
|
|
20
|
+
const body = {
|
|
21
|
+
manifestName: request.manifestName,
|
|
22
|
+
semver: request.semver,
|
|
23
|
+
archiveSha256: request.archiveSha256,
|
|
24
|
+
archiveBytes: request.archiveBytes,
|
|
25
|
+
cliVersion: request.cliVersion,
|
|
26
|
+
...(request.listingSlug ? { listingSlug: request.listingSlug } : {}),
|
|
27
|
+
...(request.machineLabel ? { machineLabel: request.machineLabel } : {}),
|
|
28
|
+
};
|
|
29
|
+
const response = await client.request('/publish-authorizations', { method: 'POST', token, body });
|
|
30
|
+
if (response.grant) {
|
|
31
|
+
return {
|
|
32
|
+
kind: 'grant',
|
|
33
|
+
grant: normalizeGrant(response.grant),
|
|
34
|
+
listing: response.listing,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
kind: 'device',
|
|
39
|
+
deviceCode: String(response.deviceCode),
|
|
40
|
+
userCode: String(response.userCode),
|
|
41
|
+
verificationUrl: String(response.verificationUrl),
|
|
42
|
+
expiresIn: Number(response.expiresIn),
|
|
43
|
+
interval: Number(response.interval),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** `POST /publish-authorizations/token` — RFC 8628 polling; a `slow_down` error surfaces as a `PortalError` with that code. */
|
|
47
|
+
export async function pollAuthorization(client, deviceCode) {
|
|
48
|
+
const response = await client.request('/publish-authorizations/token', { method: 'POST', body: { deviceCode } });
|
|
49
|
+
const state = String(response.state);
|
|
50
|
+
if (state === 'APPROVED') {
|
|
51
|
+
return { state: 'APPROVED', grant: normalizeGrant(response.grant) };
|
|
52
|
+
}
|
|
53
|
+
return { state: state };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Polls until a terminal state, honoring `slow_down` by backing off (RFC
|
|
57
|
+
* 8628 §3.5) and stopping once the authorization's own `expiresIn` window
|
|
58
|
+
* elapses. While `APPROVED`, the Portal returns the same grant on every
|
|
59
|
+
* poll, so a lost response mid-poll is recoverable by design — this loop
|
|
60
|
+
* simply returns on the first non-`PENDING` state it observes.
|
|
61
|
+
*/
|
|
62
|
+
export async function waitForApproval(client, deviceCode, options) {
|
|
63
|
+
const sleepImpl = options.sleepImpl ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
64
|
+
let intervalMs = options.intervalMs;
|
|
65
|
+
const start = Date.now();
|
|
66
|
+
const deadline = start + options.expiresInMs;
|
|
67
|
+
for (;;) {
|
|
68
|
+
if (Date.now() >= deadline)
|
|
69
|
+
return { state: 'EXPIRED' };
|
|
70
|
+
await sleepImpl(intervalMs);
|
|
71
|
+
try {
|
|
72
|
+
const outcome = await pollAuthorization(client, deviceCode);
|
|
73
|
+
if (outcome.state !== 'PENDING')
|
|
74
|
+
return outcome;
|
|
75
|
+
options.onPending?.(Date.now() - start);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (error instanceof PortalError && error.code?.toLowerCase() === 'slow_down') {
|
|
79
|
+
intervalMs += 5_000;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=authorize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../../src/cli/lib/authorize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ManifestLintResult } from '../../manifest-tools.js';
|
|
2
|
+
/** Raised when `privos-app.json` or `package.json` cannot be located or parsed. */
|
|
3
|
+
export declare class ManifestLoadError extends Error {
|
|
4
|
+
}
|
|
5
|
+
export type LoadedManifest = Readonly<{
|
|
6
|
+
manifestPath: string;
|
|
7
|
+
manifest: Record<string, unknown>;
|
|
8
|
+
}>;
|
|
9
|
+
export type LoadedPackageJson = Readonly<{
|
|
10
|
+
packagePath: string;
|
|
11
|
+
pkg: Record<string, unknown>;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function loadManifest(cwd: string, manifestFile?: string): LoadedManifest;
|
|
14
|
+
export declare function loadPackageJson(cwd: string): LoadedPackageJson;
|
|
15
|
+
/**
|
|
16
|
+
* `privos-app.json` and `package.json` must agree on the identity fields the
|
|
17
|
+
* Portal binds a publish grant to (`name`, `version`). This is a CLI-side
|
|
18
|
+
* fast-fail check; the Portal independently verifies `manifest.name` /
|
|
19
|
+
* `manifest.version` on `complete` (`409 PUBLISH_GRANT_MISMATCH`).
|
|
20
|
+
*/
|
|
21
|
+
export declare function assertIdentityAgreement(manifest: Record<string, unknown>, pkg: Record<string, unknown>): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Structure-only lint. `result.canonicalManifestHash` is the SDK's structural
|
|
24
|
+
* digest (key-sorted JSON, `localeCompare`) and is NOT the Portal's canonical
|
|
25
|
+
* digest (which may differ in comparator and Zod-applied defaults). It must
|
|
26
|
+
* never be sent to the Portal; the Portal computes and returns the
|
|
27
|
+
* authoritative `manifestDigest` on upload `complete`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function structuralLint(manifest: unknown): ManifestLintResult;
|
|
30
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/manifest.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEhF,mFAAmF;AACnF,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7B,CAAC,CAAC;AAqBH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,SAAoB,GAAG,cAAc,CAG1F;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAG9D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CASjH;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,kBAAkB,CAEpE"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { lintManifest } from '../../manifest-tools.js';
|
|
4
|
+
/** Raised when `privos-app.json` or `package.json` cannot be located or parsed. */
|
|
5
|
+
export class ManifestLoadError extends Error {
|
|
6
|
+
}
|
|
7
|
+
function readJsonObject(filePath) {
|
|
8
|
+
let raw;
|
|
9
|
+
try {
|
|
10
|
+
raw = fs.readFileSync(filePath, 'utf8');
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new ManifestLoadError(`Unable to read ${filePath}`);
|
|
14
|
+
}
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = JSON.parse(raw);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
throw new ManifestLoadError(`Unable to read valid JSON from ${filePath}`);
|
|
21
|
+
}
|
|
22
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
23
|
+
throw new ManifestLoadError(`${filePath} must contain a JSON object`);
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
export function loadManifest(cwd, manifestFile = 'privos-app.json') {
|
|
28
|
+
const manifestPath = path.resolve(cwd, manifestFile);
|
|
29
|
+
return { manifestPath, manifest: readJsonObject(manifestPath) };
|
|
30
|
+
}
|
|
31
|
+
export function loadPackageJson(cwd) {
|
|
32
|
+
const packagePath = path.resolve(cwd, 'package.json');
|
|
33
|
+
return { packagePath, pkg: readJsonObject(packagePath) };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* `privos-app.json` and `package.json` must agree on the identity fields the
|
|
37
|
+
* Portal binds a publish grant to (`name`, `version`). This is a CLI-side
|
|
38
|
+
* fast-fail check; the Portal independently verifies `manifest.name` /
|
|
39
|
+
* `manifest.version` on `complete` (`409 PUBLISH_GRANT_MISMATCH`).
|
|
40
|
+
*/
|
|
41
|
+
export function assertIdentityAgreement(manifest, pkg) {
|
|
42
|
+
const errors = [];
|
|
43
|
+
if (manifest.name !== pkg.name) {
|
|
44
|
+
errors.push(`privos-app.json "name" (${JSON.stringify(manifest.name)}) does not match package.json "name" (${JSON.stringify(pkg.name)})`);
|
|
45
|
+
}
|
|
46
|
+
if (manifest.version !== pkg.version) {
|
|
47
|
+
errors.push(`privos-app.json "version" (${JSON.stringify(manifest.version)}) does not match package.json "version" (${JSON.stringify(pkg.version)})`);
|
|
48
|
+
}
|
|
49
|
+
return errors;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Structure-only lint. `result.canonicalManifestHash` is the SDK's structural
|
|
53
|
+
* digest (key-sorted JSON, `localeCompare`) and is NOT the Portal's canonical
|
|
54
|
+
* digest (which may differ in comparator and Zod-applied defaults). It must
|
|
55
|
+
* never be sent to the Portal; the Portal computes and returns the
|
|
56
|
+
* authoritative `manifestDigest` on upload `complete`.
|
|
57
|
+
*/
|
|
58
|
+
export function structuralLint(manifest) {
|
|
59
|
+
return lintManifest(manifest);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/cli/lib/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,YAAY,EAA2B,MAAM,yBAAyB,CAAC;AAEhF,mFAAmF;AACnF,MAAM,OAAO,iBAAkB,SAAQ,KAAK;CAAG;AAY/C,SAAS,cAAc,CAAC,QAAgB;IACvC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACJ,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,iBAAiB,CAAC,kBAAkB,QAAQ,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,iBAAiB,CAAC,kCAAkC,QAAQ,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,iBAAiB,CAAC,GAAG,QAAQ,6BAA6B,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,MAAiC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,YAAY,GAAG,iBAAiB;IACzE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACrD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,CAAC,YAAY,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IACtD,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAiC,EAAE,GAA4B;IACtG,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,QAAQ,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,yCAAyC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3I,CAAC;IACD,IAAI,QAAQ,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,8BAA8B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,4CAA4C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACvJ,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,QAAiB;IAC/C,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human vs `--json` (NDJSON) rendering for `privos-app publish`, plus secret
|
|
3
|
+
* masking. Grants are never rendered by any event — callers must not pass a
|
|
4
|
+
* grant value into a {@link PublishEvent}. Tokens are only ever shown masked.
|
|
5
|
+
*/
|
|
6
|
+
export type PublishEvent = Readonly<{
|
|
7
|
+
event: 'lint';
|
|
8
|
+
ok: boolean;
|
|
9
|
+
manifestPath: string;
|
|
10
|
+
}> | Readonly<{
|
|
11
|
+
event: 'package';
|
|
12
|
+
archivePath: string;
|
|
13
|
+
bytes: number;
|
|
14
|
+
sha256: string;
|
|
15
|
+
entryCount: number;
|
|
16
|
+
}> | Readonly<{
|
|
17
|
+
event: 'authorization_token';
|
|
18
|
+
maskedToken: string;
|
|
19
|
+
}> | Readonly<{
|
|
20
|
+
event: 'authorization_device';
|
|
21
|
+
verificationUrl: string;
|
|
22
|
+
userCode: string;
|
|
23
|
+
expiresIn: number;
|
|
24
|
+
}> | Readonly<{
|
|
25
|
+
event: 'authorization_waiting';
|
|
26
|
+
elapsedMs: number;
|
|
27
|
+
}> | Readonly<{
|
|
28
|
+
event: 'authorization_approved';
|
|
29
|
+
listingId: string;
|
|
30
|
+
listingSlug: string;
|
|
31
|
+
}> | Readonly<{
|
|
32
|
+
event: 'authorization_denied';
|
|
33
|
+
}> | Readonly<{
|
|
34
|
+
event: 'authorization_expired';
|
|
35
|
+
}> | Readonly<{
|
|
36
|
+
event: 'upload_progress';
|
|
37
|
+
part: number;
|
|
38
|
+
totalParts: number;
|
|
39
|
+
}> | Readonly<{
|
|
40
|
+
event: 'upload_complete';
|
|
41
|
+
sha256: string;
|
|
42
|
+
manifestDigest: string;
|
|
43
|
+
}> | Readonly<{
|
|
44
|
+
event: 'version_created';
|
|
45
|
+
versionId: string;
|
|
46
|
+
semver: string;
|
|
47
|
+
}> | Readonly<{
|
|
48
|
+
event: 'submitted';
|
|
49
|
+
versionId: string;
|
|
50
|
+
}> | Readonly<{
|
|
51
|
+
event: 'status';
|
|
52
|
+
state: string;
|
|
53
|
+
message?: string;
|
|
54
|
+
}> | Readonly<{
|
|
55
|
+
event: 'error';
|
|
56
|
+
code?: string;
|
|
57
|
+
message: string;
|
|
58
|
+
}>;
|
|
59
|
+
export declare class Reporter {
|
|
60
|
+
private readonly jsonMode;
|
|
61
|
+
constructor(jsonMode: boolean);
|
|
62
|
+
emit(event: PublishEvent): void;
|
|
63
|
+
}
|
|
64
|
+
/** Shows only enough of a secret to identify it in logs; never the full value. */
|
|
65
|
+
export declare function maskSecret(value: string): string;
|
|
66
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,YAAY,GACrB,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9D,QAAQ,CAAC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GACtG,QAAQ,CAAC;IAAE,KAAK,EAAE,qBAAqB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,GAC/D,QAAQ,CAAC;IAAE,KAAK,EAAE,sBAAsB,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,GACzG,QAAQ,CAAC;IAAE,KAAK,EAAE,uBAAuB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,GAC/D,QAAQ,CAAC;IAAE,KAAK,EAAE,wBAAwB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,GACrF,QAAQ,CAAC;IAAE,KAAK,EAAE,sBAAsB,CAAA;CAAE,CAAC,GAC3C,QAAQ,CAAC;IAAE,KAAK,EAAE,uBAAuB,CAAA;CAAE,CAAC,GAC5C,QAAQ,CAAC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,GACxE,QAAQ,CAAC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9E,QAAQ,CAAC;IAAE,KAAK,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GACzE,QAAQ,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,GACnD,QAAQ,CAAC;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9D,QAAQ,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhE,qBAAa,QAAQ;IACR,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,OAAO;IAE9C,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;CAO/B;AA4CD,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGhD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export class Reporter {
|
|
2
|
+
jsonMode;
|
|
3
|
+
constructor(jsonMode) {
|
|
4
|
+
this.jsonMode = jsonMode;
|
|
5
|
+
}
|
|
6
|
+
emit(event) {
|
|
7
|
+
if (this.jsonMode) {
|
|
8
|
+
process.stdout.write(`${JSON.stringify(event)}\n`);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
process.stdout.write(`${formatHumanLine(event)}\n`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function formatHumanLine(event) {
|
|
15
|
+
switch (event.event) {
|
|
16
|
+
case 'lint':
|
|
17
|
+
return event.ok ? `✔ manifest ${event.manifestPath} valid` : `✖ manifest ${event.manifestPath} invalid`;
|
|
18
|
+
case 'package':
|
|
19
|
+
return `✔ archive ${event.archivePath} (${event.bytes} bytes, ${event.entryCount} entries, sha256:${event.sha256})`;
|
|
20
|
+
case 'authorization_token':
|
|
21
|
+
return `→ authorizing with publisher token ${event.maskedToken}`;
|
|
22
|
+
case 'authorization_device':
|
|
23
|
+
return [
|
|
24
|
+
'→ Approve this publish in your browser:',
|
|
25
|
+
` ${event.verificationUrl}`,
|
|
26
|
+
` user code: ${event.userCode}`,
|
|
27
|
+
` (waiting… expires in ${Math.round(event.expiresIn / 60)} min)`,
|
|
28
|
+
].join('\n');
|
|
29
|
+
case 'authorization_waiting':
|
|
30
|
+
return ' (waiting for approval…)';
|
|
31
|
+
case 'authorization_approved':
|
|
32
|
+
return `✔ approved → listing ${event.listingSlug}`;
|
|
33
|
+
case 'authorization_denied':
|
|
34
|
+
return '✖ publish authorization was denied';
|
|
35
|
+
case 'authorization_expired':
|
|
36
|
+
return '✖ publish authorization expired';
|
|
37
|
+
case 'upload_progress':
|
|
38
|
+
return ` uploaded ${event.part}/${event.totalParts} parts`;
|
|
39
|
+
case 'upload_complete':
|
|
40
|
+
return `✔ uploaded · manifest digest ${event.manifestDigest}`;
|
|
41
|
+
case 'version_created':
|
|
42
|
+
return `✔ version ${event.semver} created`;
|
|
43
|
+
case 'submitted':
|
|
44
|
+
return '✔ submitted';
|
|
45
|
+
case 'status':
|
|
46
|
+
return event.message ? `→ status: ${event.state} (${event.message})` : `→ status: ${event.state}`;
|
|
47
|
+
case 'error':
|
|
48
|
+
return `✖ ${event.message}`;
|
|
49
|
+
default: {
|
|
50
|
+
const exhaustive = event;
|
|
51
|
+
return JSON.stringify(exhaustive);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Shows only enough of a secret to identify it in logs; never the full value. */
|
|
56
|
+
export function maskSecret(value) {
|
|
57
|
+
if (value.length <= 8)
|
|
58
|
+
return '***';
|
|
59
|
+
return `${value.slice(0, 8)}…(${value.length} chars)`;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/cli/lib/output.ts"],"names":[],"mappings":"AAqBA,MAAM,OAAO,QAAQ;IACS;IAA7B,YAA6B,QAAiB;QAAjB,aAAQ,GAAR,QAAQ,CAAS;IAAG,CAAC;IAElD,IAAI,CAAC,KAAmB;QACvB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACnD,OAAO;QACR,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;CACD;AAED,SAAS,eAAe,CAAC,KAAmB;IAC3C,QAAQ,KAAK,CAAC,KAAK,EAAE,CAAC;QACrB,KAAK,MAAM;YACV,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,KAAK,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,cAAc,KAAK,CAAC,YAAY,UAAU,CAAC;QACzG,KAAK,SAAS;YACb,OAAO,aAAa,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,KAAK,WAAW,KAAK,CAAC,UAAU,oBAAoB,KAAK,CAAC,MAAM,GAAG,CAAC;QACrH,KAAK,qBAAqB;YACzB,OAAO,sCAAsC,KAAK,CAAC,WAAW,EAAE,CAAC;QAClE,KAAK,sBAAsB;YAC1B,OAAO;gBACN,yCAAyC;gBACzC,OAAO,KAAK,CAAC,eAAe,EAAE;gBAC9B,kBAAkB,KAAK,CAAC,QAAQ,EAAE;gBAClC,0BAA0B,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,OAAO;aACjE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,uBAAuB;YAC3B,OAAO,2BAA2B,CAAC;QACpC,KAAK,wBAAwB;YAC5B,OAAO,wBAAwB,KAAK,CAAC,WAAW,EAAE,CAAC;QACpD,KAAK,sBAAsB;YAC1B,OAAO,oCAAoC,CAAC;QAC7C,KAAK,uBAAuB;YAC3B,OAAO,iCAAiC,CAAC;QAC1C,KAAK,iBAAiB;YACrB,OAAO,cAAc,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,UAAU,QAAQ,CAAC;QAC7D,KAAK,iBAAiB;YACrB,OAAO,gCAAgC,KAAK,CAAC,cAAc,EAAE,CAAC;QAC/D,KAAK,iBAAiB;YACrB,OAAO,aAAa,KAAK,CAAC,MAAM,UAAU,CAAC;QAC5C,KAAK,WAAW;YACf,OAAO,aAAa,CAAC;QACtB,KAAK,QAAQ;YACZ,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,KAAK,CAAC,KAAK,MAAM,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,aAAa,KAAK,CAAC,KAAK,EAAE,CAAC;QACpG,KAAK,OAAO;YACX,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QAC7B,OAAO,CAAC,CAAC,CAAC;YACT,MAAM,UAAU,GAAU,KAAK,CAAC;YAChC,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;IACF,CAAC;AACF,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,KAAa;IACvC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,MAAM,SAAS,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy-violation codes surfaced by {@link packageSource}. Every code maps to
|
|
3
|
+
* CLI exit code 2 ("blocked by policy") except `NOT_GIT_REPOSITORY` and
|
|
4
|
+
* `GIT_ARCHIVE_FAILED`, which the caller treats as environment/usage problems.
|
|
5
|
+
*/
|
|
6
|
+
export type PackagePolicyCode = 'NOT_GIT_REPOSITORY' | 'DIRTY_TREE' | 'CREDENTIAL_FILE_FOUND' | 'GIT_ARCHIVE_FAILED' | 'INVALID_ZIP' | 'MISSING_REQUIRED_ENTRY' | 'DENIED_PATH_IN_ARCHIVE' | 'ENTRY_LIMIT_EXCEEDED' | 'FILE_SIZE_EXCEEDED' | 'TOTAL_SIZE_EXCEEDED';
|
|
7
|
+
export declare class PackagePolicyError extends Error {
|
|
8
|
+
readonly code: PackagePolicyCode;
|
|
9
|
+
readonly details: readonly string[];
|
|
10
|
+
constructor(message: string, code: PackagePolicyCode, details?: readonly string[]);
|
|
11
|
+
}
|
|
12
|
+
export type PackageSourceOptions = Readonly<{
|
|
13
|
+
/** Directory the CLI was invoked from; resolved up to the git worktree root. */
|
|
14
|
+
cwd: string;
|
|
15
|
+
/** Package identity used to name the archive: `<outputDir>/<safeName>-<version>.zip`. */
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
/** Refuse a dirty tree unless true (mirrors `scripts/package-source.sh`). */
|
|
19
|
+
allowDirty: boolean;
|
|
20
|
+
/** Relative to the git worktree root. Defaults to `dist-source`. */
|
|
21
|
+
outputDir?: string;
|
|
22
|
+
}>;
|
|
23
|
+
export type ZipEntry = Readonly<{
|
|
24
|
+
name: string;
|
|
25
|
+
uncompressedSize: number;
|
|
26
|
+
isDirectory: boolean;
|
|
27
|
+
}>;
|
|
28
|
+
export type PackageSourceResult = Readonly<{
|
|
29
|
+
archivePath: string;
|
|
30
|
+
sha256: string;
|
|
31
|
+
bytes: number;
|
|
32
|
+
/** All central-directory entries, including directory entries (`unzip -Z1` parity). */
|
|
33
|
+
entries: readonly string[];
|
|
34
|
+
/** File entries only (directories filtered out) — the `paths` sent to the Portal upload session. */
|
|
35
|
+
filePaths: readonly string[];
|
|
36
|
+
/** `git rev-parse HEAD` of the worktree the archive was produced from. */
|
|
37
|
+
gitRevision: string;
|
|
38
|
+
repoRoot: string;
|
|
39
|
+
}>;
|
|
40
|
+
export declare const ENTRY_LIMIT = 20000;
|
|
41
|
+
export declare const MAX_FILE_BYTES: number;
|
|
42
|
+
export declare const MAX_TOTAL_BYTES: number;
|
|
43
|
+
export declare function isDeniedArchiveEntry(entryName: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Reads entry names + uncompressed sizes from a ZIP's central directory —
|
|
46
|
+
* the same source `unzip -Z1` reads from, never from `git ls-tree` (a git
|
|
47
|
+
* tree cannot reflect `.gitattributes export-ignore` or `--allow-dirty`
|
|
48
|
+
* untracked additions the way the produced archive does).
|
|
49
|
+
*/
|
|
50
|
+
export declare function readZipCentralDirectoryEntries(buffer: Buffer): ZipEntry[];
|
|
51
|
+
/** Pure policy evaluation over an already-read entry list — kept separate from I/O for fast unit tests. */
|
|
52
|
+
export declare function evaluateArchiveEntries(entries: readonly ZipEntry[]): void;
|
|
53
|
+
/** Recursively scans the worktree for credential-like files, mirroring the `find` guard in `scripts/package-source.sh`. */
|
|
54
|
+
export declare function findCredentialLikeFiles(root: string): string[];
|
|
55
|
+
/**
|
|
56
|
+
* Packages the git worktree at `options.cwd` into a zip archive, applying the
|
|
57
|
+
* same safety policy as `scripts/package-source.sh` (dirty-tree refusal,
|
|
58
|
+
* credential-file scan, denied-path/entry-count/size limits, required root
|
|
59
|
+
* entries), and reads the produced archive's entries from its ZIP central
|
|
60
|
+
* directory. Throws {@link PackagePolicyError} on any violation.
|
|
61
|
+
*/
|
|
62
|
+
export declare function packageSource(options: PackageSourceOptions): PackageSourceResult;
|
|
63
|
+
//# sourceMappingURL=package-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-source.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/package-source.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAC1B,oBAAoB,GACpB,YAAY,GACZ,uBAAuB,GACvB,oBAAoB,GACpB,aAAa,GACb,wBAAwB,GACxB,wBAAwB,GACxB,sBAAsB,GACtB,oBAAoB,GACpB,qBAAqB,CAAC;AAEzB,qBAAa,kBAAmB,SAAQ,KAAK;aACC,IAAI,EAAE,iBAAiB;aAAkB,OAAO,EAAE,SAAS,MAAM,EAAE;gBAApG,OAAO,EAAE,MAAM,EAAkB,IAAI,EAAE,iBAAiB,EAAkB,OAAO,GAAE,SAAS,MAAM,EAAO;CAIrH;AAED,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC3C,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,UAAU,EAAE,OAAO,CAAC;IACpB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAElG,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,oGAAoG;IACpG,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAEH,eAAO,MAAM,WAAW,QAAS,CAAC;AAClC,eAAO,MAAM,cAAc,QAAmB,CAAC;AAC/C,eAAO,MAAM,eAAe,QAAoB,CAAC;AASjD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAQ/D;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAmCzE;AAED,2GAA2G;AAC3G,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,GAAG,IAAI,CAkBzE;AAED,2HAA2H;AAC3H,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmC9D;AAOD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CAqFhF"}
|