@kristijorgji/static-asset-upload 0.1.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +116 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +19 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/upload.d.ts +5 -0
  8. package/dist/commands/upload.d.ts.map +1 -0
  9. package/dist/commands/upload.js +11 -0
  10. package/dist/commands/upload.js.map +1 -0
  11. package/dist/config/define-config.d.ts +3 -0
  12. package/dist/config/define-config.d.ts.map +1 -0
  13. package/dist/config/define-config.js +4 -0
  14. package/dist/config/define-config.js.map +1 -0
  15. package/dist/config/index.d.ts +4 -0
  16. package/dist/config/index.d.ts.map +1 -0
  17. package/dist/config/index.js +3 -0
  18. package/dist/config/index.js.map +1 -0
  19. package/dist/config/load-config.d.ts +6 -0
  20. package/dist/config/load-config.d.ts.map +1 -0
  21. package/dist/config/load-config.js +77 -0
  22. package/dist/config/load-config.js.map +1 -0
  23. package/dist/config/types.d.ts +68 -0
  24. package/dist/config/types.d.ts.map +1 -0
  25. package/dist/config/types.js +2 -0
  26. package/dist/config/types.js.map +1 -0
  27. package/dist/fs/walk-files.d.ts +3 -0
  28. package/dist/fs/walk-files.d.ts.map +1 -0
  29. package/dist/fs/walk-files.js +18 -0
  30. package/dist/fs/walk-files.js.map +1 -0
  31. package/dist/glob/match.d.ts +4 -0
  32. package/dist/glob/match.d.ts.map +1 -0
  33. package/dist/glob/match.js +38 -0
  34. package/dist/glob/match.js.map +1 -0
  35. package/dist/index.d.ts +5 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +4 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/mime/content-type.d.ts +2 -0
  40. package/dist/mime/content-type.d.ts.map +1 -0
  41. package/dist/mime/content-type.js +5 -0
  42. package/dist/mime/content-type.js.map +1 -0
  43. package/dist/plan/resolve-plan.d.ts +4 -0
  44. package/dist/plan/resolve-plan.d.ts.map +1 -0
  45. package/dist/plan/resolve-plan.js +74 -0
  46. package/dist/plan/resolve-plan.js.map +1 -0
  47. package/dist/upload/run-upload.d.ts +3 -0
  48. package/dist/upload/run-upload.d.ts.map +1 -0
  49. package/dist/upload/run-upload.js +44 -0
  50. package/dist/upload/run-upload.js.map +1 -0
  51. package/dist/upload/s3-provider.d.ts +9 -0
  52. package/dist/upload/s3-provider.d.ts.map +1 -0
  53. package/dist/upload/s3-provider.js +26 -0
  54. package/dist/upload/s3-provider.js.map +1 -0
  55. package/package.json +59 -0
  56. package/skills/static-asset-upload/SKILL.md +32 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kristijorgji
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # @kristijorgji/static-asset-upload
2
+
3
+ Upload a caller-supplied static-asset manifest to S3-compatible object storage (AWS S3, Cloudflare R2, MinIO). Framework-agnostic: there is no Next.js peer and no default `web/` or `_next/` prefix.
4
+
5
+ The package plans files from local directories, maps Cache-Control and Content-Type, and puts objects. CDN layout, env wiring, and prune/invalidation stay in the app.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add -D @kristijorgji/static-asset-upload
11
+ ```
12
+
13
+ ## Setup
14
+
15
+ Create `static-assets.config.ts` at the app root (discovered upward as `.ts`, `.mts`, `.js`, or `.mjs`):
16
+
17
+ ```ts
18
+ import { defineStaticAssetsConfig } from '@kristijorgji/static-asset-upload/config';
19
+
20
+ export default defineStaticAssetsConfig({
21
+ root: import.meta.dirname,
22
+ bucket: process.env.ASSETS_BUCKET!,
23
+ region: process.env.S3_REGION ?? 'auto',
24
+ commit: process.env.APP_VERSION!,
25
+ endpoint: process.env.S3_ENDPOINT,
26
+ forcePathStyle: Boolean(process.env.S3_ENDPOINT),
27
+ commitPrefix: 'assets/{commit}',
28
+ sharedPrefix: 'assets/shared',
29
+ requiredTargetIds: ['hashed-static'],
30
+ validateCommit: (commit) => {
31
+ if (!/^[0-9a-f]{7,40}$/i.test(commit)) {
32
+ throw new Error('commit must be a git hash (7–40 hex characters)');
33
+ }
34
+ },
35
+ targets: [
36
+ {
37
+ id: 'hashed-static',
38
+ localDir: 'dist/static',
39
+ remotePrefix: '{commitPrefix}/static',
40
+ versioning: 'commit',
41
+ cacheControl: 'public, max-age=31536000, immutable',
42
+ },
43
+ {
44
+ id: 'public-icons',
45
+ localDir: 'public',
46
+ remotePrefix: '{sharedPrefix}',
47
+ versioning: 'shared',
48
+ cacheControl: 'public, max-age=10800',
49
+ include: ['icon.png'],
50
+ exclude: ['sw.js'],
51
+ optional: true,
52
+ },
53
+ ],
54
+ });
55
+ ```
56
+
57
+ Add a script:
58
+
59
+ ```json
60
+ {
61
+ "scripts": {
62
+ "assets:upload": "kj-static-assets upload",
63
+ "assets:upload:dry": "kj-static-assets upload --dry-run"
64
+ }
65
+ }
66
+ ```
67
+
68
+ AWS credentials use the standard SDK chain. Set `endpoint` (and usually `forcePathStyle`) for R2 or MinIO.
69
+
70
+ ## Commands
71
+
72
+ | Command | Flags | When |
73
+ | --- | --- | --- |
74
+ | `upload` | `--dry-run` | Put planned objects, or print the plan and exit 0 |
75
+
76
+ ## Config
77
+
78
+ | Field | Default | Purpose |
79
+ | --- | --- | --- |
80
+ | `root` | required | App directory; `localDir` values are relative to this |
81
+ | `bucket` | required | Destination bucket |
82
+ | `commit` | required | Substituted into `{commit}` in prefixes |
83
+ | `commitPrefix` / `sharedPrefix` | required | Remote key prefixes; `{commit}` is expanded |
84
+ | `targets` | required | Directories to walk |
85
+ | `region` | `us-east-1` | Passed to the S3 client (`auto` is valid for R2) |
86
+ | `endpoint` | unset | S3-compatible API URL |
87
+ | `forcePathStyle` | `false` | Path-style addressing for MinIO / some R2 setups |
88
+ | `targetIds` | all targets | Limit the plan to these target ids |
89
+ | `requiredTargetIds` | `[]` | Fail if a listed target produces no files |
90
+ | `validateCommit` | no-op | Optional commit-format check |
91
+
92
+ Each target sets its own `cacheControl` string. `{commitPrefix}` and `{sharedPrefix}` in `remotePrefix` are expanded by the planner.
93
+
94
+ ## Programmatic API
95
+
96
+ ```ts
97
+ import {
98
+ assertRequiredTargets,
99
+ defineStaticAssetsConfig,
100
+ resolveUploadPlan,
101
+ runStaticAssetUpload,
102
+ } from '@kristijorgji/static-asset-upload';
103
+
104
+ const config = defineStaticAssetsConfig({ /* ... */ });
105
+ const plan = resolveUploadPlan(config);
106
+ assertRequiredTargets(plan, config);
107
+ await runStaticAssetUpload(config, { dryRun: true });
108
+ ```
109
+
110
+ `runStaticAssetUpload` constructs an `S3Client` from `region` / `endpoint` / `forcePathStyle`. Tests can pass `{ client: { send } }` instead.
111
+
112
+ Plan entries use `remoteKey` (object key), not a vendor-specific field name.
113
+
114
+ ## License
115
+
116
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { logFatalAndExitFromError } from '@kristijorgji/cli-kit';
4
+ import { runUpload } from './commands/upload.js';
5
+ import { loadConfig } from './config/load-config.js';
6
+ const program = new Command();
7
+ program.name('kj-static-assets').description('Upload static assets from a caller-supplied manifest to S3-compatible storage');
8
+ program
9
+ .command('upload')
10
+ .description('Upload files from static-assets.config to object storage')
11
+ .option('--dry-run', 'print the upload plan without putting objects', false)
12
+ .action(async (options) => {
13
+ const config = await loadConfig();
14
+ await runUpload(config, { dryRun: Boolean(options.dryRun) });
15
+ });
16
+ program.parseAsync(process.argv).catch((error) => {
17
+ logFatalAndExitFromError(error);
18
+ });
19
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,WAAW,CAAC,+EAA+E,CAAC,CAAC;AAE9H,OAAO;KACF,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,0DAA0D,CAAC;KACvE,MAAM,CAAC,WAAW,EAAE,+CAA+C,EAAE,KAAK,CAAC;KAC3E,MAAM,CAAC,KAAK,EAAE,OAA6B,EAAE,EAAE;IAC5C,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,SAAS,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC,CAAC,CAAC;AAEP,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IACtD,wBAAwB,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ResolvedStaticAssetsConfig } from '../config/types.js';
2
+ export declare function runUpload(config: ResolvedStaticAssetsConfig, options: {
3
+ dryRun: boolean;
4
+ }): Promise<void>;
5
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAGrE,wBAAsB,SAAS,CAC3B,MAAM,EAAE,0BAA0B,EAClC,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAC7B,OAAO,CAAC,IAAI,CAAC,CAOf"}
@@ -0,0 +1,11 @@
1
+ import { cliLogger } from '@kristijorgji/cli-kit';
2
+ import { runStaticAssetUpload } from '../upload/run-upload.js';
3
+ export async function runUpload(config, options) {
4
+ const result = await runStaticAssetUpload(config, { dryRun: options.dryRun });
5
+ if (options.dryRun) {
6
+ cliLogger.info('Dry run complete');
7
+ return;
8
+ }
9
+ cliLogger.info(`Upload complete (${result.totalUploaded} files)`);
10
+ }
11
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,SAAS,CAC3B,MAAkC,EAClC,OAA4B;IAE5B,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACnC,OAAO;IACX,CAAC;IACD,SAAS,CAAC,IAAI,CAAC,oBAAoB,MAAM,CAAC,aAAa,SAAS,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { StaticAssetsConfig } from './types.js';
2
+ export declare function defineStaticAssetsConfig(config: StaticAssetsConfig): StaticAssetsConfig;
3
+ //# sourceMappingURL=define-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-config.d.ts","sourceRoot":"","sources":["../../src/config/define-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,kBAAkB,CAEvF"}
@@ -0,0 +1,4 @@
1
+ export function defineStaticAssetsConfig(config) {
2
+ return config;
3
+ }
4
+ //# sourceMappingURL=define-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-config.js","sourceRoot":"","sources":["../../src/config/define-config.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,wBAAwB,CAAC,MAA0B;IAC/D,OAAO,MAAM,CAAC;AAClB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { defineStaticAssetsConfig } from './define-config.js';
2
+ export { expandPlaceholders, findConfigFile, loadConfig, resolveStaticAssetsConfig } from './load-config.js';
3
+ export type { ResolvedStaticAssetsConfig, StaticAssetStoreClient, StaticAssetTarget, StaticAssetUploadOptions, StaticAssetsConfig, UploadPlan, UploadPlanEntry, UploadResult, VersioningTier, } from './types.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7G,YAAY,EACR,0BAA0B,EAC1B,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,YAAY,EACZ,cAAc,GACjB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { defineStaticAssetsConfig } from './define-config.js';
2
+ export { expandPlaceholders, findConfigFile, loadConfig, resolveStaticAssetsConfig } from './load-config.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { ResolvedStaticAssetsConfig, StaticAssetsConfig } from './types.js';
2
+ export declare function findConfigFile(startDir: string): string | null;
3
+ export declare function expandPlaceholders(template: string, vars: Record<string, string>): string;
4
+ export declare function resolveStaticAssetsConfig(config: StaticAssetsConfig, baseDir?: string): ResolvedStaticAssetsConfig;
5
+ export declare function loadConfig(cwd?: string): Promise<ResolvedStaticAssetsConfig>;
6
+ //# sourceMappingURL=load-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-config.d.ts","sourceRoot":"","sources":["../../src/config/load-config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,0BAA0B,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAWjF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe9D;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAEzF;AAED,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,MAAsB,GAChC,0BAA0B,CAuC5B;AAED,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAYjG"}
@@ -0,0 +1,77 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { dirname, join, resolve } from 'node:path';
3
+ import { createJiti } from 'jiti';
4
+ const CONFIG_FILENAMES = [
5
+ 'static-assets.config.ts',
6
+ 'static-assets.config.mts',
7
+ 'static-assets.config.js',
8
+ 'static-assets.config.mjs',
9
+ ];
10
+ const DEFAULT_REGION = 'us-east-1';
11
+ export function findConfigFile(startDir) {
12
+ let current = resolve(startDir);
13
+ while (true) {
14
+ for (const filename of CONFIG_FILENAMES) {
15
+ const candidate = join(current, filename);
16
+ if (existsSync(candidate)) {
17
+ return candidate;
18
+ }
19
+ }
20
+ const parent = dirname(current);
21
+ if (parent === current) {
22
+ return null;
23
+ }
24
+ current = parent;
25
+ }
26
+ }
27
+ export function expandPlaceholders(template, vars) {
28
+ return template.replace(/\{(\w+)\}/g, (match, key) => vars[key] ?? match);
29
+ }
30
+ export function resolveStaticAssetsConfig(config, baseDir = process.cwd()) {
31
+ if (!config.root?.trim()) {
32
+ throw new Error('static-assets config must set root');
33
+ }
34
+ if (!config.bucket?.trim()) {
35
+ throw new Error('static-assets config must set bucket');
36
+ }
37
+ if (!config.commit?.trim()) {
38
+ throw new Error('static-assets config must set commit');
39
+ }
40
+ if (!config.commitPrefix?.trim()) {
41
+ throw new Error('static-assets config must set commitPrefix');
42
+ }
43
+ if (!config.sharedPrefix?.trim()) {
44
+ throw new Error('static-assets config must set sharedPrefix');
45
+ }
46
+ if (!config.targets?.length) {
47
+ throw new Error('static-assets config must set targets');
48
+ }
49
+ config.validateCommit?.(config.commit);
50
+ const commitVars = { commit: config.commit };
51
+ const commitPrefix = expandPlaceholders(config.commitPrefix, commitVars).replace(/\/$/, '');
52
+ const sharedPrefix = expandPlaceholders(config.sharedPrefix, commitVars).replace(/\/$/, '');
53
+ return {
54
+ root: resolve(baseDir, config.root),
55
+ bucket: config.bucket,
56
+ region: config.region?.trim() || DEFAULT_REGION,
57
+ commit: config.commit,
58
+ endpoint: config.endpoint?.trim() || undefined,
59
+ forcePathStyle: Boolean(config.forcePathStyle),
60
+ commitPrefix,
61
+ sharedPrefix,
62
+ targets: config.targets,
63
+ targetIds: config.targetIds,
64
+ requiredTargetIds: config.requiredTargetIds ?? [],
65
+ };
66
+ }
67
+ export async function loadConfig(cwd = process.cwd()) {
68
+ const configPath = findConfigFile(cwd);
69
+ if (!configPath) {
70
+ throw new Error(`No static-assets.config.ts found from ${cwd}. Create one with defineStaticAssetsConfig().`);
71
+ }
72
+ const jiti = createJiti(import.meta.url);
73
+ const loaded = (await jiti.import(configPath));
74
+ const config = loaded.default ?? loaded;
75
+ return resolveStaticAssetsConfig(config, dirname(configPath));
76
+ }
77
+ //# sourceMappingURL=load-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-config.js","sourceRoot":"","sources":["../../src/config/load-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ export type VersioningTier = 'commit' | 'shared';
2
+ export interface StaticAssetTarget {
3
+ id: string;
4
+ localDir: string;
5
+ /** `{commitPrefix}` and `{sharedPrefix}` are expanded by the planner. */
6
+ remotePrefix: string;
7
+ versioning: VersioningTier;
8
+ /** Caller-supplied Cache-Control header value. */
9
+ cacheControl: string;
10
+ optional?: boolean;
11
+ include?: readonly string[];
12
+ exclude?: readonly string[];
13
+ }
14
+ export interface StaticAssetsConfig {
15
+ root: string;
16
+ bucket: string;
17
+ region?: string;
18
+ commit: string;
19
+ /** S3-compatible endpoint (R2, MinIO). Omit for AWS. */
20
+ endpoint?: string;
21
+ forcePathStyle?: boolean;
22
+ /** May include `{commit}`; expanded before remote prefixes. */
23
+ commitPrefix: string;
24
+ sharedPrefix: string;
25
+ targets: readonly StaticAssetTarget[];
26
+ targetIds?: readonly string[];
27
+ requiredTargetIds?: readonly string[];
28
+ validateCommit?: (commit: string) => void;
29
+ }
30
+ export interface ResolvedStaticAssetsConfig {
31
+ root: string;
32
+ bucket: string;
33
+ region: string;
34
+ commit: string;
35
+ endpoint?: string;
36
+ forcePathStyle: boolean;
37
+ commitPrefix: string;
38
+ sharedPrefix: string;
39
+ targets: readonly StaticAssetTarget[];
40
+ targetIds?: readonly string[];
41
+ requiredTargetIds: readonly string[];
42
+ }
43
+ export interface UploadPlanEntry {
44
+ targetId: string;
45
+ localPath: string;
46
+ remoteKey: string;
47
+ contentType: string;
48
+ cacheControl: string;
49
+ }
50
+ export interface UploadPlan {
51
+ bucket: string;
52
+ region: string;
53
+ commit: string;
54
+ entries: UploadPlanEntry[];
55
+ }
56
+ export interface UploadResult {
57
+ uploadedByTarget: Record<string, number>;
58
+ totalUploaded: number;
59
+ }
60
+ export type StaticAssetStoreClient = {
61
+ send(command: unknown): Promise<unknown>;
62
+ };
63
+ export interface StaticAssetUploadOptions {
64
+ dryRun?: boolean;
65
+ client?: StaticAssetStoreClient;
66
+ baseDir?: string;
67
+ }
68
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,cAAc,CAAC;IAC3B,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,0BAA0B;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IACzB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACjC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5C,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,sBAAsB,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ /** Recursively list all file paths under a directory. */
2
+ export declare function walkFiles(directory: string): string[];
3
+ //# sourceMappingURL=walk-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walk-files.d.ts","sourceRoot":"","sources":["../../src/fs/walk-files.ts"],"names":[],"mappings":"AAGA,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAYrD"}
@@ -0,0 +1,18 @@
1
+ import { readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ /** Recursively list all file paths under a directory. */
4
+ export function walkFiles(directory) {
5
+ const entries = readdirSync(directory, { withFileTypes: true });
6
+ const files = [];
7
+ for (const entry of entries) {
8
+ const fullPath = join(directory, entry.name);
9
+ if (entry.isDirectory()) {
10
+ files.push(...walkFiles(fullPath));
11
+ }
12
+ else if (entry.isFile()) {
13
+ files.push(fullPath);
14
+ }
15
+ }
16
+ return files;
17
+ }
18
+ //# sourceMappingURL=walk-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walk-files.js","sourceRoot":"","sources":["../../src/fs/walk-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,yDAAyD;AACzD,MAAM,UAAU,SAAS,CAAC,SAAiB;IACvC,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Match a path against simple glob patterns (`*`, `**`, `/`). */
2
+ export declare function matchesGlob(relativePath: string, pattern: string): boolean;
3
+ export declare function matchesAnyGlob(relativePath: string, patterns: readonly string[]): boolean;
4
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../src/glob/match.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAK1E;AA2BD,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAEzF"}
@@ -0,0 +1,38 @@
1
+ /** Match a path against simple glob patterns (`*`, `**`, `/`). */
2
+ export function matchesGlob(relativePath, pattern) {
3
+ const normalizedPath = relativePath.replace(/\\/g, '/');
4
+ const normalizedPattern = pattern.replace(/\\/g, '/');
5
+ const regex = globToRegExp(normalizedPattern);
6
+ return regex.test(normalizedPath);
7
+ }
8
+ function globToRegExp(pattern) {
9
+ const chars = [...pattern];
10
+ let regex = '^';
11
+ for (let index = 0; index < chars.length; index += 1) {
12
+ const char = chars[index];
13
+ if (char === '*') {
14
+ if (chars[index + 1] === '*') {
15
+ regex += '.*';
16
+ index += 1;
17
+ if (chars[index + 1] === '/') {
18
+ index += 1;
19
+ }
20
+ }
21
+ else {
22
+ regex += '[^/]*';
23
+ }
24
+ }
25
+ else if (char !== undefined && '.+^${}()|[]\\'.includes(char)) {
26
+ regex += `\\${char}`;
27
+ }
28
+ else {
29
+ regex += char;
30
+ }
31
+ }
32
+ regex += '$';
33
+ return new RegExp(regex);
34
+ }
35
+ export function matchesAnyGlob(relativePath, patterns) {
36
+ return patterns.some((pattern) => matchesGlob(relativePath, pattern));
37
+ }
38
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/glob/match.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,UAAU,WAAW,CAAC,YAAoB,EAAE,OAAe;IAC7D,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,YAAY,CAAC,OAAe;IACjC,MAAM,KAAK,GAAa,CAAC,GAAG,OAAO,CAAC,CAAC;IACrC,IAAI,KAAK,GAAG,GAAG,CAAC;IAChB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACf,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC3B,KAAK,IAAI,IAAI,CAAC;gBACd,KAAK,IAAI,CAAC,CAAC;gBACX,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBAC3B,KAAK,IAAI,CAAC,CAAC;gBACf,CAAC;YACL,CAAC;iBAAM,CAAC;gBACJ,KAAK,IAAI,OAAO,CAAC;YACrB,CAAC;QACL,CAAC;aAAM,IAAI,IAAI,KAAK,SAAS,IAAI,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,KAAK,IAAI,KAAK,IAAI,EAAE,CAAC;QACzB,CAAC;aAAM,CAAC;YACJ,KAAK,IAAI,IAAI,CAAC;QAClB,CAAC;IACL,CAAC;IACD,KAAK,IAAI,GAAG,CAAC;IACb,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,YAAoB,EAAE,QAA2B;IAC5E,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { defineStaticAssetsConfig, loadConfig, resolveStaticAssetsConfig } from './config/index.js';
2
+ export type { ResolvedStaticAssetsConfig, StaticAssetStoreClient, StaticAssetTarget, StaticAssetUploadOptions, StaticAssetsConfig, UploadPlan, UploadPlanEntry, UploadResult, VersioningTier, } from './config/index.js';
3
+ export { assertRequiredTargets, resolveUploadPlan } from './plan/resolve-plan.js';
4
+ export { runStaticAssetUpload } from './upload/run-upload.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AACpG,YAAY,EACR,0BAA0B,EAC1B,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,YAAY,EACZ,cAAc,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { defineStaticAssetsConfig, loadConfig, resolveStaticAssetsConfig } from './config/index.js';
2
+ export { assertRequiredTargets, resolveUploadPlan } from './plan/resolve-plan.js';
3
+ export { runStaticAssetUpload } from './upload/run-upload.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAYpG,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function contentTypeForFileName(fileName: string): string;
2
+ //# sourceMappingURL=content-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-type.d.ts","sourceRoot":"","sources":["../../src/mime/content-type.ts"],"names":[],"mappings":"AAEA,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE/D"}
@@ -0,0 +1,5 @@
1
+ import { lookup as lookupMimeType } from 'mime-types';
2
+ export function contentTypeForFileName(fileName) {
3
+ return lookupMimeType(fileName) || 'application/octet-stream';
4
+ }
5
+ //# sourceMappingURL=content-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-type.js","sourceRoot":"","sources":["../../src/mime/content-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACnD,OAAO,cAAc,CAAC,QAAQ,CAAC,IAAI,0BAA0B,CAAC;AAClE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { StaticAssetsConfig, UploadPlan } from '../config/types.js';
2
+ export declare function resolveUploadPlan(config: StaticAssetsConfig, baseDir?: string): UploadPlan;
3
+ export declare function assertRequiredTargets(plan: UploadPlan, config: StaticAssetsConfig): void;
4
+ //# sourceMappingURL=resolve-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-plan.d.ts","sourceRoot":"","sources":["../../src/plan/resolve-plan.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGR,kBAAkB,EAClB,UAAU,EAEb,MAAM,oBAAoB,CAAC;AAoD5B,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,GAAE,MAAsB,GAAG,UAAU,CAiBzG;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAYxF"}
@@ -0,0 +1,74 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { basename, relative, resolve } from 'node:path';
3
+ import { expandPlaceholders, resolveStaticAssetsConfig } from '../config/load-config.js';
4
+ import { walkFiles } from '../fs/walk-files.js';
5
+ import { matchesAnyGlob } from '../glob/match.js';
6
+ import { contentTypeForFileName } from '../mime/content-type.js';
7
+ function shouldIncludeFile(relativePath, target) {
8
+ if (target.exclude?.length && matchesAnyGlob(relativePath, target.exclude)) {
9
+ return false;
10
+ }
11
+ if (target.include?.length) {
12
+ return matchesAnyGlob(relativePath, target.include);
13
+ }
14
+ return true;
15
+ }
16
+ function resolveTargetEntries(config, target) {
17
+ const localDirectory = resolve(config.root, target.localDir);
18
+ if (!existsSync(localDirectory)) {
19
+ if (target.optional) {
20
+ return [];
21
+ }
22
+ throw new Error(`Missing required directory: ${localDirectory}`);
23
+ }
24
+ const remotePrefix = expandPlaceholders(target.remotePrefix, {
25
+ commit: config.commit,
26
+ commitPrefix: config.commitPrefix,
27
+ sharedPrefix: config.sharedPrefix,
28
+ }).replace(/\/$/, '');
29
+ const entries = [];
30
+ for (const filePath of walkFiles(localDirectory)) {
31
+ const relativePath = relative(localDirectory, filePath).split('\\').join('/');
32
+ if (!shouldIncludeFile(relativePath, target)) {
33
+ continue;
34
+ }
35
+ entries.push({
36
+ targetId: target.id,
37
+ localPath: filePath,
38
+ remoteKey: `${remotePrefix}/${relativePath}`,
39
+ contentType: contentTypeForFileName(basename(relativePath)),
40
+ cacheControl: target.cacheControl,
41
+ });
42
+ }
43
+ return entries;
44
+ }
45
+ export function resolveUploadPlan(config, baseDir = process.cwd()) {
46
+ const resolved = resolveStaticAssetsConfig(config, baseDir);
47
+ const entries = [];
48
+ for (const target of resolved.targets) {
49
+ if (resolved.targetIds && !resolved.targetIds.includes(target.id)) {
50
+ continue;
51
+ }
52
+ entries.push(...resolveTargetEntries(resolved, target));
53
+ }
54
+ return {
55
+ bucket: resolved.bucket,
56
+ region: resolved.region,
57
+ commit: resolved.commit,
58
+ entries,
59
+ };
60
+ }
61
+ export function assertRequiredTargets(plan, config) {
62
+ const requiredTargetIds = config.requiredTargetIds ?? [];
63
+ const knownIds = new Set(config.targets.map((target) => target.id));
64
+ for (const targetId of requiredTargetIds) {
65
+ if (!knownIds.has(targetId)) {
66
+ throw new Error(`Unknown required upload target: ${targetId}`);
67
+ }
68
+ const count = plan.entries.filter((entry) => entry.targetId === targetId).length;
69
+ if (count === 0) {
70
+ throw new Error(`Required upload target "${targetId}" produced no files`);
71
+ }
72
+ }
73
+ }
74
+ //# sourceMappingURL=resolve-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-plan.js","sourceRoot":"","sources":["../../src/plan/resolve-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { StaticAssetUploadOptions, StaticAssetsConfig, UploadResult } from '../config/types.js';
2
+ export declare function runStaticAssetUpload(config: StaticAssetsConfig, options?: StaticAssetUploadOptions): Promise<UploadResult>;
3
+ //# sourceMappingURL=run-upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-upload.d.ts","sourceRoot":"","sources":["../../src/upload/run-upload.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAER,wBAAwB,EACxB,kBAAkB,EAElB,YAAY,EACf,MAAM,oBAAoB,CAAC;AA2B5B,wBAAsB,oBAAoB,CACtC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,GAAE,wBAA6B,GACvC,OAAO,CAAC,YAAY,CAAC,CAsBvB"}
@@ -0,0 +1,44 @@
1
+ import { S3Client } from '@aws-sdk/client-s3';
2
+ import { cliLogger } from '@kristijorgji/cli-kit';
3
+ import { resolveStaticAssetsConfig } from '../config/load-config.js';
4
+ import { assertRequiredTargets, resolveUploadPlan } from '../plan/resolve-plan.js';
5
+ import { S3UploadProvider } from './s3-provider.js';
6
+ function createS3Client(config) {
7
+ return new S3Client({
8
+ region: config.region,
9
+ ...(config.endpoint ? { endpoint: config.endpoint } : {}),
10
+ ...(config.forcePathStyle ? { forcePathStyle: true } : {}),
11
+ });
12
+ }
13
+ function logDryRunPlan(plan) {
14
+ cliLogger.info(`Dry run — ${plan.entries.length} files would upload to s3://${plan.bucket}/`);
15
+ for (const entry of plan.entries) {
16
+ cliLogger.info(` [${entry.targetId}] ${entry.remoteKey} (${entry.contentType}, ${entry.cacheControl})`);
17
+ }
18
+ }
19
+ function logUploadSummary(result) {
20
+ for (const [targetId, count] of Object.entries(result.uploadedByTarget)) {
21
+ cliLogger.info(`Uploaded ${count} files for target "${targetId}"`);
22
+ }
23
+ cliLogger.info(`Uploaded ${result.totalUploaded} files total`);
24
+ }
25
+ export async function runStaticAssetUpload(config, options = {}) {
26
+ const baseDir = options.baseDir ?? process.cwd();
27
+ const resolved = resolveStaticAssetsConfig(config, baseDir);
28
+ const plan = resolveUploadPlan(resolved, baseDir);
29
+ assertRequiredTargets(plan, resolved);
30
+ if (plan.entries.length === 0) {
31
+ cliLogger.warn('Upload plan is empty — no files matched manifest targets');
32
+ }
33
+ const dryRun = Boolean(options.dryRun);
34
+ if (dryRun) {
35
+ logDryRunPlan(plan);
36
+ return { uploadedByTarget: {}, totalUploaded: 0 };
37
+ }
38
+ cliLogger.info(`Uploading static assets to s3://${plan.bucket}/ (commit ${plan.commit})`);
39
+ const client = options.client ?? createS3Client(resolved);
40
+ const result = await new S3UploadProvider(client).upload(plan, { dryRun: false });
41
+ logUploadSummary(result);
42
+ return result;
43
+ }
44
+ //# sourceMappingURL=run-upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-upload.js","sourceRoot":"","sources":["../../src/upload/run-upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { StaticAssetStoreClient, UploadPlan, UploadResult } from '../config/types.js';
2
+ export declare class S3UploadProvider {
3
+ private readonly client;
4
+ constructor(client: StaticAssetStoreClient);
5
+ upload(plan: UploadPlan, options: {
6
+ dryRun: boolean;
7
+ }): Promise<UploadResult>;
8
+ }
9
+ //# sourceMappingURL=s3-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-provider.d.ts","sourceRoot":"","sources":["../../src/upload/s3-provider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE3F,qBAAa,gBAAgB;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,sBAAsB;IAErD,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;CAuBtF"}
@@ -0,0 +1,26 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { PutObjectCommand } from '@aws-sdk/client-s3';
3
+ export class S3UploadProvider {
4
+ client;
5
+ constructor(client) {
6
+ this.client = client;
7
+ }
8
+ async upload(plan, options) {
9
+ const uploadedByTarget = {};
10
+ for (const entry of plan.entries) {
11
+ uploadedByTarget[entry.targetId] = (uploadedByTarget[entry.targetId] ?? 0) + 1;
12
+ if (options.dryRun) {
13
+ continue;
14
+ }
15
+ await this.client.send(new PutObjectCommand({
16
+ Bucket: plan.bucket,
17
+ Key: entry.remoteKey,
18
+ Body: readFileSync(entry.localPath),
19
+ ContentType: entry.contentType,
20
+ CacheControl: entry.cacheControl,
21
+ }));
22
+ }
23
+ return { uploadedByTarget, totalUploaded: plan.entries.length };
24
+ }
25
+ }
26
+ //# sourceMappingURL=s3-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-provider.js","sourceRoot":"","sources":["../../src/upload/s3-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAItD,MAAM,OAAO,gBAAgB;IACI;IAA7B,YAA6B,MAA8B;QAA9B,WAAM,GAAN,MAAM,CAAwB;IAAG,CAAC;IAE/D,KAAK,CAAC,MAAM,CAAC,IAAgB,EAAE,OAA4B;QACvD,MAAM,gBAAgB,GAA2B,EAAE,CAAC;QAEpD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAE/E,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjB,SAAS;YACb,CAAC;YAED,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAClB,IAAI,gBAAgB,CAAC;gBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,EAAE,KAAK,CAAC,SAAS;gBACpB,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC;gBACnC,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;aACnC,CAAC,CACL,CAAC;QACN,CAAC;QAED,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;IACpE,CAAC;CACJ"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@kristijorgji/static-asset-upload",
3
+ "version": "0.1.0",
4
+ "description": "Framework-agnostic manifest uploader for static assets to S3-compatible object storage",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "kristijorgji",
8
+ "engines": {
9
+ "node": ">=22.16.0"
10
+ },
11
+ "bin": {
12
+ "kj-static-assets": "./dist/cli.js"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "provenance": true
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/kristijorgji/js-devkit.git",
21
+ "directory": "packages/static-asset-upload"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "skills",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js"
33
+ },
34
+ "./config": {
35
+ "types": "./dist/config/index.d.ts",
36
+ "import": "./dist/config/index.js"
37
+ }
38
+ },
39
+ "types": "./dist/index.d.ts",
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.json",
42
+ "typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
43
+ "test": "vitest run",
44
+ "test:watch": "vitest"
45
+ },
46
+ "dependencies": {
47
+ "@aws-sdk/client-s3": "^3",
48
+ "@kristijorgji/cli-kit": "workspace:^",
49
+ "commander": "^15",
50
+ "jiti": "^2",
51
+ "mime-types": "^2"
52
+ },
53
+ "devDependencies": {
54
+ "@types/mime-types": "^2",
55
+ "@types/node": "^26",
56
+ "typescript": "^5",
57
+ "vitest": "^5"
58
+ }
59
+ }
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: static-asset-upload
3
+ description: >-
4
+ Use when uploading hashed or shared static files to S3-compatible storage
5
+ from a caller-supplied manifest, or wiring kj-static-assets into a new project.
6
+ ---
7
+
8
+ # static-asset-upload
9
+
10
+ CLI: `kj-static-assets` from `@kristijorgji/static-asset-upload`.
11
+
12
+ ## Commands
13
+
14
+ | Command | Flags | When |
15
+ | --- | --- | --- |
16
+ | `upload` | `--dry-run` | Put planned objects, or print the plan |
17
+
18
+ ## Config
19
+
20
+ `static-assets.config.ts` via `defineStaticAssetsConfig({ root, bucket, commit, commitPrefix, sharedPrefix, targets, ... })`.
21
+
22
+ Keep app-specific CDN prefixes, env names, and cache lifetimes in the consumer config. Do not hardcode them in this package.
23
+
24
+ Example prefixes: `commitPrefix: 'assets/{commit}'`, `sharedPrefix: 'assets/shared'`.
25
+
26
+ Each target supplies `cacheControl` as a header string. There is no package-level 1y/3h enum.
27
+
28
+ `runStaticAssetUpload` builds the S3 client from `region` / `endpoint` / `forcePathStyle`. Inject `{ client: { send } }` in tests. No live AWS.
29
+
30
+ ## Out of scope
31
+
32
+ Prune, CloudFront invalidation, and extra storage backends. An S3-compatible `endpoint` is enough for R2 and MinIO.