Skip to content
28 changes: 15 additions & 13 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

### Fixed

- Use pathToFileURL so that import() works under ESM across platforms [#38](https://github.com/fastly/compute-js-static-publish/issues/38)

## [7.0.2] - 2025-09-16

### Fixed

- Fix script listed in readme instructions
- Handle symlinks properly in file enumeration [#41](https://github.com/fastly/compute-js-static-publish/issues/41)

### Breaking

- Rename symbols
Expand All @@ -26,12 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- S3-compatible storage
- S3-compatible storage (BETA)
- Add support for S3-compatible storage, such as Fastly Object Storage
- Store items using same keys as KV Store
- Use S3 object metadata for storing asset metadata
- Storage factored out to StorageProvider, and S3 is implemented using this architecture
- Configure using
- Add AWS-related configurations to fastly.toml in local_server and setup sections

- `static-publish.rc.js`
- Add `s3` mode configuration
Expand All @@ -41,6 +30,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `publish-content.config.js`
- `kvStoreAssetInclusionTest` renamed to `assetInclusionTest`. Previous name deprecated.

## [7.0.3] - 2025-09-29

### Fixed

- Use pathToFileURL so that import() works under ESM across platforms [#38](https://github.com/fastly/compute-js-static-publish/issues/38)

## [7.0.2] - 2025-09-16

### Fixed

- Fix script listed in readme instructions
- Handle symlinks properly in file enumeration [#41](https://github.com/fastly/compute-js-static-publish/issues/41)

## [7.0.1] - 2025-04-24

### Fixed
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ Create a directory for your project, place your static files in `./public`, then
```sh
npx @fastly/compute-js-static-publish@latest \
--root-dir=./public \
--storage-mode=kv-store \
--kv-store-name=site-content
```

Expand Down Expand Up @@ -236,7 +235,7 @@ const rc = {
export default rc;
```

### Using S3-compatible storage
### Using S3-compatible storage (BETA)

#### Fields:

Expand Down Expand Up @@ -525,7 +524,7 @@ If you do need to rebuild and redeploy the Compute app, simply run:
npm run fastly:deploy
```

### Using S3-compatible storage
### Using S3-compatible storage (BETA)

#### Local development

Expand Down Expand Up @@ -731,10 +730,9 @@ Run outside an existing Compute app directory:
# Using KV store storage
npx @fastly/compute-js-static-publish@latest \
--root-dir=./public \
--storage-mode=kv-store \
--kv-store-name=<site-content>

# Using S3 storage
# Using S3 storage (BETA)
npx @fastly/compute-js-static-publish@latest \
--root-dir=./public \
--storage-mode=s3 \
Expand All @@ -748,7 +746,7 @@ npx @fastly/compute-js-static-publish@latest \
```sh
npx @fastly/compute-js-static-publish@latest \
--root-dir=./public \
{ --storage-mode=kv-store --kv-store-name=<site-content> | \
{ [--storage-mode=kv-store] --kv-store-name=<site-content> | \
--storage-mode=s3 --s3-region=<s3 region> --s3-bucket=<bucket name> [--s3-endpoint=<endpoint>] } \
[--output=./compute-js] \
[--static-publisher-working-dir=<output>/static-publisher] \
Expand All @@ -768,7 +766,7 @@ npx @fastly/compute-js-static-publish@latest \
#### Options:

**Used to generate the Compute app:**
- `--storage-mode`: Required. Specifies the storage mode. Must be either `kv-store` or `s3`.
- `--storage-mode`: Specifies the storage mode. Must be either `kv-store` or `s3` (default: `kv-store`).

If `--storage-mode=kv-store`:
- `--kv-store-name`: Required. Name of KV Store to use.
Expand Down
2 changes: 1 addition & 1 deletion README.short.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This CLI tool helps you:
Create a directory for your project, place your static files in `./public`, then type:

```sh
npx @fastly/compute-js-static-publish@latest --root-dir=./public --storage-mode=kv-store --kv-store-name=site-content
npx @fastly/compute-js-static-publish@latest --root-dir=./public --kv-store-name=site-content
```

**New in v8:** S3-compatible storage (such as Fastly Object Storage) is also supported (Beta). To use this mode, type:
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/manage/clean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ KV Store Options:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

S3 Storage Options:
S3 Storage Options (BETA):
--aws-access-key-id=<key> AWS Access Key ID and Secret Access Key used to
--aws-secret-access-key=<key> interface with S3.
If not set, the tool will check:
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/manage/collections/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ KV Store Options:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

S3 Storage Options:
S3 Storage Options (BETA):
--aws-access-key-id=<key> AWS Access Key ID and Secret Access Key used to
--aws-secret-access-key=<key> interface with S3.
If not set, the tool will check:
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/manage/collections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ KV Store Options:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

S3 Storage Options:
S3 Storage Options (BETA):
--aws-access-key-id=<key> AWS Access Key ID and Secret Access Key used to
--aws-secret-access-key=<key> interface with S3.
If not set, the tool will check:
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/manage/collections/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ KV Store Options:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

S3 Storage Options:
S3 Storage Options (BETA):
--aws-access-key-id=<key> AWS Access Key ID and Secret Access Key used to
--aws-secret-access-key=<key> interface with S3.
If not set, the tool will check:
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/manage/collections/promote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ KV Store Options:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

S3 Storage Options:
S3 Storage Options (BETA):
--aws-access-key-id=<key> AWS Access Key ID and Secret Access Key used to
--aws-secret-access-key=<key> interface with S3.
If not set, the tool will check:
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/manage/collections/update-expiration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ KV Store Options:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

S3 Storage Options:
S3 Storage Options (BETA):
--aws-access-key-id=<key> AWS Access Key ID and Secret Access Key used to
--aws-secret-access-key=<key> interface with S3.
If not set, the tool will check:
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/manage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ KV Store Options:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

S3 Storage Options:
S3 Storage Options (BETA):
--aws-access-key-id=<key> AWS Access Key ID and Secret Access Key used to
--aws-secret-access-key=<key> interface with S3.
If not set, the tool will check:
Expand Down
18 changes: 11 additions & 7 deletions src/cli/commands/manage/publish-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { calculateFileSizeAndHash, enumerateFiles, rootRelative } from '../../ut
import { ensureVariantFileExists, type Variants } from '../../util/variants.js';
import {
loadStorageProviderFromStaticPublishRc,
StorageProvider,
StorageProviderBatch,
type StorageProviderBatchEntry,
} from '../../storage/storage-provider.js';
Expand All @@ -46,6 +47,12 @@ Description:
will see the updated index of files and updated server settings from the
publish-content.config.js file.

Required
--fastly-api-token=<token> Fastly API token for KV Store or cache access.
If not set, the tool will check:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

Optional:
--collection-name=<name> Name of the collection to publish into.
Default: value from static-publisher.rc.js (defaultCollectionName)
Expand Down Expand Up @@ -75,14 +82,9 @@ KV Store Options:
local files that will be used to simulate the KV Store
with the local development environment.

--fastly-api-token=<token> Fastly API token for KV Store access.
If not set, the tool will check:
1. FASTLY_API_TOKEN environment variable
2. Logged-in Fastly CLI profile

--kv-overwrite Alias for --overwrite-existing.

S3 Storage Options:
S3 Storage Options (BETA):
--aws-access-key-id=<key> AWS Access Key ID and Secret Access Key used to
--aws-secret-access-key=<key> interface with S3.
If not set, the tool will check:
Expand Down Expand Up @@ -229,7 +231,7 @@ export async function action(actionArgs: string[]) {
console.log(` | Static publisher working directory: ${staticPublisherWorkingDir}`);

// Storage Provider
let storageProvider: any;
let storageProvider: StorageProvider;
try {
storageProvider = await loadStorageProviderFromStaticPublishRc(staticPublisherRc, {
computeAppDir,
Expand Down Expand Up @@ -594,6 +596,8 @@ export async function action(actionArgs: string[]) {

console.log(`✅ Settings have been saved.`);

await storageProvider.purgeSurrogateKey(`${publishId}-${collectionName}`);

console.log(`🎉 Completed.`);

}
33 changes: 26 additions & 7 deletions src/cli/commands/scaffold/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ Description:
management mode.

Options:
--storage-mode <mode> (required) Storage mode for content storage.
Can be "kv-store" or "s3".
--storage-mode <mode> Storage mode for content storage.
Can be "kv-store" or "s3" (BETA).
(default: kv-store)
If --storage-mode=kv-store, then:
--kv-store-name <name> (required) Name of the KV Store.

Expand All @@ -45,8 +46,8 @@ Options:
--root-dir <path> (required) Path to static content (e.g., ./public)
-o, --output <dir> Output directory for Compute app (default: ./compute-js)
--static-publisher-working-dir <dir> Working directory for build artifacts (default: <output>/static-publisher)
--publish-id <id> Advanced. Prefix for KV keys (default: "default")
(default: ./compute-js/static-publisher)
--publish-id <id> Advanced. Prefix for KV keys (default: "default")

Compute Service Metadata:
--name <name> App name (for fastly.toml)
Expand Down Expand Up @@ -407,8 +408,8 @@ export async function action(actionArgs: string[]) {
const optionDefinitions: OptionDefinition[] = [
{ name: 'verbose', type: Boolean },

// Required. Storage mode for content storage. Can be "kv-store" or "s3".
{ name: 'storage-mode', type: String, },
// Storage mode for content storage. Can be "kv-store" or "s3".
{ name: 'storage-mode', type: String, defaultValue: 'kv-store', },

// If storage-mode=kv-store, then:

Expand Down Expand Up @@ -651,7 +652,7 @@ export async function action(actionArgs: string[]) {
const fastlyServiceId = options.serviceId;
const storageMode = options.storageMode;
if (!(storageMode === 'kv-store' || storageMode === 's3')) {
console.error(`❌ required parameter --storage-mode must be set to 'kv-store' or 's3'.`);
console.error(`❌ parameter --storage-mode must be set to 'kv-store' or 's3'.`);
process.exitCode = 1;
return;
}
Expand Down Expand Up @@ -725,7 +726,7 @@ export async function action(actionArgs: string[]) {
console.log('Storage Mode : Fastly KV Store');
console.log('KV Store Name :', kvStoreName);
} else if (storageMode === 's3') {
console.log('Storage Name : S3-compatible storage');
console.log('Storage Name : S3-compatible storage (BETA)');
console.log('S3 Region :', s3Region);
console.log('S3 Bucket :', s3Bucket);
console.log('S3 Endpoint :', String(s3EndpointUrl));
Expand Down Expand Up @@ -808,17 +809,24 @@ export async function action(actionArgs: string[]) {
if (storageMode === 'kv-store') {
const localServerKvStorePath = dotRelative(computeJsDir, path.resolve(staticPublisherWorkingDir, 'kvstore.json'));
fastlyTomlLocalServer = /* language=text */ `\
[local_server]

[local_server.kv_stores]
${kvStoreName} = { file = "${localServerKvStorePath}", format = "json" }
`;
fastlyTomlSetup = /* language=text */ `\
[setup]

[setup.kv_stores]
[setup.kv_stores.${kvStoreName}]
`;

// kvstore.json
resourceFiles[localServerKvStorePath] = '{}';
} else if (storageMode === 's3') {
fastlyTomlLocalServer = /* language=text */ `\
[local_server]

[local_server.secret_stores]
[[local_server.secret_stores.AWS_CREDENTIALS]]
key = "AWS_ACCESS_KEY_ID"
Expand All @@ -833,10 +841,21 @@ url = "${String(s3EndpointUrl)}"
override_host = "${s3EndpointUrl!.hostname}"
`;
fastlyTomlSetup = /* language=text */ `\
[setup]

[setup.backends]
[setup.backends.aws]
address = "${s3EndpointUrl!.hostname}"
description = "S3 API endpoint"
port = 443
[setup.secret_stores]
[setup.secret_stores.AWS_CREDENTIALS]
description = "Credentials for S3 storage"
[setup.secret_stores.AWS_CREDENTIALS.items]
[setup.secret_stores.AWS_CREDENTIALS.items.AWS_ACCESS_KEY_ID]
description = "AWS Access Key ID"
[setup.secret_stores.AWS_CREDENTIALS.items.AWS_SECRET_ACCESS_KEY]
description = "AWS Secret Access Key"
`;
}

Expand Down
3 changes: 3 additions & 0 deletions src/cli/storage/kv-store-local-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,7 @@ export class KvStoreLocalProvider implements StorageProvider {
// to save time by checking for an existing item. This is not applicable for local.
return null;
}

async purgeSurrogateKey(_surrogateKey: string): Promise<void> {
}
}
3 changes: 3 additions & 0 deletions src/cli/storage/kv-store-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ export class KvStoreProvider implements StorageProvider {
return kvStoreItemMetadata;

}

async purgeSurrogateKey(_surrogateKey: string): Promise<void> {
}
}

export function kvStoreEntryToStorageEntry(
Expand Down
Loading