@staticforge/azure 0.0.0-stage → 0.1.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 (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -2
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/clients.d.ts +23 -0
  5. package/dist/clients.d.ts.map +1 -0
  6. package/dist/clients.js +85 -0
  7. package/dist/clients.js.map +1 -0
  8. package/dist/deployer.d.ts +20 -0
  9. package/dist/deployer.d.ts.map +1 -0
  10. package/dist/deployer.js +343 -0
  11. package/dist/deployer.js.map +1 -0
  12. package/dist/history.d.ts +37 -0
  13. package/dist/history.d.ts.map +1 -0
  14. package/dist/history.js +49 -0
  15. package/dist/history.js.map +1 -0
  16. package/dist/iac.d.ts +27 -0
  17. package/dist/iac.d.ts.map +1 -0
  18. package/dist/iac.js +188 -0
  19. package/dist/iac.js.map +1 -0
  20. package/dist/index.d.ts +12 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +20 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/rebuild.d.ts +15 -0
  25. package/dist/rebuild.d.ts.map +1 -0
  26. package/dist/rebuild.js +97 -0
  27. package/dist/rebuild.js.map +1 -0
  28. package/dist/swa-config.d.ts +19 -0
  29. package/dist/swa-config.d.ts.map +1 -0
  30. package/dist/swa-config.js +136 -0
  31. package/dist/swa-config.js.map +1 -0
  32. package/dist/uploader.d.ts +24 -0
  33. package/dist/uploader.d.ts.map +1 -0
  34. package/dist/uploader.js +58 -0
  35. package/dist/uploader.js.map +1 -0
  36. package/package.json +52 -3
  37. package/terraform/modules/site/main.tf +38 -0
  38. package/terraform/modules/site/outputs.tf +27 -0
  39. package/terraform/modules/site/variables.tf +44 -0
  40. package/terraform/modules/site/versions.tf +10 -0
  41. package/terraform/state-bootstrap/main.tf +83 -0
  42. package/terraform/state-bootstrap/outputs.tf +21 -0
  43. package/terraform/state-bootstrap/variables.tf +53 -0
  44. package/terraform/state-bootstrap/versions.tf +14 -0
@@ -0,0 +1,23 @@
1
+ import { WebSiteManagementClient } from '@azure/arm-appservice';
2
+ import { StorageManagementClient } from '@azure/arm-storage';
3
+ import { type TokenCredential } from '@azure/identity';
4
+ import { SforgeError } from '@staticforge/core';
5
+ import { type HistoryStore } from './history.js';
6
+ /** Azure SDK clients, injectable for tests. Credentials come from `DefaultAzureCredential`. */
7
+ export interface AzureClients {
8
+ credential(): TokenCredential;
9
+ webSites(subscriptionId: string): WebSiteManagementClient;
10
+ storage(subscriptionId: string): StorageManagementClient;
11
+ /** The deploy history document in the state container. */
12
+ history(account: string, container: string, blobName: string): HistoryStore;
13
+ /** Output of `az <args>`, or undefined when the Azure CLI is not installed or fails. */
14
+ az(args: string[]): Promise<string | undefined>;
15
+ }
16
+ export declare function defaultClients(): AzureClients;
17
+ /** Status code of an SDK error. */
18
+ export declare function httpStatus(error: unknown): number | undefined;
19
+ /** Error name or service error code ("ResourceNotFound", "AuthorizationFailed", …). */
20
+ export declare function errorName(error: unknown): string;
21
+ /** Wrap an SDK error: credential and permission problems → SF_CLOUD_AUTH, the rest → `code`. */
22
+ export declare function azureError(error: unknown, what: string, code?: SforgeError['code']): SforgeError;
23
+ //# sourceMappingURL=clients.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../src/clients.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,KAAK,eAAe,EAA0B,MAAM,iBAAiB,CAAC;AAE/E,OAAO,EAAa,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAoB,MAAM,cAAc,CAAC;AAInE,+FAA+F;AAC/F,MAAM,WAAW,YAAY;IAC3B,UAAU,IAAI,eAAe,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,uBAAuB,CAAC;IAC1D,OAAO,CAAC,cAAc,EAAE,MAAM,GAAG,uBAAuB,CAAC;IACzD,0DAA0D;IAC1D,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAAC;IAC5E,wFAAwF;IACxF,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACjD;AAED,wBAAgB,cAAc,IAAI,YAAY,CAoC7C;AAUD,mCAAmC;AACnC,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAG7D;AAED,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIhD;AAED,gGAAgG;AAChG,wBAAgB,UAAU,CACxB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,WAAW,CAAC,MAAM,CAA0B,GACjD,WAAW,CA8Bb"}
@@ -0,0 +1,85 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { WebSiteManagementClient } from '@azure/arm-appservice';
4
+ import { StorageManagementClient } from '@azure/arm-storage';
5
+ import { DefaultAzureCredential } from '@azure/identity';
6
+ import { BlobServiceClient } from '@azure/storage-blob';
7
+ import { ErrorCode, SforgeError } from '@staticforge/core';
8
+ import { blobHistoryStore } from './history.js';
9
+ const run = promisify(execFile);
10
+ export function defaultClients() {
11
+ const cache = new Map();
12
+ const once = (key, create) => {
13
+ if (!cache.has(key))
14
+ cache.set(key, create());
15
+ return cache.get(key);
16
+ };
17
+ const credential = () => once('credential', () => new DefaultAzureCredential());
18
+ return {
19
+ credential,
20
+ webSites: (subscriptionId) => once(`web:${subscriptionId}`, () => new WebSiteManagementClient(credential(), subscriptionId)),
21
+ storage: (subscriptionId) => once(`storage:${subscriptionId}`, () => new StorageManagementClient(credential(), subscriptionId)),
22
+ history: (account, container, blobName) => blobHistoryStore(once(`blob:${account}`, () => new BlobServiceClient(`https://${account}.blob.core.windows.net`, credential())).getContainerClient(container), blobName),
23
+ async az(args) {
24
+ try {
25
+ const { stdout } = await run('az', args, { timeout: 30_000 });
26
+ return stdout.trim();
27
+ }
28
+ catch {
29
+ return undefined;
30
+ }
31
+ },
32
+ };
33
+ }
34
+ const AUTH_ERRORS = new Set([
35
+ 'CredentialUnavailableError',
36
+ 'AuthenticationRequiredError',
37
+ 'AggregateAuthenticationError',
38
+ 'AuthenticationError',
39
+ 'ExpiredAuthenticationToken',
40
+ ]);
41
+ /** Status code of an SDK error. */
42
+ export function httpStatus(error) {
43
+ const status = error?.statusCode;
44
+ return typeof status === 'number' ? status : undefined;
45
+ }
46
+ /** Error name or service error code ("ResourceNotFound", "AuthorizationFailed", …). */
47
+ export function errorName(error) {
48
+ if (error === null || typeof error !== 'object')
49
+ return '';
50
+ const e = error;
51
+ return e.code ?? e.name ?? '';
52
+ }
53
+ /** Wrap an SDK error: credential and permission problems → SF_CLOUD_AUTH, the rest → `code`. */
54
+ export function azureError(error, what, code = ErrorCode.DeployFailed) {
55
+ if (error instanceof SforgeError)
56
+ return error;
57
+ const name = errorName(error);
58
+ const status = httpStatus(error);
59
+ const message = error instanceof Error ? error.message : String(error);
60
+ if (AUTH_ERRORS.has(name) ||
61
+ status === 401 ||
62
+ /az login|AADSTS|credential|token.*expired|no accounts were found/i.test(message)) {
63
+ return new SforgeError(ErrorCode.CloudAuth, `${what}: ${firstLine(message)}`, {
64
+ cause: error,
65
+ hint: 'Sign in to Azure with `az login` (or set AZURE_CLIENT_ID, AZURE_TENANT_ID and AZURE_CLIENT_SECRET / federated credentials) and try again.',
66
+ });
67
+ }
68
+ if (status === 403 ||
69
+ name === 'AuthorizationFailed' ||
70
+ name === 'AuthorizationPermissionMismatch' ||
71
+ name === 'AuthorizationFailure') {
72
+ return new SforgeError(ErrorCode.CloudAuth, `${what}: access denied (${firstLine(message)})`, {
73
+ cause: error,
74
+ hint: 'The Azure identity in use lacks a permission this operation needs. Reading and writing state or deploy history needs "Storage Blob Data Contributor" on the state storage account; role assignments can take a few minutes to apply.',
75
+ });
76
+ }
77
+ return new SforgeError(code, `${what}: ${firstLine(message)}`, {
78
+ cause: error,
79
+ details: { error: name },
80
+ });
81
+ }
82
+ function firstLine(text) {
83
+ return text.split('\n')[0] ?? text;
84
+ }
85
+ //# sourceMappingURL=clients.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.js","sourceRoot":"","sources":["../src/clients.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type Deployer, type DeployerContext } from '@staticforge/provider-api';
2
+ import { type AzureClients } from './clients.js';
3
+ import { type Rebuild } from './rebuild.js';
4
+ import { type Uploader } from './uploader.js';
5
+ /** Outputs of terraform/modules/site the deployer needs. */
6
+ export declare const REQUIRED_OUTPUTS: string[];
7
+ export interface AzureDeployerOptions {
8
+ uploader?: Uploader;
9
+ rebuild?: Rebuild;
10
+ /** Milliseconds between checks that an upload went live. */
11
+ pollIntervalMs?: number;
12
+ readyTimeoutMs?: number;
13
+ }
14
+ /**
15
+ * The name Azure gives a preview environment: it keeps lowercase letters and digits
16
+ * only, so "pr-42" becomes "pr42" (and so does the host name).
17
+ */
18
+ export declare const previewEnvironment: (id: string) => string;
19
+ export declare function createAzureDeployer(context: DeployerContext, clients?: AzureClients, options?: AzureDeployerOptions): Deployer;
20
+ //# sourceMappingURL=deployer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployer.d.ts","sourceRoot":"","sources":["../src/deployer.ts"],"names":[],"mappings":"AAMA,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,eAAe,EASrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,KAAK,YAAY,EAA8B,MAAM,cAAc,CAAC;AAG7E,OAAO,EAAE,KAAK,OAAO,EAAmB,MAAM,cAAc,CAAC;AAE7D,OAAO,EAAE,KAAK,QAAQ,EAAkB,MAAM,eAAe,CAAC;AAE9D,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,UAM5B,CAAC;AAcF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAsBD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,IAAI,MAAM,KAAG,MACJ,CAAC;AAI7C,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,OAAO,GAAE,YAA+B,EACxC,OAAO,GAAE,oBAAyB,GACjC,QAAQ,CA+WV"}
@@ -0,0 +1,343 @@
1
+ import { constants, copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ import { ErrorCode, SforgeError } from '@staticforge/core';
5
+ import { projectName } from '@staticforge/iac';
6
+ import { assertPreviewId, gitIsDirty, gitShortSha, newVersionId, publishedFiles, readManifest, } from '@staticforge/provider-api';
7
+ import { azureError, defaultClients } from './clients.js';
8
+ import { HistoryConflict } from './history.js';
9
+ import { assertSignedIn, historyBlobName, resolveSubscription, stateLocation } from './iac.js';
10
+ import { rebuildAtCommit } from './rebuild.js';
11
+ import { SWA_CONFIG_FILE, generateStaticWebAppConfig } from './swa-config.js';
12
+ import { swaCliUploader } from './uploader.js';
13
+ /** Outputs of terraform/modules/site the deployer needs. */
14
+ export const REQUIRED_OUTPUTS = [
15
+ 'static_web_app_name',
16
+ 'resource_group',
17
+ 'default_host_name',
18
+ 'url',
19
+ 'location',
20
+ ];
21
+ /** Static Web Apps limits (https://learn.microsoft.com/azure/static-web-apps/quotas). */
22
+ const MAX_FILES = 15_000;
23
+ const FREE_MAX_BYTES = 250 * 1024 * 1024;
24
+ /** ARM calls the production environment "default". */
25
+ const PRODUCTION_BUILD = 'default';
26
+ const READY_TIMEOUT_MS = 5 * 60_000;
27
+ const READY_POLL_MS = 3_000;
28
+ /** The deploy client and Azure's clocks may differ a little. */
29
+ const CLOCK_SKEW_MS = 30_000;
30
+ const HISTORY_ATTEMPTS = 4;
31
+ /**
32
+ * The name Azure gives a preview environment: it keeps lowercase letters and digits
33
+ * only, so "pr-42" becomes "pr42" (and so does the host name).
34
+ */
35
+ export const previewEnvironment = (id) => id.toLowerCase().replace(/[^a-z0-9]/g, '');
36
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
37
+ export function createAzureDeployer(context, clients = defaultClients(), options = {}) {
38
+ const target = context.target;
39
+ const project = projectName(context.config);
40
+ const uploader = options.uploader ?? swaCliUploader;
41
+ const rebuild = options.rebuild ?? rebuildAtCommit;
42
+ const output = (key) => {
43
+ const value = context.outputs[key];
44
+ if (typeof value !== 'string' || value === '') {
45
+ throw new SforgeError(ErrorCode.NotProvisioned, `"${context.targetName}" has no "${key}" output`, { hint: `Run \`sforge provision ${context.targetName}\` first.` });
46
+ }
47
+ return value;
48
+ };
49
+ const appName = () => output('static_web_app_name');
50
+ const resourceGroup = () => output('resource_group');
51
+ let session;
52
+ function open() {
53
+ session ??= (async () => {
54
+ const subscriptionId = await resolveSubscription(clients, target, context.env);
55
+ await assertSignedIn(clients);
56
+ const state = stateLocation(target, subscriptionId, project, context.targetName);
57
+ return {
58
+ sites: clients.webSites(subscriptionId).staticSites,
59
+ history: clients.history(state.storageAccount, state.container, historyBlobName(project, context.targetName)),
60
+ };
61
+ })();
62
+ return session;
63
+ }
64
+ async function builds(sites) {
65
+ try {
66
+ const found = [];
67
+ for await (const b of sites.listStaticSiteBuilds(resourceGroup(), appName())) {
68
+ found.push({
69
+ buildId: b.buildId ?? '',
70
+ hostname: b.hostname,
71
+ status: b.status,
72
+ createdAt: b.createdTimeUtc,
73
+ updatedAt: b.lastUpdatedOn,
74
+ });
75
+ }
76
+ return found;
77
+ }
78
+ catch (error) {
79
+ throw azureError(error, 'Could not list the environments of the Static Web App');
80
+ }
81
+ }
82
+ /** The environment is live once ARM reports it Ready after the upload started. */
83
+ async function waitUntilLive(sites, environment, since) {
84
+ const buildId = environment === 'production' ? PRODUCTION_BUILD : previewEnvironment(environment);
85
+ const deadline = Date.now() + (options.readyTimeoutMs ?? READY_TIMEOUT_MS);
86
+ for (;;) {
87
+ const build = (await builds(sites)).find((b) => b.buildId === buildId);
88
+ const changed = (build?.updatedAt ?? build?.createdAt)?.getTime() ?? 0;
89
+ if (build?.status === 'Ready' && changed >= since - CLOCK_SKEW_MS)
90
+ return build;
91
+ if (build?.status === 'Failed') {
92
+ throw new SforgeError(ErrorCode.DeployFailed, `Azure reports the deployment as failed`, {
93
+ hint: 'Look at the Static Web App in the Azure portal (Environments) for details.',
94
+ });
95
+ }
96
+ if (Date.now() > deadline) {
97
+ throw new SforgeError(ErrorCode.DeployFailed, `The deployment was uploaded but is not live after ${Math.round((options.readyTimeoutMs ?? READY_TIMEOUT_MS) / 1000)}s (status: ${build?.status ?? 'unknown'})`, { hint: 'It may still finish: check `sforge versions`, or the Azure portal.' });
98
+ }
99
+ await sleep(options.pollIntervalMs ?? READY_POLL_MS);
100
+ }
101
+ }
102
+ async function deploymentToken(sites) {
103
+ try {
104
+ const secrets = await sites.listStaticSiteSecrets(resourceGroup(), appName());
105
+ const token = secrets.properties?.apiKey;
106
+ if (token === undefined || token === '')
107
+ throw new Error('the app has no deployment token');
108
+ return token;
109
+ }
110
+ catch (error) {
111
+ throw azureError(error, 'Could not get the deployment token of the Static Web App');
112
+ }
113
+ }
114
+ /** Record a production deploy; retries when another deploy updated the history meanwhile. */
115
+ async function record(history, entry) {
116
+ for (let attempt = 1; attempt <= HISTORY_ATTEMPTS; attempt++) {
117
+ try {
118
+ const { doc, etag } = await history.read();
119
+ const previous = doc.active;
120
+ const all = [entry, ...doc.versions.filter((v) => v.id !== entry.id)];
121
+ const kept = all.slice(0, target.retainVersions);
122
+ await history.write({ schema: 1, active: entry.id, versions: kept }, etag);
123
+ return { previous, pruned: all.slice(kept.length).map((v) => v.id) };
124
+ }
125
+ catch (error) {
126
+ if (!(error instanceof HistoryConflict)) {
127
+ throw azureError(error, 'The site is live, but its deploy history could not be updated');
128
+ }
129
+ }
130
+ }
131
+ throw new SforgeError(ErrorCode.DeployFailed, 'The site is live, but its deploy history could not be updated: other deploys kept changing it', { hint: 'Deploy again.' });
132
+ }
133
+ /** Copy the publishable files (no dot-paths such as .sforge/) and the generated config. */
134
+ function stage(buildDir, paths, configJson) {
135
+ const root = mkdtempSync(join(tmpdir(), 'sforge-azure-'));
136
+ const site = join(root, 'site');
137
+ mkdirSync(site, { recursive: true });
138
+ for (const path of paths) {
139
+ const destination = join(site, path);
140
+ mkdirSync(dirname(destination), { recursive: true });
141
+ copyFileSync(join(buildDir, path), destination, constants.COPYFILE_FICLONE);
142
+ }
143
+ if (configJson !== undefined)
144
+ writeFileSync(join(site, SWA_CONFIG_FILE), configJson);
145
+ return root;
146
+ }
147
+ function previewHost(id) {
148
+ // <app>-<id>.<region>.<rest of the default host name>
149
+ const [first = '', ...rest] = output('default_host_name').split('.');
150
+ return `${first}-${previewEnvironment(id)}.${output('location')}.${rest.join('.')}`;
151
+ }
152
+ async function publish(deployOptions, extras) {
153
+ const { buildDir, preview } = deployOptions;
154
+ if (preview !== undefined)
155
+ assertPreviewId(preview);
156
+ const manifest = readManifest(buildDir);
157
+ const files = publishedFiles(manifest);
158
+ const generated = generateStaticWebAppConfig(context.config, manifest);
159
+ const ownConfig = manifest.files[SWA_CONFIG_FILE] !== undefined;
160
+ if (ownConfig) {
161
+ context.logger.warn(`static/${SWA_CONFIG_FILE} is used as it is: sforge's security headers, cache rules and 404 page are not added`);
162
+ }
163
+ else if (generated.droppedRoutes > 0) {
164
+ context.logger.warn(`${generated.droppedRoutes} fingerprinted files are not cached for a year: Static Web Apps limits ${SWA_CONFIG_FILE} to 20 KB`);
165
+ }
166
+ const fileCount = files.length + (ownConfig ? 0 : 1);
167
+ const bytes = files.reduce((sum, [, entry]) => sum + entry.size, 0);
168
+ if (fileCount > MAX_FILES) {
169
+ throw new SforgeError(ErrorCode.DeployFailed, `The site has ${fileCount} files; Static Web Apps allows ${MAX_FILES} per app`);
170
+ }
171
+ if (target.sku === 'Free' && bytes > FREE_MAX_BYTES) {
172
+ throw new SforgeError(ErrorCode.DeployFailed, `The site is ${Math.round(bytes / 1024 / 1024)} MB; the Free plan allows ${FREE_MAX_BYTES / 1024 / 1024} MB per environment`, { hint: 'Reduce the size of images and videos, or set sku: "Standard".' });
173
+ }
174
+ const now = deployOptions.now ?? new Date();
175
+ const sha = deployOptions.gitSha ?? gitShortSha(context.rootDir, context.env);
176
+ const versionId = preview ?? newVersionId(now, sha);
177
+ const environment = preview ?? 'production';
178
+ const base = {
179
+ target: context.targetName,
180
+ provider: 'azure',
181
+ versionId,
182
+ preview: preview !== undefined,
183
+ uploaded: fileCount,
184
+ copied: 0,
185
+ skipped: 0,
186
+ deleted: 0,
187
+ bytes,
188
+ pruned: [],
189
+ invalidated: false,
190
+ };
191
+ if (deployOptions.dryRun === true) {
192
+ return {
193
+ ...base,
194
+ url: preview === undefined ? output('url') : `https://${previewHost(preview)}`,
195
+ dryRun: true,
196
+ };
197
+ }
198
+ const { sites, history } = await open();
199
+ const token = await deploymentToken(sites);
200
+ const staging = stage(buildDir, files.map(([path]) => path), ownConfig ? undefined : generated.json);
201
+ const startedAt = Date.now();
202
+ let reported;
203
+ try {
204
+ context.logger.info(`Uploading ${fileCount} files to ${environment}`);
205
+ reported = (await uploader({
206
+ dir: join(staging, 'site'),
207
+ environment,
208
+ token,
209
+ env: context.env,
210
+ })).url;
211
+ }
212
+ finally {
213
+ rmSync(staging, { recursive: true, force: true });
214
+ }
215
+ const live = await waitUntilLive(sites, environment, startedAt);
216
+ const url = preview === undefined
217
+ ? output('url')
218
+ : `https://${live.hostname ?? reported?.replace(/^https:\/\//, '') ?? previewHost(preview)}`;
219
+ if (preview !== undefined)
220
+ return { ...base, url, dryRun: false };
221
+ const { previous, pruned } = await record(history, {
222
+ id: versionId,
223
+ createdAt: now.toISOString(),
224
+ ...(sha !== undefined && { gitSha: sha }),
225
+ ...((extras.dirty ?? gitIsDirty(context.rootDir)) && { dirty: true }),
226
+ files: fileCount,
227
+ bytes,
228
+ ...(extras.rollbackOf !== undefined && { rollbackOf: extras.rollbackOf }),
229
+ });
230
+ return {
231
+ ...base,
232
+ url,
233
+ pruned,
234
+ dryRun: false,
235
+ ...(previous !== null && { previousVersionId: previous }),
236
+ };
237
+ }
238
+ return {
239
+ deploy: (deployOptions) => publish(deployOptions, {}),
240
+ async versions() {
241
+ const { sites, history } = await open();
242
+ let doc;
243
+ try {
244
+ doc = (await history.read()).doc;
245
+ }
246
+ catch (error) {
247
+ throw azureError(error, 'Could not read the deploy history');
248
+ }
249
+ const production = doc.versions.map((v) => ({
250
+ id: v.id,
251
+ createdAt: v.createdAt,
252
+ ...(v.gitSha !== undefined && { gitSha: v.gitSha }),
253
+ files: v.files,
254
+ bytes: v.bytes,
255
+ active: v.id === doc.active,
256
+ preview: false,
257
+ }));
258
+ const previews = (await builds(sites))
259
+ .filter((b) => b.buildId !== PRODUCTION_BUILD && b.buildId !== '')
260
+ .map((b) => ({
261
+ id: b.buildId,
262
+ createdAt: (b.createdAt ?? b.updatedAt)?.toISOString() ?? '',
263
+ files: 0,
264
+ bytes: 0,
265
+ active: false,
266
+ preview: true,
267
+ ...(b.hostname !== undefined && { url: `https://${b.hostname}` }),
268
+ }))
269
+ .sort((a, b) => b.createdAt.localeCompare(a.createdAt));
270
+ return [...production, ...previews];
271
+ },
272
+ async rollback(to) {
273
+ const { history } = await open();
274
+ let doc;
275
+ try {
276
+ doc = (await history.read()).doc;
277
+ }
278
+ catch (error) {
279
+ throw azureError(error, 'Could not read the deploy history');
280
+ }
281
+ const activeIndex = doc.versions.findIndex((v) => v.id === doc.active);
282
+ if (activeIndex === -1) {
283
+ throw new SforgeError(ErrorCode.VersionNotFound, `Nothing has been deployed to "${context.targetName}" yet`);
284
+ }
285
+ const wanted = to === undefined
286
+ ? doc.versions[activeIndex + 1]
287
+ : doc.versions.find((v) => v.id === to || (to.length >= 4 && v.gitSha?.startsWith(to) === true));
288
+ if (wanted === undefined) {
289
+ throw new SforgeError(ErrorCode.VersionNotFound, to === undefined
290
+ ? 'There is no earlier version to roll back to'
291
+ : `No deployed version matches "${to}"`, { hint: 'See `sforge versions`; Azure keeps the last `retainVersions` deploys.' });
292
+ }
293
+ if (wanted.id === doc.active) {
294
+ throw new SforgeError(ErrorCode.Usage, `${wanted.id} is already the active version`);
295
+ }
296
+ if (wanted.gitSha === undefined || wanted.gitSha === 'local' || wanted.dirty === true) {
297
+ throw new SforgeError(ErrorCode.Unsupported, `${wanted.id} cannot be rebuilt: it was deployed ${wanted.dirty === true ? 'with uncommitted changes' : 'outside a git repository'}`, {
298
+ hint: 'Azure rollbacks rebuild the site from the commit. Roll back to a version deployed from a clean checkout, or fix forward.',
299
+ });
300
+ }
301
+ const rebuilt = await rebuild(wanted.gitSha, context);
302
+ try {
303
+ const result = await publish({ buildDir: rebuilt.buildDir, gitSha: wanted.gitSha }, { rollbackOf: wanted.id, dirty: false });
304
+ return {
305
+ target: context.targetName,
306
+ versionId: result.versionId,
307
+ previousVersionId: doc.active,
308
+ url: result.url,
309
+ };
310
+ }
311
+ finally {
312
+ rebuilt.cleanup();
313
+ }
314
+ },
315
+ async destroyPreview(previewId) {
316
+ assertPreviewId(previewId);
317
+ const { sites } = await open();
318
+ const environment = previewEnvironment(previewId);
319
+ const exists = (await builds(sites)).some((b) => b.buildId === environment);
320
+ if (exists) {
321
+ try {
322
+ const poller = sites.deleteStaticSiteBuild(resourceGroup(), appName(), environment);
323
+ await poller.pollUntilDone();
324
+ }
325
+ catch (error) {
326
+ throw azureError(error, `Could not remove the preview ${previewId}`);
327
+ }
328
+ }
329
+ return { target: context.targetName, previewId, deleted: 0, existed: exists };
330
+ },
331
+ async current() {
332
+ const { history } = await open();
333
+ try {
334
+ return { url: output('url'), versionId: (await history.read()).doc.active };
335
+ }
336
+ catch (error) {
337
+ throw azureError(error, 'Could not read the deploy history');
338
+ }
339
+ },
340
+ previewBaseUrl: (previewId) => `https://${previewHost(previewId)}`,
341
+ };
342
+ }
343
+ //# sourceMappingURL=deployer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployer.js","sourceRoot":"","sources":["../src/deployer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { ContainerClient } from '@azure/storage-blob';
2
+ /** A production deploy, as recorded in the history. */
3
+ export interface VersionEntry {
4
+ id: string;
5
+ createdAt: string;
6
+ gitSha?: string;
7
+ /** Deployed from a working tree with uncommitted changes: a rebuild would not match it. */
8
+ dirty?: boolean;
9
+ files: number;
10
+ bytes: number;
11
+ /** Set when this deploy was a rollback: the version it rebuilt. */
12
+ rollbackOf?: string;
13
+ }
14
+ /**
15
+ * Static Web Apps keeps no versions of its own, so sforge records production
16
+ * deploys (newest first) in the state container, next to the state files.
17
+ */
18
+ export interface HistoryDoc {
19
+ schema: 1;
20
+ active: string | null;
21
+ versions: VersionEntry[];
22
+ }
23
+ export declare const emptyHistory: () => HistoryDoc;
24
+ /** Another deploy changed the history since it was read. */
25
+ export declare class HistoryConflict extends Error {
26
+ constructor();
27
+ }
28
+ export interface HistoryStore {
29
+ read(): Promise<{
30
+ doc: HistoryDoc;
31
+ etag: string | undefined;
32
+ }>;
33
+ /** Writes only if the document is still at `etag` (or does not exist, when undefined). */
34
+ write(doc: HistoryDoc, etag: string | undefined): Promise<void>;
35
+ }
36
+ export declare function blobHistoryStore(container: ContainerClient, blobName: string): HistoryStore;
37
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,eAAO,MAAM,YAAY,QAAO,UAAyD,CAAC;AAE1F,4DAA4D;AAC5D,qBAAa,eAAgB,SAAQ,KAAK;;CAKzC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CAAC;IAC/D,0FAA0F;IAC1F,KAAK,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjE;AAKD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAoC3F"}
@@ -0,0 +1,49 @@
1
+ import { ErrorCode, SforgeError } from '@staticforge/core';
2
+ export const emptyHistory = () => ({ schema: 1, active: null, versions: [] });
3
+ /** Another deploy changed the history since it was read. */
4
+ export class HistoryConflict extends Error {
5
+ constructor() {
6
+ super('The deploy history changed while it was being updated');
7
+ this.name = 'HistoryConflict';
8
+ }
9
+ }
10
+ const statusOf = (error) => error?.statusCode;
11
+ export function blobHistoryStore(container, blobName) {
12
+ const blob = container.getBlockBlobClient(blobName);
13
+ return {
14
+ async read() {
15
+ try {
16
+ const response = await blob.download();
17
+ const chunks = [];
18
+ for await (const chunk of response.readableStreamBody) {
19
+ chunks.push(Buffer.from(chunk));
20
+ }
21
+ const doc = JSON.parse(Buffer.concat(chunks).toString('utf8'));
22
+ if (doc.schema !== 1 || !Array.isArray(doc.versions)) {
23
+ throw new SforgeError(ErrorCode.DeployFailed, `${blobName} is not a staticforge deploy history`);
24
+ }
25
+ return { doc, etag: response.etag };
26
+ }
27
+ catch (error) {
28
+ if (statusOf(error) === 404)
29
+ return { doc: emptyHistory(), etag: undefined };
30
+ throw error;
31
+ }
32
+ },
33
+ async write(doc, etag) {
34
+ const body = Buffer.from(`${JSON.stringify(doc, null, 2)}\n`);
35
+ try {
36
+ await blob.upload(body, body.length, {
37
+ blobHTTPHeaders: { blobContentType: 'application/json' },
38
+ conditions: etag === undefined ? { ifNoneMatch: '*' } : { ifMatch: etag },
39
+ });
40
+ }
41
+ catch (error) {
42
+ if (statusOf(error) === 412 || statusOf(error) === 409)
43
+ throw new HistoryConflict();
44
+ throw error;
45
+ }
46
+ },
47
+ };
48
+ }
49
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAyB3D,MAAM,CAAC,MAAM,YAAY,GAAG,GAAe,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;AAE1F,4DAA4D;AAC5D,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC;QACE,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAQD,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAsB,EAAE,CACrD,KAAwC,EAAE,UAAU,CAAC;AAExD,MAAM,UAAU,gBAAgB,CAAC,SAA0B,EAAE,QAAgB;IAC3E,MAAM,IAAI,GAAG,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACpD,OAAO;QACL,KAAK,CAAC,IAAI;YACR,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACvC,MAAM,MAAM,GAAa,EAAE,CAAC;gBAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ,CAAC,kBAAoD,EAAE,CAAC;oBACxF,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;gBAClC,CAAC;gBACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAe,CAAC;gBAC7E,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACrD,MAAM,IAAI,WAAW,CACnB,SAAS,CAAC,YAAY,EACtB,GAAG,QAAQ,sCAAsC,CAClD,CAAC;gBACJ,CAAC;gBACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;YACtC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG;oBAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;gBAC7E,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI;YACnB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAC9D,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE;oBACnC,eAAe,EAAE,EAAE,eAAe,EAAE,kBAAkB,EAAE;oBACxD,UAAU,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;iBAC1E,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG;oBAAE,MAAM,IAAI,eAAe,EAAE,CAAC;gBACpF,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/iac.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { type AzureTargetConfig } from '@staticforge/core';
2
+ import { type IacProfile } from '@staticforge/iac';
3
+ import { type AzureClients } from './clients.js';
4
+ export declare const SITE_MODULE_DIR: string;
5
+ export declare const STATE_BOOTSTRAP_DIR: string;
6
+ /** Where Azure offers Static Web Apps. */
7
+ export declare const SWA_LOCATIONS: string[];
8
+ export interface StateLocation {
9
+ subscriptionId: string;
10
+ resourceGroup: string;
11
+ storageAccount: string;
12
+ container: string;
13
+ key: string;
14
+ }
15
+ /** `sfstate<hash of the subscription>` in resource group `sforge-state`, key `<site>/<target>.tfstate`. */
16
+ export declare function stateLocation(target: AzureTargetConfig, subscriptionId: string, project: string, targetName: string): StateLocation;
17
+ /** Blob that holds a target's deploy history, in the state container. */
18
+ export declare const historyBlobName: (project: string, targetName: string) => string;
19
+ /**
20
+ * `targets.<n>.subscriptionId`, else AZURE_SUBSCRIPTION_ID / ARM_SUBSCRIPTION_ID,
21
+ * else the subscription `az login` selected.
22
+ */
23
+ export declare function resolveSubscription(clients: AzureClients, target: AzureTargetConfig, env: NodeJS.ProcessEnv): Promise<string>;
24
+ /** Fail early, with a useful message, when no credential works. */
25
+ export declare function assertSignedIn(clients: AzureClients): Promise<void>;
26
+ export declare function createAzureIacProfile(clients?: AzureClients): IacProfile;
27
+ //# sourceMappingURL=iac.d.ts.map