@guanjinke/artifact-client 1.5.1 → 1.6.1

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.
Files changed (99) hide show
  1. package/README.md +32 -3
  2. package/dist/cli/setup.d.ts.map +1 -1
  3. package/dist/cli/setup.js +6 -5
  4. package/dist/cli/setup.js.map +1 -1
  5. package/dist/cli/stored-client.d.ts +24 -0
  6. package/dist/cli/stored-client.d.ts.map +1 -0
  7. package/dist/cli/stored-client.js +59 -0
  8. package/dist/cli/stored-client.js.map +1 -0
  9. package/dist/cli/web.d.ts +23 -0
  10. package/dist/cli/web.d.ts.map +1 -0
  11. package/dist/cli/web.js +99 -0
  12. package/dist/cli/web.js.map +1 -0
  13. package/dist/environment/builder.d.ts.map +1 -1
  14. package/dist/environment/builder.js +26 -13
  15. package/dist/environment/builder.js.map +1 -1
  16. package/dist/environment/catalog.d.ts.map +1 -1
  17. package/dist/environment/catalog.js +18 -0
  18. package/dist/environment/catalog.js.map +1 -1
  19. package/dist/environment/config.d.ts +1 -1
  20. package/dist/environment/config.d.ts.map +1 -1
  21. package/dist/environment/config.js +7 -5
  22. package/dist/environment/config.js.map +1 -1
  23. package/dist/environment/manager.d.ts +9 -0
  24. package/dist/environment/manager.d.ts.map +1 -1
  25. package/dist/environment/manager.js +34 -6
  26. package/dist/environment/manager.js.map +1 -1
  27. package/dist/environment/plan.d.ts +37 -1
  28. package/dist/environment/plan.d.ts.map +1 -1
  29. package/dist/environment/plan.js +71 -16
  30. package/dist/environment/plan.js.map +1 -1
  31. package/dist/environment/posix-process.d.ts +71 -0
  32. package/dist/environment/posix-process.d.ts.map +1 -0
  33. package/dist/environment/posix-process.js +393 -0
  34. package/dist/environment/posix-process.js.map +1 -0
  35. package/dist/environment/process.d.ts +3 -1
  36. package/dist/environment/process.d.ts.map +1 -1
  37. package/dist/environment/process.js +5 -2
  38. package/dist/environment/process.js.map +1 -1
  39. package/dist/environment/registry.d.ts.map +1 -1
  40. package/dist/environment/registry.js +2 -1
  41. package/dist/environment/registry.js.map +1 -1
  42. package/dist/environment/root.d.ts +24 -6
  43. package/dist/environment/root.d.ts.map +1 -1
  44. package/dist/environment/root.js +78 -24
  45. package/dist/environment/root.js.map +1 -1
  46. package/dist/environment/types.d.ts +7 -2
  47. package/dist/environment/types.d.ts.map +1 -1
  48. package/dist/environment/update.d.ts +3 -1
  49. package/dist/environment/update.d.ts.map +1 -1
  50. package/dist/environment/update.js +48 -36
  51. package/dist/environment/update.js.map +1 -1
  52. package/dist/environment/validate.d.ts.map +1 -1
  53. package/dist/environment/validate.js +5 -1
  54. package/dist/environment/validate.js.map +1 -1
  55. package/dist/index.d.ts +9 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +18 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/utils/atomic.d.ts +10 -0
  60. package/dist/utils/atomic.d.ts.map +1 -0
  61. package/dist/utils/atomic.js +65 -0
  62. package/dist/utils/atomic.js.map +1 -0
  63. package/dist/utils/local-path.d.ts +14 -0
  64. package/dist/utils/local-path.d.ts.map +1 -1
  65. package/dist/utils/local-path.js +25 -0
  66. package/dist/utils/local-path.js.map +1 -1
  67. package/dist/web/api.d.ts +28 -0
  68. package/dist/web/api.d.ts.map +1 -0
  69. package/dist/web/api.js +336 -0
  70. package/dist/web/api.js.map +1 -0
  71. package/dist/web/assets.d.ts +26 -0
  72. package/dist/web/assets.d.ts.map +1 -0
  73. package/dist/web/assets.js +87 -0
  74. package/dist/web/assets.js.map +1 -0
  75. package/dist/web/http.d.ts +41 -0
  76. package/dist/web/http.d.ts.map +1 -0
  77. package/dist/web/http.js +167 -0
  78. package/dist/web/http.js.map +1 -0
  79. package/dist/web/jobs.d.ts +69 -0
  80. package/dist/web/jobs.d.ts.map +1 -0
  81. package/dist/web/jobs.js +110 -0
  82. package/dist/web/jobs.js.map +1 -0
  83. package/dist/web/providers.d.ts +12 -0
  84. package/dist/web/providers.d.ts.map +1 -0
  85. package/dist/web/providers.js +108 -0
  86. package/dist/web/providers.js.map +1 -0
  87. package/dist/web/server.d.ts +43 -0
  88. package/dist/web/server.d.ts.map +1 -0
  89. package/dist/web/server.js +148 -0
  90. package/dist/web/server.js.map +1 -0
  91. package/dist/web/static/app.js +59 -0
  92. package/dist/web/static/favicon.svg +12 -0
  93. package/dist/web/static/index.html +15 -0
  94. package/dist/web/static/styles.css +1333 -0
  95. package/dist/web/types.d.ts +82 -0
  96. package/dist/web/types.d.ts.map +1 -0
  97. package/dist/web/types.js +3 -0
  98. package/dist/web/types.js.map +1 -0
  99. package/package.json +9 -2
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpError = void 0;
4
+ exports.applySecurityHeaders = applySecurityHeaders;
5
+ exports.sendJson = sendJson;
6
+ exports.sendText = sendText;
7
+ exports.header = header;
8
+ exports.readJson = readJson;
9
+ exports.requireString = requireString;
10
+ exports.optionalString = optionalString;
11
+ exports.requireEnum = requireEnum;
12
+ exports.optionalEnum = optionalEnum;
13
+ exports.requireOptionalInteger = requireOptionalInteger;
14
+ exports.optionalBoolean = optionalBoolean;
15
+ exports.requireStringList = requireStringList;
16
+ exports.requireRawStringList = requireRawStringList;
17
+ exports.splitList = splitList;
18
+ /** A failure that should reach the caller as an HTTP status rather than a 500. */
19
+ class HttpError extends Error {
20
+ status;
21
+ allow;
22
+ constructor(status, message, allow) {
23
+ super(message);
24
+ this.status = status;
25
+ this.allow = allow;
26
+ }
27
+ }
28
+ exports.HttpError = HttpError;
29
+ /** Response headers shared by every reply; no CORS header is ever sent. */
30
+ function applySecurityHeaders(response) {
31
+ response.setHeader('X-Content-Type-Options', 'nosniff');
32
+ response.setHeader('Referrer-Policy', 'no-referrer');
33
+ response.setHeader('Cache-Control', 'no-store');
34
+ }
35
+ function sendJson(response, status, payload, allow) {
36
+ const body = Buffer.from(JSON.stringify(payload, null, 2) + '\n', 'utf8');
37
+ applySecurityHeaders(response);
38
+ response.writeHead(status, {
39
+ 'Content-Type': 'application/json; charset=utf-8',
40
+ 'Content-Length': body.length,
41
+ ...(allow ? { Allow: allow } : {}),
42
+ });
43
+ response.end(body);
44
+ }
45
+ function sendText(response, status, text, contentType, extra) {
46
+ const body = Buffer.from(text, 'utf8');
47
+ applySecurityHeaders(response);
48
+ response.writeHead(status, { 'Content-Type': contentType, 'Content-Length': body.length, ...extra });
49
+ response.end(body);
50
+ }
51
+ /** First value of a possibly repeated header, or undefined. */
52
+ function header(request, name) {
53
+ const value = request.headers[name];
54
+ return Array.isArray(value) ? value[0] : value;
55
+ }
56
+ /**
57
+ * Read a JSON object body.
58
+ *
59
+ * Only `application/json` is accepted, so a browser form (which can be posted
60
+ * cross-origin without a preflight) can never reach a state-changing handler.
61
+ * An oversized body is drained rather than aborted, so the caller still
62
+ * receives the 413 instead of a reset connection.
63
+ */
64
+ async function readJson(request, limit) {
65
+ const contentType = header(request, 'content-type') ?? '';
66
+ if (!contentType.toLowerCase().startsWith('application/json'))
67
+ throw new HttpError(415, 'Expected Content-Type: application/json.');
68
+ const chunks = [];
69
+ let size = 0;
70
+ let oversized = false;
71
+ for await (const chunk of request) {
72
+ const buffer = chunk;
73
+ size += buffer.length;
74
+ if (size > limit) {
75
+ oversized = true;
76
+ continue;
77
+ }
78
+ chunks.push(buffer);
79
+ }
80
+ if (oversized)
81
+ throw new HttpError(413, `Request body exceeds ${limit} bytes.`);
82
+ if (!size)
83
+ throw new HttpError(400, 'Expected a JSON object body.');
84
+ let parsed;
85
+ try {
86
+ parsed = JSON.parse(Buffer.concat(chunks).toString('utf8'));
87
+ }
88
+ catch {
89
+ throw new HttpError(400, 'Request body is not valid JSON.');
90
+ }
91
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
92
+ throw new HttpError(400, 'Expected a JSON object body.');
93
+ return parsed;
94
+ }
95
+ function requireString(body, field) {
96
+ const value = body[field];
97
+ if (typeof value !== 'string' || value.trim() === '')
98
+ throw new HttpError(400, `"${field}" is required and must be a non-empty string.`);
99
+ return value.trim();
100
+ }
101
+ function optionalString(body, field) {
102
+ const value = body[field];
103
+ if (value === undefined || value === null)
104
+ return undefined;
105
+ if (typeof value !== 'string')
106
+ throw new HttpError(400, `"${field}" must be a string.`);
107
+ return value;
108
+ }
109
+ function requireEnum(body, field, allowed) {
110
+ const value = body[field];
111
+ if (typeof value !== 'string' || !allowed.includes(value))
112
+ throw new HttpError(400, `"${field}" must be one of: ${allowed.join(', ')}.`);
113
+ return value;
114
+ }
115
+ function optionalEnum(body, field, allowed) {
116
+ if (body[field] === undefined || body[field] === null)
117
+ return undefined;
118
+ return requireEnum(body, field, allowed);
119
+ }
120
+ function requireOptionalInteger(body, field, min, max) {
121
+ const value = body[field];
122
+ if (value === undefined || value === null)
123
+ return undefined;
124
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < min || value > max)
125
+ throw new HttpError(400, `"${field}" must be an integer between ${min} and ${max}.`);
126
+ return value;
127
+ }
128
+ function optionalBoolean(body, field) {
129
+ const value = body[field];
130
+ if (value === undefined || value === null)
131
+ return undefined;
132
+ if (typeof value !== 'boolean')
133
+ throw new HttpError(400, `"${field}" must be a boolean.`);
134
+ return value;
135
+ }
136
+ /** A `string[]` field that also accepts a single whitespace/comma separated string. */
137
+ function requireStringList(body, field) {
138
+ const value = body[field];
139
+ if (typeof value === 'string')
140
+ return splitList(value);
141
+ if (Array.isArray(value)) {
142
+ if (!value.every(entry => typeof entry === 'string'))
143
+ throw new HttpError(400, `"${field}" must contain strings only.`);
144
+ return value.flatMap(entry => splitList(entry));
145
+ }
146
+ throw new HttpError(400, `"${field}" is required and must be a string or an array of strings.`);
147
+ }
148
+ /**
149
+ * A `string[]` field that is passed through unsplit.
150
+ *
151
+ * Module *specs* must reach `parseModuleSpecs` verbatim: a spec carrying a local
152
+ * source (`dashboard=D:\my build\out.dll`) is split on commas only there, so a
153
+ * Windows path may contain spaces.
154
+ */
155
+ function requireRawStringList(body, field) {
156
+ const value = body[field];
157
+ if (typeof value === 'string')
158
+ return [value];
159
+ if (Array.isArray(value) && value.every(entry => typeof entry === 'string'))
160
+ return value;
161
+ throw new HttpError(400, `"${field}" is required and must be a string or an array of strings.`);
162
+ }
163
+ /** Same separator handling as the CLI's `--modules` values for plain module names. */
164
+ function splitList(value) {
165
+ return value.split(/[\s,]+/).map(entry => entry.trim()).filter(Boolean);
166
+ }
167
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/web/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { Provider } from './types';
2
+ export type JobKind = 'create' | 'delete' | 'update' | 'lifecycle';
3
+ export type JobStatus = 'queued' | 'running' | 'succeeded' | 'failed';
4
+ export interface ProgressLine {
5
+ at: string;
6
+ message: string;
7
+ }
8
+ /** A job as returned by the HTTP API: never the live object, always a copy. */
9
+ export interface JobSnapshot {
10
+ id: string;
11
+ kind: JobKind;
12
+ /** The environment name the job acts on (the new name for `create`). */
13
+ target: string;
14
+ provider?: Provider;
15
+ dryRun?: boolean;
16
+ status: JobStatus;
17
+ createdAt: string;
18
+ startedAt?: string;
19
+ finishedAt?: string;
20
+ progress: ProgressLine[];
21
+ /** True when old progress lines were dropped to bound memory. */
22
+ progressTruncated?: boolean;
23
+ result?: unknown;
24
+ error?: string;
25
+ }
26
+ export interface JobInput {
27
+ kind: JobKind;
28
+ target: string;
29
+ provider?: Provider;
30
+ dryRun?: boolean;
31
+ }
32
+ /**
33
+ * In-memory registry of long-running operations.
34
+ *
35
+ * Creating an environment downloads and assembles artifacts for minutes, so the
36
+ * HTTP API answers with a job id and the page polls it. Jobs are deliberately
37
+ * not persisted: they describe the work of this server process only, while the
38
+ * durable result (the environment registry and `<root>/environment.lock.json`)
39
+ * is written by the environment manager itself.
40
+ *
41
+ * Mutating jobs for the same environment are serialized here. `update-env`
42
+ * documents that it does not take the per-environment lifecycle lock, so a web
43
+ * update must never race a web start/stop/restart for the same environment.
44
+ */
45
+ export declare class JobStore {
46
+ private readonly limit;
47
+ private readonly progressLimit;
48
+ private readonly jobs;
49
+ private readonly tails;
50
+ constructor(limit?: number, progressLimit?: number);
51
+ /**
52
+ * Queue `action` and return its snapshot immediately.
53
+ *
54
+ * The action receives a progress sink; its rejection is recorded on the job
55
+ * instead of propagating, because there is no request left to fail.
56
+ */
57
+ run<T>(input: JobInput, action: (progress: (line: string) => void) => Promise<T>): JobSnapshot;
58
+ get(id: string): JobSnapshot | undefined;
59
+ /** Newest first. */
60
+ list(): JobSnapshot[];
61
+ /** Resolves once no job is queued or running; used for a graceful shutdown. */
62
+ whenIdle(): Promise<void>;
63
+ busy(): boolean;
64
+ private append;
65
+ private snapshot;
66
+ /** Drop the oldest finished jobs first; a running job is never discarded. */
67
+ private prune;
68
+ }
69
+ //# sourceMappingURL=jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../../src/web/jobs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AACnE,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEtE,MAAM,WAAW,YAAY;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAE7D,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,iEAAiE;IACjE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IAAG,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE;AAMlG;;;;;;;;;;;;GAYG;AACH,qBAAa,QAAQ;IAGP,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAO,OAAO,CAAC,QAAQ,CAAC,aAAa;IAFvE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;gBAC7B,KAAK,SAAK,EAAmB,aAAa,SAAM;IAE7E;;;;;OAKG;IACH,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW;IAoC9F,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAKxC,oBAAoB;IACpB,IAAI,IAAI,WAAW,EAAE;IAIrB,+EAA+E;IACzE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,IAAI,IAAI,OAAO;IAIf,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,QAAQ;IAIhB,6EAA6E;IAC7E,OAAO,CAAC,KAAK;CAOd"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JobStore = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const message = (error) => (error instanceof Error ? error.message : String(error));
6
+ /**
7
+ * In-memory registry of long-running operations.
8
+ *
9
+ * Creating an environment downloads and assembles artifacts for minutes, so the
10
+ * HTTP API answers with a job id and the page polls it. Jobs are deliberately
11
+ * not persisted: they describe the work of this server process only, while the
12
+ * durable result (the environment registry and `<root>/environment.lock.json`)
13
+ * is written by the environment manager itself.
14
+ *
15
+ * Mutating jobs for the same environment are serialized here. `update-env`
16
+ * documents that it does not take the per-environment lifecycle lock, so a web
17
+ * update must never race a web start/stop/restart for the same environment.
18
+ */
19
+ class JobStore {
20
+ limit;
21
+ progressLimit;
22
+ jobs = new Map();
23
+ tails = new Map();
24
+ constructor(limit = 50, progressLimit = 400) {
25
+ this.limit = limit;
26
+ this.progressLimit = progressLimit;
27
+ }
28
+ /**
29
+ * Queue `action` and return its snapshot immediately.
30
+ *
31
+ * The action receives a progress sink; its rejection is recorded on the job
32
+ * instead of propagating, because there is no request left to fail.
33
+ */
34
+ run(input, action) {
35
+ const key = input.target.toLowerCase();
36
+ const job = {
37
+ id: (0, crypto_1.randomUUID)(),
38
+ kind: input.kind,
39
+ target: input.target,
40
+ ...(input.provider !== undefined ? { provider: input.provider } : {}),
41
+ ...(input.dryRun !== undefined ? { dryRun: input.dryRun } : {}),
42
+ status: 'queued',
43
+ createdAt: new Date().toISOString(),
44
+ progress: [],
45
+ progressTruncated: false,
46
+ };
47
+ this.jobs.set(job.id, job);
48
+ const previous = this.tails.get(key);
49
+ if (previous)
50
+ this.append(job, `Queued behind another operation on ${input.target}; mutations of one environment are serialized.`);
51
+ const started = (previous ?? Promise.resolve()).then(async () => {
52
+ job.status = 'running';
53
+ job.startedAt = new Date().toISOString();
54
+ try {
55
+ job.result = await action(line => this.append(job, line));
56
+ job.status = 'succeeded';
57
+ }
58
+ catch (error) {
59
+ job.error = message(error);
60
+ job.status = 'failed';
61
+ }
62
+ finally {
63
+ job.finishedAt = new Date().toISOString();
64
+ this.prune();
65
+ }
66
+ });
67
+ this.tails.set(key, started);
68
+ void started.then(() => { if (this.tails.get(key) === started)
69
+ this.tails.delete(key); });
70
+ this.prune();
71
+ return this.snapshot(job);
72
+ }
73
+ get(id) {
74
+ const job = this.jobs.get(id);
75
+ return job ? this.snapshot(job) : undefined;
76
+ }
77
+ /** Newest first. */
78
+ list() {
79
+ return [...this.jobs.values()].reverse().map(job => this.snapshot(job));
80
+ }
81
+ /** Resolves once no job is queued or running; used for a graceful shutdown. */
82
+ async whenIdle() {
83
+ while (this.busy())
84
+ await new Promise(resolve => setTimeout(resolve, 200));
85
+ }
86
+ busy() {
87
+ return [...this.jobs.values()].some(job => job.status === 'queued' || job.status === 'running');
88
+ }
89
+ append(job, line) {
90
+ if (job.progress.length >= this.progressLimit) {
91
+ job.progress.shift();
92
+ job.progressTruncated = true;
93
+ }
94
+ job.progress.push({ at: new Date().toISOString(), message: line });
95
+ }
96
+ snapshot(job) {
97
+ return { ...job, progress: job.progress.map(line => ({ ...line })), ...(job.progressTruncated ? { progressTruncated: true } : {}) };
98
+ }
99
+ /** Drop the oldest finished jobs first; a running job is never discarded. */
100
+ prune() {
101
+ while (this.jobs.size > this.limit) {
102
+ const oldest = [...this.jobs.values()].find(candidate => candidate.status === 'succeeded' || candidate.status === 'failed');
103
+ if (!oldest)
104
+ return;
105
+ this.jobs.delete(oldest.id);
106
+ }
107
+ }
108
+ }
109
+ exports.JobStore = JobStore;
110
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.js","sourceRoot":"","sources":["../../src/web/jobs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { WebProviders } from './types';
2
+ /**
3
+ * The web server's credential access.
4
+ *
5
+ * Credentials are the same profile the CLI writes (`afm az login` /
6
+ * `afm oss login`), so both front-ends agree; the browser may write them but
7
+ * only ever reads back booleans and non-secret names. An update keeps every
8
+ * other field of the section (for example a hand-configured `basePrefix`) and
9
+ * every other setting of the file.
10
+ */
11
+ export declare function storedProviders(): WebProviders;
12
+ //# sourceMappingURL=providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/web/providers.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgD,YAAY,EAAE,MAAM,SAAS,CAAC;AAkDrF;;;;;;;;GAQG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAoC9C"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.storedProviders = storedProviders;
4
+ const config_manager_1 = require("../cli/config-manager");
5
+ const stored_client_1 = require("../cli/stored-client");
6
+ /**
7
+ * One upload/reference name segment: bucket and region, not a secret.
8
+ * Rejected values are refused with a message rather than stored silently.
9
+ */
10
+ const nameSegment = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
11
+ function requiredText(value, field) {
12
+ const text = typeof value === 'string' ? value.trim() : '';
13
+ if (!text)
14
+ throw new Error(`${field} is required.`);
15
+ if (/[\x00-\x1f\x7f]/.test(text))
16
+ throw new Error(`${field} contains control characters.`);
17
+ return text;
18
+ }
19
+ function optionalNameSegment(value, field) {
20
+ const text = typeof value === 'string' ? value.trim() : '';
21
+ if (!text)
22
+ return undefined;
23
+ if (!nameSegment.test(text))
24
+ throw new Error(`${field} may only contain letters, digits, dot, underscore and hyphen.`);
25
+ return text;
26
+ }
27
+ /** The SAS URL must be a real http(s) URL; its signature stays server-side. */
28
+ function sasUrlOf(value) {
29
+ const text = requiredText(value, 'SAS URL');
30
+ let parsed;
31
+ try {
32
+ parsed = new URL(text);
33
+ }
34
+ catch {
35
+ throw new Error('SAS URL is not a valid URL.');
36
+ }
37
+ // `new URL()` tolerates a space (it percent-encodes it), which would silently
38
+ // corrupt the signature, so it is rejected explicitly.
39
+ if (/\s/.test(text))
40
+ throw new Error('SAS URL must not contain whitespace.');
41
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:')
42
+ throw new Error('SAS URL must use https or http.');
43
+ if (!parsed.hostname)
44
+ throw new Error('SAS URL has no host.');
45
+ return text;
46
+ }
47
+ /** Container name of a SAS URL, when it carries one. */
48
+ function containerOf(sasUrl) {
49
+ if (!sasUrl)
50
+ return null;
51
+ try {
52
+ const name = new URL(sasUrl).pathname.replace(/^\/+/, '').split('/')[0];
53
+ return name || null;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ /**
60
+ * The web server's credential access.
61
+ *
62
+ * Credentials are the same profile the CLI writes (`afm az login` /
63
+ * `afm oss login`), so both front-ends agree; the browser may write them but
64
+ * only ever reads back booleans and non-secret names. An update keeps every
65
+ * other field of the section (for example a hand-configured `basePrefix`) and
66
+ * every other setting of the file.
67
+ */
68
+ function storedProviders() {
69
+ return {
70
+ available: stored_client_1.storedProviderAvailability,
71
+ client(provider) { return (0, stored_client_1.createStoredClient)(provider); },
72
+ info() {
73
+ const config = (0, config_manager_1.readConfig)();
74
+ return {
75
+ ...(config.az ? { az: { container: containerOf(config.az.sasUrl) } } : {}),
76
+ ...(config.oss ? { oss: { bucket: config.oss.bucket ?? null, region: config.oss.region ?? null } } : {}),
77
+ };
78
+ },
79
+ async save(provider, credentials) {
80
+ const config = (0, config_manager_1.readConfig)();
81
+ if (provider === 'az') {
82
+ const previous = config.az;
83
+ (0, config_manager_1.saveAzureConfig)({ ...previous, sasUrl: sasUrlOf(credentials.sasUrl) });
84
+ return;
85
+ }
86
+ if (credentials.keyId === undefined || credentials.key === undefined) {
87
+ throw new Error('OSS credentials need both Key ID and Key.');
88
+ }
89
+ const previous = config.oss;
90
+ (0, config_manager_1.saveOSSConfig)({
91
+ ...previous,
92
+ keyId: requiredText(credentials.keyId, 'Key ID'),
93
+ key: requiredText(credentials.key, 'Key'),
94
+ ...(optionalNameSegment(credentials.bucket, 'Bucket') !== undefined ? { bucket: optionalNameSegment(credentials.bucket, 'Bucket') } : {}),
95
+ ...(optionalNameSegment(credentials.region, 'Region') !== undefined ? { region: optionalNameSegment(credentials.region, 'Region') } : {}),
96
+ });
97
+ },
98
+ async clear(provider) {
99
+ const config = (0, config_manager_1.readConfig)();
100
+ if (provider === 'az')
101
+ delete config.az;
102
+ else
103
+ delete config.oss;
104
+ (0, config_manager_1.writeConfig)(config);
105
+ },
106
+ };
107
+ }
108
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/web/providers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { JobStore } from './jobs';
2
+ import { WebManager, WebProviders, WebRegistry, WebStateInfo, WebUpdater } from './types';
3
+ export interface WebServerOptions {
4
+ /** Secret required by every `/api` request. At least 16 characters. */
5
+ token: string;
6
+ /** 0 (default) lets the OS choose a free port. */
7
+ port?: number;
8
+ /** Loopback address to bind; the default is the only value the CLI exposes. */
9
+ host?: string;
10
+ assetsDirectory?: string;
11
+ manager?: WebManager;
12
+ updater?: WebUpdater;
13
+ registry?: WebRegistry;
14
+ providers?: WebProviders;
15
+ state?: () => WebStateInfo;
16
+ jobs?: JobStore;
17
+ maxBodyBytes?: number;
18
+ resolveRoot?: (name: string, requested: string | undefined, dryRun: boolean) => Promise<string>;
19
+ /** Remember or forget the unified environment root; defaults to the CLI's `env root`. */
20
+ setEnvironmentRoot?: (root: string | null) => Promise<string | null>;
21
+ }
22
+ export interface RunningWebServer {
23
+ host: string;
24
+ port: number;
25
+ /** Page URL without the token. */
26
+ url: string;
27
+ /** Page URL with the token in the fragment, so it never reaches the server log. */
28
+ tokenUrl: string;
29
+ jobs: JobStore;
30
+ close(): Promise<void>;
31
+ }
32
+ /** The token lives in the URL fragment: fragments are not sent in requests. */
33
+ export declare function tokenizedUrl(url: string, token: string): string;
34
+ /**
35
+ * Start the local web interface.
36
+ *
37
+ * It binds loopback only, requires the token for every API call, rejects any
38
+ * request whose Host header is not one of its own loopback names (DNS
39
+ * rebinding) and never sends a CORS header, so a page on another origin can
40
+ * neither read a reply nor send the custom token header.
41
+ */
42
+ export declare function startWebServer(options: WebServerOptions): Promise<RunningWebServer>;
43
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/web/server.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1F,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,YAAY,CAAC;IAC3B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChG,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAID,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwDzF"}