@openworkers/adapter-static 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.
- package/README.md +113 -0
- package/bin/cli.js +77 -0
- package/files/worker.js +549 -0
- package/index.d.ts +42 -0
- package/index.js +213 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# @openworkers/adapter-static
|
|
2
|
+
|
|
3
|
+
Static site adapter for OpenWorkers. Converts any static site into a deployable worker with optimized asset serving.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add -g @openworkers/adapter-static
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Auto-detect input folder and generate worker
|
|
15
|
+
adapter-static
|
|
16
|
+
|
|
17
|
+
# Specify input and output directories
|
|
18
|
+
adapter-static ./build -o ./dist
|
|
19
|
+
|
|
20
|
+
# Custom 404 page
|
|
21
|
+
adapter-static --fallback /404.html
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## CLI Options
|
|
25
|
+
|
|
26
|
+
| Option | Flag | Default | Description |
|
|
27
|
+
| --------- | ---------------- | ------------------ | --------------------------------------------------- |
|
|
28
|
+
| Input | positional | auto-detect | Source directory (`dist`, `build`, `out`, `public`) |
|
|
29
|
+
| Output | `-o, --out` | `dist-openworkers` | Output directory |
|
|
30
|
+
| Mode | `-m, --mode` | auto-detect | Routing mode: `directory` or `flat` |
|
|
31
|
+
| Fallback | `-f, --fallback` | none | Fallback file for unmatched routes |
|
|
32
|
+
| Immutable | `--immutable` | auto-detect | Comma-separated immutable path patterns |
|
|
33
|
+
|
|
34
|
+
## Programmatic Usage
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import { adapt } from '@openworkers/adapter-static';
|
|
38
|
+
|
|
39
|
+
await adapt({
|
|
40
|
+
input: 'build',
|
|
41
|
+
out: 'dist',
|
|
42
|
+
mode: 'flat',
|
|
43
|
+
fallback: '/404.html'
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Output Structure
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
dist/
|
|
51
|
+
├── worker.js # Worker serving files via ASSETS binding
|
|
52
|
+
├── assets/ # Static files
|
|
53
|
+
└── routes.js # Route manifest
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Routing Modes
|
|
57
|
+
|
|
58
|
+
The adapter auto-detects the routing mode based on your file structure.
|
|
59
|
+
|
|
60
|
+
| Mode | URL | File |
|
|
61
|
+
| ------------- | -------- | ------------------- |
|
|
62
|
+
| **Directory** | `/about` | `/about/index.html` |
|
|
63
|
+
| **Flat** | `/about` | `/about.html` |
|
|
64
|
+
|
|
65
|
+
Directory mode is used by most static generators. Flat mode is common with SvelteKit static adapter.
|
|
66
|
+
|
|
67
|
+
## Immutable Assets
|
|
68
|
+
|
|
69
|
+
Assets with hashed filenames are served with long cache headers (`max-age=31536000, immutable`).
|
|
70
|
+
|
|
71
|
+
Auto-detected patterns:
|
|
72
|
+
|
|
73
|
+
- `/_app/immutable/*` — SvelteKit
|
|
74
|
+
- `/assets/*` — Vite
|
|
75
|
+
- `/_next/static/*` — Next.js
|
|
76
|
+
- `/_astro/*` — Astro
|
|
77
|
+
|
|
78
|
+
## Deploy to OpenWorkers
|
|
79
|
+
|
|
80
|
+
**Quick deploy** (existing worker):
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
ow workers upload my-site ./dist
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Full setup**:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# 1. Create storage for assets
|
|
90
|
+
ow storage create my-site-assets --provider platform
|
|
91
|
+
|
|
92
|
+
# 2. Create environment
|
|
93
|
+
ow env create my-site-env
|
|
94
|
+
|
|
95
|
+
# 3. Bind storage to environment as ASSETS
|
|
96
|
+
ow env bind my-site-env ASSETS my-site-assets -t assets
|
|
97
|
+
|
|
98
|
+
# 4. Create worker
|
|
99
|
+
ow workers create my-site
|
|
100
|
+
|
|
101
|
+
# 5. Link environment to worker
|
|
102
|
+
ow workers link my-site my-site-env
|
|
103
|
+
|
|
104
|
+
# 6. Build and upload
|
|
105
|
+
adapter-static ./build -o ./dist
|
|
106
|
+
ow workers upload my-site ./dist
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Your site is live at `https://my-site.workers.rocks`
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { adapt } from '../index.js';
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
|
|
7
|
+
/** @type {import('../index.js').AdapterOptions} */
|
|
8
|
+
const options = {};
|
|
9
|
+
|
|
10
|
+
for (let i = 0; i < args.length; i++) {
|
|
11
|
+
const arg = args[i];
|
|
12
|
+
|
|
13
|
+
if (arg === '--input' || arg === '-i') {
|
|
14
|
+
options.input = args[++i];
|
|
15
|
+
} else if (arg === '--out' || arg === '-o') {
|
|
16
|
+
options.out = args[++i];
|
|
17
|
+
} else if (arg === '--mode' || arg === '-m') {
|
|
18
|
+
const mode = args[++i];
|
|
19
|
+
|
|
20
|
+
if (mode !== 'directory' && mode !== 'flat') {
|
|
21
|
+
console.error(`Invalid mode: ${mode}. Must be 'directory' or 'flat'.`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
options.mode = mode;
|
|
26
|
+
} else if (arg === '--fallback' || arg === '-f') {
|
|
27
|
+
options.fallback = args[++i];
|
|
28
|
+
} else if (arg === '--immutable') {
|
|
29
|
+
options.immutable = args[++i].split(',');
|
|
30
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
31
|
+
printHelp();
|
|
32
|
+
process.exit(0);
|
|
33
|
+
} else if (arg === '--version' || arg === '-v') {
|
|
34
|
+
const pkg = await import('../package.json', { with: { type: 'json' } });
|
|
35
|
+
console.log(pkg.default.version);
|
|
36
|
+
process.exit(0);
|
|
37
|
+
} else if (!arg.startsWith('-')) {
|
|
38
|
+
// Positional argument = input directory
|
|
39
|
+
options.input = arg;
|
|
40
|
+
} else {
|
|
41
|
+
console.error(`Unknown option: ${arg}`);
|
|
42
|
+
printHelp();
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await adapt(options);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function printHelp() {
|
|
55
|
+
console.log(`
|
|
56
|
+
Usage: adapter-static [input] [options]
|
|
57
|
+
|
|
58
|
+
Build a static site for OpenWorkers.
|
|
59
|
+
|
|
60
|
+
Arguments:
|
|
61
|
+
input Input directory (default: dist, build, out, or public)
|
|
62
|
+
|
|
63
|
+
Options:
|
|
64
|
+
-o, --out <dir> Output directory (default: dist-openworkers)
|
|
65
|
+
-m, --mode <mode> Routing mode: 'directory' or 'flat' (default: auto-detect)
|
|
66
|
+
-f, --fallback <f> SPA fallback file (e.g., /index.html or /200.html)
|
|
67
|
+
--immutable <p> Comma-separated immutable patterns (e.g., /assets/*,/_app/*)
|
|
68
|
+
-h, --help Show this help message
|
|
69
|
+
-v, --version Show version
|
|
70
|
+
|
|
71
|
+
Examples:
|
|
72
|
+
adapter-static # Auto-detect input, output to dist-openworkers
|
|
73
|
+
adapter-static dist -o out # Build dist/ to out/
|
|
74
|
+
adapter-static --fallback /index.html # Enable SPA mode
|
|
75
|
+
adapter-static --mode flat # Use flat routing (/page -> /page.html)
|
|
76
|
+
`);
|
|
77
|
+
}
|
package/files/worker.js
ADDED
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
// node_modules/mime/dist/types/standard.js
|
|
2
|
+
var types = {
|
|
3
|
+
"application/andrew-inset": ["ez"],
|
|
4
|
+
"application/appinstaller": ["appinstaller"],
|
|
5
|
+
"application/applixware": ["aw"],
|
|
6
|
+
"application/appx": ["appx"],
|
|
7
|
+
"application/appxbundle": ["appxbundle"],
|
|
8
|
+
"application/atom+xml": ["atom"],
|
|
9
|
+
"application/atomcat+xml": ["atomcat"],
|
|
10
|
+
"application/atomdeleted+xml": ["atomdeleted"],
|
|
11
|
+
"application/atomsvc+xml": ["atomsvc"],
|
|
12
|
+
"application/atsc-dwd+xml": ["dwd"],
|
|
13
|
+
"application/atsc-held+xml": ["held"],
|
|
14
|
+
"application/atsc-rsat+xml": ["rsat"],
|
|
15
|
+
"application/automationml-aml+xml": ["aml"],
|
|
16
|
+
"application/automationml-amlx+zip": ["amlx"],
|
|
17
|
+
"application/bdoc": ["bdoc"],
|
|
18
|
+
"application/calendar+xml": ["xcs"],
|
|
19
|
+
"application/ccxml+xml": ["ccxml"],
|
|
20
|
+
"application/cdfx+xml": ["cdfx"],
|
|
21
|
+
"application/cdmi-capability": ["cdmia"],
|
|
22
|
+
"application/cdmi-container": ["cdmic"],
|
|
23
|
+
"application/cdmi-domain": ["cdmid"],
|
|
24
|
+
"application/cdmi-object": ["cdmio"],
|
|
25
|
+
"application/cdmi-queue": ["cdmiq"],
|
|
26
|
+
"application/cpl+xml": ["cpl"],
|
|
27
|
+
"application/cu-seeme": ["cu"],
|
|
28
|
+
"application/cwl": ["cwl"],
|
|
29
|
+
"application/dash+xml": ["mpd"],
|
|
30
|
+
"application/dash-patch+xml": ["mpp"],
|
|
31
|
+
"application/davmount+xml": ["davmount"],
|
|
32
|
+
"application/dicom": ["dcm"],
|
|
33
|
+
"application/docbook+xml": ["dbk"],
|
|
34
|
+
"application/dssc+der": ["dssc"],
|
|
35
|
+
"application/dssc+xml": ["xdssc"],
|
|
36
|
+
"application/ecmascript": ["ecma"],
|
|
37
|
+
"application/emma+xml": ["emma"],
|
|
38
|
+
"application/emotionml+xml": ["emotionml"],
|
|
39
|
+
"application/epub+zip": ["epub"],
|
|
40
|
+
"application/exi": ["exi"],
|
|
41
|
+
"application/express": ["exp"],
|
|
42
|
+
"application/fdf": ["fdf"],
|
|
43
|
+
"application/fdt+xml": ["fdt"],
|
|
44
|
+
"application/font-tdpfr": ["pfr"],
|
|
45
|
+
"application/geo+json": ["geojson"],
|
|
46
|
+
"application/gml+xml": ["gml"],
|
|
47
|
+
"application/gpx+xml": ["gpx"],
|
|
48
|
+
"application/gxf": ["gxf"],
|
|
49
|
+
"application/gzip": ["gz"],
|
|
50
|
+
"application/hjson": ["hjson"],
|
|
51
|
+
"application/hyperstudio": ["stk"],
|
|
52
|
+
"application/inkml+xml": ["ink", "inkml"],
|
|
53
|
+
"application/ipfix": ["ipfix"],
|
|
54
|
+
"application/its+xml": ["its"],
|
|
55
|
+
"application/java-archive": ["jar", "war", "ear"],
|
|
56
|
+
"application/java-serialized-object": ["ser"],
|
|
57
|
+
"application/java-vm": ["class"],
|
|
58
|
+
"application/javascript": ["*js"],
|
|
59
|
+
"application/json": ["json", "map"],
|
|
60
|
+
"application/json5": ["json5"],
|
|
61
|
+
"application/jsonml+json": ["jsonml"],
|
|
62
|
+
"application/ld+json": ["jsonld"],
|
|
63
|
+
"application/lgr+xml": ["lgr"],
|
|
64
|
+
"application/lost+xml": ["lostxml"],
|
|
65
|
+
"application/mac-binhex40": ["hqx"],
|
|
66
|
+
"application/mac-compactpro": ["cpt"],
|
|
67
|
+
"application/mads+xml": ["mads"],
|
|
68
|
+
"application/manifest+json": ["webmanifest"],
|
|
69
|
+
"application/marc": ["mrc"],
|
|
70
|
+
"application/marcxml+xml": ["mrcx"],
|
|
71
|
+
"application/mathematica": ["ma", "nb", "mb"],
|
|
72
|
+
"application/mathml+xml": ["mathml"],
|
|
73
|
+
"application/mbox": ["mbox"],
|
|
74
|
+
"application/media-policy-dataset+xml": ["mpf"],
|
|
75
|
+
"application/mediaservercontrol+xml": ["mscml"],
|
|
76
|
+
"application/metalink+xml": ["metalink"],
|
|
77
|
+
"application/metalink4+xml": ["meta4"],
|
|
78
|
+
"application/mets+xml": ["mets"],
|
|
79
|
+
"application/mmt-aei+xml": ["maei"],
|
|
80
|
+
"application/mmt-usd+xml": ["musd"],
|
|
81
|
+
"application/mods+xml": ["mods"],
|
|
82
|
+
"application/mp21": ["m21", "mp21"],
|
|
83
|
+
"application/mp4": ["*mp4", "*mpg4", "mp4s", "m4p"],
|
|
84
|
+
"application/msix": ["msix"],
|
|
85
|
+
"application/msixbundle": ["msixbundle"],
|
|
86
|
+
"application/msword": ["doc", "dot"],
|
|
87
|
+
"application/mxf": ["mxf"],
|
|
88
|
+
"application/n-quads": ["nq"],
|
|
89
|
+
"application/n-triples": ["nt"],
|
|
90
|
+
"application/node": ["cjs"],
|
|
91
|
+
"application/octet-stream": [
|
|
92
|
+
"bin",
|
|
93
|
+
"dms",
|
|
94
|
+
"lrf",
|
|
95
|
+
"mar",
|
|
96
|
+
"so",
|
|
97
|
+
"dist",
|
|
98
|
+
"distz",
|
|
99
|
+
"pkg",
|
|
100
|
+
"bpk",
|
|
101
|
+
"dump",
|
|
102
|
+
"elc",
|
|
103
|
+
"deploy",
|
|
104
|
+
"exe",
|
|
105
|
+
"dll",
|
|
106
|
+
"deb",
|
|
107
|
+
"dmg",
|
|
108
|
+
"iso",
|
|
109
|
+
"img",
|
|
110
|
+
"msi",
|
|
111
|
+
"msp",
|
|
112
|
+
"msm",
|
|
113
|
+
"buffer"
|
|
114
|
+
],
|
|
115
|
+
"application/oda": ["oda"],
|
|
116
|
+
"application/oebps-package+xml": ["opf"],
|
|
117
|
+
"application/ogg": ["ogx"],
|
|
118
|
+
"application/omdoc+xml": ["omdoc"],
|
|
119
|
+
"application/onenote": [
|
|
120
|
+
"onetoc",
|
|
121
|
+
"onetoc2",
|
|
122
|
+
"onetmp",
|
|
123
|
+
"onepkg",
|
|
124
|
+
"one",
|
|
125
|
+
"onea"
|
|
126
|
+
],
|
|
127
|
+
"application/oxps": ["oxps"],
|
|
128
|
+
"application/p2p-overlay+xml": ["relo"],
|
|
129
|
+
"application/patch-ops-error+xml": ["xer"],
|
|
130
|
+
"application/pdf": ["pdf"],
|
|
131
|
+
"application/pgp-encrypted": ["pgp"],
|
|
132
|
+
"application/pgp-keys": ["asc"],
|
|
133
|
+
"application/pgp-signature": ["sig", "*asc"],
|
|
134
|
+
"application/pics-rules": ["prf"],
|
|
135
|
+
"application/pkcs10": ["p10"],
|
|
136
|
+
"application/pkcs7-mime": ["p7m", "p7c"],
|
|
137
|
+
"application/pkcs7-signature": ["p7s"],
|
|
138
|
+
"application/pkcs8": ["p8"],
|
|
139
|
+
"application/pkix-attr-cert": ["ac"],
|
|
140
|
+
"application/pkix-cert": ["cer"],
|
|
141
|
+
"application/pkix-crl": ["crl"],
|
|
142
|
+
"application/pkix-pkipath": ["pkipath"],
|
|
143
|
+
"application/pkixcmp": ["pki"],
|
|
144
|
+
"application/pls+xml": ["pls"],
|
|
145
|
+
"application/postscript": ["ai", "eps", "ps"],
|
|
146
|
+
"application/provenance+xml": ["provx"],
|
|
147
|
+
"application/pskc+xml": ["pskcxml"],
|
|
148
|
+
"application/raml+yaml": ["raml"],
|
|
149
|
+
"application/rdf+xml": ["rdf", "owl"],
|
|
150
|
+
"application/reginfo+xml": ["rif"],
|
|
151
|
+
"application/relax-ng-compact-syntax": ["rnc"],
|
|
152
|
+
"application/resource-lists+xml": ["rl"],
|
|
153
|
+
"application/resource-lists-diff+xml": ["rld"],
|
|
154
|
+
"application/rls-services+xml": ["rs"],
|
|
155
|
+
"application/route-apd+xml": ["rapd"],
|
|
156
|
+
"application/route-s-tsid+xml": ["sls"],
|
|
157
|
+
"application/route-usd+xml": ["rusd"],
|
|
158
|
+
"application/rpki-ghostbusters": ["gbr"],
|
|
159
|
+
"application/rpki-manifest": ["mft"],
|
|
160
|
+
"application/rpki-roa": ["roa"],
|
|
161
|
+
"application/rsd+xml": ["rsd"],
|
|
162
|
+
"application/rss+xml": ["rss"],
|
|
163
|
+
"application/rtf": ["rtf"],
|
|
164
|
+
"application/sbml+xml": ["sbml"],
|
|
165
|
+
"application/scvp-cv-request": ["scq"],
|
|
166
|
+
"application/scvp-cv-response": ["scs"],
|
|
167
|
+
"application/scvp-vp-request": ["spq"],
|
|
168
|
+
"application/scvp-vp-response": ["spp"],
|
|
169
|
+
"application/sdp": ["sdp"],
|
|
170
|
+
"application/senml+xml": ["senmlx"],
|
|
171
|
+
"application/sensml+xml": ["sensmlx"],
|
|
172
|
+
"application/set-payment-initiation": ["setpay"],
|
|
173
|
+
"application/set-registration-initiation": ["setreg"],
|
|
174
|
+
"application/shf+xml": ["shf"],
|
|
175
|
+
"application/sieve": ["siv", "sieve"],
|
|
176
|
+
"application/smil+xml": ["smi", "smil"],
|
|
177
|
+
"application/sparql-query": ["rq"],
|
|
178
|
+
"application/sparql-results+xml": ["srx"],
|
|
179
|
+
"application/sql": ["sql"],
|
|
180
|
+
"application/srgs": ["gram"],
|
|
181
|
+
"application/srgs+xml": ["grxml"],
|
|
182
|
+
"application/sru+xml": ["sru"],
|
|
183
|
+
"application/ssdl+xml": ["ssdl"],
|
|
184
|
+
"application/ssml+xml": ["ssml"],
|
|
185
|
+
"application/swid+xml": ["swidtag"],
|
|
186
|
+
"application/tei+xml": ["tei", "teicorpus"],
|
|
187
|
+
"application/thraud+xml": ["tfi"],
|
|
188
|
+
"application/timestamped-data": ["tsd"],
|
|
189
|
+
"application/toml": ["toml"],
|
|
190
|
+
"application/trig": ["trig"],
|
|
191
|
+
"application/ttml+xml": ["ttml"],
|
|
192
|
+
"application/ubjson": ["ubj"],
|
|
193
|
+
"application/urc-ressheet+xml": ["rsheet"],
|
|
194
|
+
"application/urc-targetdesc+xml": ["td"],
|
|
195
|
+
"application/voicexml+xml": ["vxml"],
|
|
196
|
+
"application/wasm": ["wasm"],
|
|
197
|
+
"application/watcherinfo+xml": ["wif"],
|
|
198
|
+
"application/widget": ["wgt"],
|
|
199
|
+
"application/winhlp": ["hlp"],
|
|
200
|
+
"application/wsdl+xml": ["wsdl"],
|
|
201
|
+
"application/wspolicy+xml": ["wspolicy"],
|
|
202
|
+
"application/xaml+xml": ["xaml"],
|
|
203
|
+
"application/xcap-att+xml": ["xav"],
|
|
204
|
+
"application/xcap-caps+xml": ["xca"],
|
|
205
|
+
"application/xcap-diff+xml": ["xdf"],
|
|
206
|
+
"application/xcap-el+xml": ["xel"],
|
|
207
|
+
"application/xcap-ns+xml": ["xns"],
|
|
208
|
+
"application/xenc+xml": ["xenc"],
|
|
209
|
+
"application/xfdf": ["xfdf"],
|
|
210
|
+
"application/xhtml+xml": ["xhtml", "xht"],
|
|
211
|
+
"application/xliff+xml": ["xlf"],
|
|
212
|
+
"application/xml": ["xml", "xsl", "xsd", "rng"],
|
|
213
|
+
"application/xml-dtd": ["dtd"],
|
|
214
|
+
"application/xop+xml": ["xop"],
|
|
215
|
+
"application/xproc+xml": ["xpl"],
|
|
216
|
+
"application/xslt+xml": ["*xsl", "xslt"],
|
|
217
|
+
"application/xspf+xml": ["xspf"],
|
|
218
|
+
"application/xv+xml": ["mxml", "xhvml", "xvml", "xvm"],
|
|
219
|
+
"application/yang": ["yang"],
|
|
220
|
+
"application/yin+xml": ["yin"],
|
|
221
|
+
"application/zip": ["zip"],
|
|
222
|
+
"application/zip+dotlottie": ["lottie"],
|
|
223
|
+
"audio/3gpp": ["*3gpp"],
|
|
224
|
+
"audio/aac": ["adts", "aac"],
|
|
225
|
+
"audio/adpcm": ["adp"],
|
|
226
|
+
"audio/amr": ["amr"],
|
|
227
|
+
"audio/basic": ["au", "snd"],
|
|
228
|
+
"audio/midi": ["mid", "midi", "kar", "rmi"],
|
|
229
|
+
"audio/mobile-xmf": ["mxmf"],
|
|
230
|
+
"audio/mp3": ["*mp3"],
|
|
231
|
+
"audio/mp4": ["m4a", "mp4a", "m4b"],
|
|
232
|
+
"audio/mpeg": ["mpga", "mp2", "mp2a", "mp3", "m2a", "m3a"],
|
|
233
|
+
"audio/ogg": ["oga", "ogg", "spx", "opus"],
|
|
234
|
+
"audio/s3m": ["s3m"],
|
|
235
|
+
"audio/silk": ["sil"],
|
|
236
|
+
"audio/wav": ["wav"],
|
|
237
|
+
"audio/wave": ["*wav"],
|
|
238
|
+
"audio/webm": ["weba"],
|
|
239
|
+
"audio/xm": ["xm"],
|
|
240
|
+
"font/collection": ["ttc"],
|
|
241
|
+
"font/otf": ["otf"],
|
|
242
|
+
"font/ttf": ["ttf"],
|
|
243
|
+
"font/woff": ["woff"],
|
|
244
|
+
"font/woff2": ["woff2"],
|
|
245
|
+
"image/aces": ["exr"],
|
|
246
|
+
"image/apng": ["apng"],
|
|
247
|
+
"image/avci": ["avci"],
|
|
248
|
+
"image/avcs": ["avcs"],
|
|
249
|
+
"image/avif": ["avif"],
|
|
250
|
+
"image/bmp": ["bmp", "dib"],
|
|
251
|
+
"image/cgm": ["cgm"],
|
|
252
|
+
"image/dicom-rle": ["drle"],
|
|
253
|
+
"image/dpx": ["dpx"],
|
|
254
|
+
"image/emf": ["emf"],
|
|
255
|
+
"image/fits": ["fits"],
|
|
256
|
+
"image/g3fax": ["g3"],
|
|
257
|
+
"image/gif": ["gif"],
|
|
258
|
+
"image/heic": ["heic"],
|
|
259
|
+
"image/heic-sequence": ["heics"],
|
|
260
|
+
"image/heif": ["heif"],
|
|
261
|
+
"image/heif-sequence": ["heifs"],
|
|
262
|
+
"image/hej2k": ["hej2"],
|
|
263
|
+
"image/ief": ["ief"],
|
|
264
|
+
"image/jaii": ["jaii"],
|
|
265
|
+
"image/jais": ["jais"],
|
|
266
|
+
"image/jls": ["jls"],
|
|
267
|
+
"image/jp2": ["jp2", "jpg2"],
|
|
268
|
+
"image/jpeg": ["jpg", "jpeg", "jpe"],
|
|
269
|
+
"image/jph": ["jph"],
|
|
270
|
+
"image/jphc": ["jhc"],
|
|
271
|
+
"image/jpm": ["jpm", "jpgm"],
|
|
272
|
+
"image/jpx": ["jpx", "jpf"],
|
|
273
|
+
"image/jxl": ["jxl"],
|
|
274
|
+
"image/jxr": ["jxr"],
|
|
275
|
+
"image/jxra": ["jxra"],
|
|
276
|
+
"image/jxrs": ["jxrs"],
|
|
277
|
+
"image/jxs": ["jxs"],
|
|
278
|
+
"image/jxsc": ["jxsc"],
|
|
279
|
+
"image/jxsi": ["jxsi"],
|
|
280
|
+
"image/jxss": ["jxss"],
|
|
281
|
+
"image/ktx": ["ktx"],
|
|
282
|
+
"image/ktx2": ["ktx2"],
|
|
283
|
+
"image/pjpeg": ["jfif"],
|
|
284
|
+
"image/png": ["png"],
|
|
285
|
+
"image/sgi": ["sgi"],
|
|
286
|
+
"image/svg+xml": ["svg", "svgz"],
|
|
287
|
+
"image/t38": ["t38"],
|
|
288
|
+
"image/tiff": ["tif", "tiff"],
|
|
289
|
+
"image/tiff-fx": ["tfx"],
|
|
290
|
+
"image/webp": ["webp"],
|
|
291
|
+
"image/wmf": ["wmf"],
|
|
292
|
+
"message/disposition-notification": ["disposition-notification"],
|
|
293
|
+
"message/global": ["u8msg"],
|
|
294
|
+
"message/global-delivery-status": ["u8dsn"],
|
|
295
|
+
"message/global-disposition-notification": ["u8mdn"],
|
|
296
|
+
"message/global-headers": ["u8hdr"],
|
|
297
|
+
"message/rfc822": ["eml", "mime", "mht", "mhtml"],
|
|
298
|
+
"model/3mf": ["3mf"],
|
|
299
|
+
"model/gltf+json": ["gltf"],
|
|
300
|
+
"model/gltf-binary": ["glb"],
|
|
301
|
+
"model/iges": ["igs", "iges"],
|
|
302
|
+
"model/jt": ["jt"],
|
|
303
|
+
"model/mesh": ["msh", "mesh", "silo"],
|
|
304
|
+
"model/mtl": ["mtl"],
|
|
305
|
+
"model/obj": ["obj"],
|
|
306
|
+
"model/prc": ["prc"],
|
|
307
|
+
"model/step": ["step", "stp", "stpnc", "p21", "210"],
|
|
308
|
+
"model/step+xml": ["stpx"],
|
|
309
|
+
"model/step+zip": ["stpz"],
|
|
310
|
+
"model/step-xml+zip": ["stpxz"],
|
|
311
|
+
"model/stl": ["stl"],
|
|
312
|
+
"model/u3d": ["u3d"],
|
|
313
|
+
"model/vrml": ["wrl", "vrml"],
|
|
314
|
+
"model/x3d+binary": ["*x3db", "x3dbz"],
|
|
315
|
+
"model/x3d+fastinfoset": ["x3db"],
|
|
316
|
+
"model/x3d+vrml": ["*x3dv", "x3dvz"],
|
|
317
|
+
"model/x3d+xml": ["x3d", "x3dz"],
|
|
318
|
+
"model/x3d-vrml": ["x3dv"],
|
|
319
|
+
"text/cache-manifest": ["appcache", "manifest"],
|
|
320
|
+
"text/calendar": ["ics", "ifb"],
|
|
321
|
+
"text/coffeescript": ["coffee", "litcoffee"],
|
|
322
|
+
"text/css": ["css"],
|
|
323
|
+
"text/csv": ["csv"],
|
|
324
|
+
"text/html": ["html", "htm", "shtml"],
|
|
325
|
+
"text/jade": ["jade"],
|
|
326
|
+
"text/javascript": ["js", "mjs"],
|
|
327
|
+
"text/jsx": ["jsx"],
|
|
328
|
+
"text/less": ["less"],
|
|
329
|
+
"text/markdown": ["md", "markdown"],
|
|
330
|
+
"text/mathml": ["mml"],
|
|
331
|
+
"text/mdx": ["mdx"],
|
|
332
|
+
"text/n3": ["n3"],
|
|
333
|
+
"text/plain": ["txt", "text", "conf", "def", "list", "log", "in", "ini"],
|
|
334
|
+
"text/richtext": ["rtx"],
|
|
335
|
+
"text/rtf": ["*rtf"],
|
|
336
|
+
"text/sgml": ["sgml", "sgm"],
|
|
337
|
+
"text/shex": ["shex"],
|
|
338
|
+
"text/slim": ["slim", "slm"],
|
|
339
|
+
"text/spdx": ["spdx"],
|
|
340
|
+
"text/stylus": ["stylus", "styl"],
|
|
341
|
+
"text/tab-separated-values": ["tsv"],
|
|
342
|
+
"text/troff": ["t", "tr", "roff", "man", "me", "ms"],
|
|
343
|
+
"text/turtle": ["ttl"],
|
|
344
|
+
"text/uri-list": ["uri", "uris", "urls"],
|
|
345
|
+
"text/vcard": ["vcard"],
|
|
346
|
+
"text/vtt": ["vtt"],
|
|
347
|
+
"text/wgsl": ["wgsl"],
|
|
348
|
+
"text/xml": ["*xml"],
|
|
349
|
+
"text/yaml": ["yaml", "yml"],
|
|
350
|
+
"video/3gpp": ["3gp", "3gpp"],
|
|
351
|
+
"video/3gpp2": ["3g2"],
|
|
352
|
+
"video/h261": ["h261"],
|
|
353
|
+
"video/h263": ["h263"],
|
|
354
|
+
"video/h264": ["h264"],
|
|
355
|
+
"video/iso.segment": ["m4s"],
|
|
356
|
+
"video/jpeg": ["jpgv"],
|
|
357
|
+
"video/jpm": ["*jpm", "*jpgm"],
|
|
358
|
+
"video/mj2": ["mj2", "mjp2"],
|
|
359
|
+
"video/mp2t": ["ts", "m2t", "m2ts", "mts"],
|
|
360
|
+
"video/mp4": ["mp4", "mp4v", "mpg4"],
|
|
361
|
+
"video/mpeg": ["mpeg", "mpg", "mpe", "m1v", "m2v"],
|
|
362
|
+
"video/ogg": ["ogv"],
|
|
363
|
+
"video/quicktime": ["qt", "mov"],
|
|
364
|
+
"video/webm": ["webm"]
|
|
365
|
+
};
|
|
366
|
+
Object.freeze(types);
|
|
367
|
+
var standard_default = types;
|
|
368
|
+
|
|
369
|
+
// node_modules/mime/dist/src/Mime.js
|
|
370
|
+
var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
371
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
372
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
373
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
374
|
+
};
|
|
375
|
+
var _Mime_extensionToType;
|
|
376
|
+
var _Mime_typeToExtension;
|
|
377
|
+
var _Mime_typeToExtensions;
|
|
378
|
+
var Mime = class {
|
|
379
|
+
constructor(...args) {
|
|
380
|
+
_Mime_extensionToType.set(this, /* @__PURE__ */ new Map());
|
|
381
|
+
_Mime_typeToExtension.set(this, /* @__PURE__ */ new Map());
|
|
382
|
+
_Mime_typeToExtensions.set(this, /* @__PURE__ */ new Map());
|
|
383
|
+
for (const arg of args) {
|
|
384
|
+
this.define(arg);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
define(typeMap, force = false) {
|
|
388
|
+
for (let [type, extensions] of Object.entries(typeMap)) {
|
|
389
|
+
type = type.toLowerCase();
|
|
390
|
+
extensions = extensions.map((ext) => ext.toLowerCase());
|
|
391
|
+
if (!__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").has(type)) {
|
|
392
|
+
__classPrivateFieldGet(this, _Mime_typeToExtensions, "f").set(type, /* @__PURE__ */ new Set());
|
|
393
|
+
}
|
|
394
|
+
const allExtensions = __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type);
|
|
395
|
+
let first = true;
|
|
396
|
+
for (let extension of extensions) {
|
|
397
|
+
const starred = extension.startsWith("*");
|
|
398
|
+
extension = starred ? extension.slice(1) : extension;
|
|
399
|
+
allExtensions?.add(extension);
|
|
400
|
+
if (first) {
|
|
401
|
+
__classPrivateFieldGet(this, _Mime_typeToExtension, "f").set(type, extension);
|
|
402
|
+
}
|
|
403
|
+
first = false;
|
|
404
|
+
if (starred)
|
|
405
|
+
continue;
|
|
406
|
+
const currentType = __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(extension);
|
|
407
|
+
if (currentType && currentType != type && !force) {
|
|
408
|
+
throw new Error(`"${type} -> ${extension}" conflicts with "${currentType} -> ${extension}". Pass \`force=true\` to override this definition.`);
|
|
409
|
+
}
|
|
410
|
+
__classPrivateFieldGet(this, _Mime_extensionToType, "f").set(extension, type);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return this;
|
|
414
|
+
}
|
|
415
|
+
getType(path) {
|
|
416
|
+
if (typeof path !== "string")
|
|
417
|
+
return null;
|
|
418
|
+
const last = path.replace(/^.*[/\\]/s, "").toLowerCase();
|
|
419
|
+
const ext = last.replace(/^.*\./s, "").toLowerCase();
|
|
420
|
+
const hasPath = last.length < path.length;
|
|
421
|
+
const hasDot = ext.length < last.length - 1;
|
|
422
|
+
if (!hasDot && hasPath)
|
|
423
|
+
return null;
|
|
424
|
+
return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
|
|
425
|
+
}
|
|
426
|
+
getExtension(type) {
|
|
427
|
+
if (typeof type !== "string")
|
|
428
|
+
return null;
|
|
429
|
+
type = type?.split?.(";")[0];
|
|
430
|
+
return (type && __classPrivateFieldGet(this, _Mime_typeToExtension, "f").get(type.trim().toLowerCase())) ?? null;
|
|
431
|
+
}
|
|
432
|
+
getAllExtensions(type) {
|
|
433
|
+
if (typeof type !== "string")
|
|
434
|
+
return null;
|
|
435
|
+
return __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").get(type.toLowerCase()) ?? null;
|
|
436
|
+
}
|
|
437
|
+
_freeze() {
|
|
438
|
+
this.define = () => {
|
|
439
|
+
throw new Error("define() not allowed for built-in Mime objects. See https://github.com/broofa/mime/blob/main/README.md#custom-mime-instances");
|
|
440
|
+
};
|
|
441
|
+
Object.freeze(this);
|
|
442
|
+
for (const extensions of __classPrivateFieldGet(this, _Mime_typeToExtensions, "f").values()) {
|
|
443
|
+
Object.freeze(extensions);
|
|
444
|
+
}
|
|
445
|
+
return this;
|
|
446
|
+
}
|
|
447
|
+
_getTestState() {
|
|
448
|
+
return {
|
|
449
|
+
types: __classPrivateFieldGet(this, _Mime_extensionToType, "f"),
|
|
450
|
+
extensions: __classPrivateFieldGet(this, _Mime_typeToExtension, "f")
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
_Mime_extensionToType = /* @__PURE__ */ new WeakMap(), _Mime_typeToExtension = /* @__PURE__ */ new WeakMap(), _Mime_typeToExtensions = /* @__PURE__ */ new WeakMap();
|
|
455
|
+
var Mime_default = Mime;
|
|
456
|
+
|
|
457
|
+
// node_modules/mime/dist/src/index_lite.js
|
|
458
|
+
var index_lite_default = new Mime_default(standard_default)._freeze();
|
|
459
|
+
|
|
460
|
+
// src/worker.js
|
|
461
|
+
import { routes } from "ROUTES";
|
|
462
|
+
function isImmutable(pathname) {
|
|
463
|
+
for (const pattern of routes.immutable) {
|
|
464
|
+
if (pattern.endsWith("/*")) {
|
|
465
|
+
const prefix = pattern.slice(0, -1);
|
|
466
|
+
if (pathname.startsWith(prefix)) {
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
} else if (pathname === pattern) {
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
var worker_default = {
|
|
476
|
+
async fetch(req, env) {
|
|
477
|
+
const url = new URL(req.url);
|
|
478
|
+
let { pathname } = url;
|
|
479
|
+
try {
|
|
480
|
+
pathname = decodeURIComponent(pathname);
|
|
481
|
+
} catch {
|
|
482
|
+
}
|
|
483
|
+
if (pathname !== "/" && pathname.endsWith("/")) {
|
|
484
|
+
pathname = pathname.slice(0, -1);
|
|
485
|
+
}
|
|
486
|
+
let response = await tryServeFile(env, pathname);
|
|
487
|
+
if (response) {
|
|
488
|
+
return addHeaders(response, pathname);
|
|
489
|
+
}
|
|
490
|
+
if (pathname === "/" || routes.mode === "directory") {
|
|
491
|
+
const indexPath = pathname === "/" ? "/index.html" : pathname + "/index.html";
|
|
492
|
+
response = await tryServeFile(env, indexPath);
|
|
493
|
+
if (response) {
|
|
494
|
+
return addHeaders(response, indexPath);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (routes.mode === "flat" && pathname !== "/") {
|
|
498
|
+
response = await tryServeFile(env, pathname + ".html");
|
|
499
|
+
if (response) {
|
|
500
|
+
return addHeaders(response, pathname + ".html");
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (routes.fallback) {
|
|
504
|
+
response = await tryServeFile(env, routes.fallback);
|
|
505
|
+
if (response) {
|
|
506
|
+
return addHeaders(response, routes.fallback);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
response = await tryServeFile(env, "/404.html");
|
|
510
|
+
if (response) {
|
|
511
|
+
return new Response(response.body, {
|
|
512
|
+
status: 404,
|
|
513
|
+
headers: response.headers
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
return new Response("Not Found", { status: 404 });
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
async function tryServeFile(env, pathname) {
|
|
520
|
+
try {
|
|
521
|
+
const response = await env.ASSETS.fetch(pathname);
|
|
522
|
+
if (response.ok) {
|
|
523
|
+
return response;
|
|
524
|
+
}
|
|
525
|
+
return null;
|
|
526
|
+
} catch {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function addHeaders(response, pathname) {
|
|
531
|
+
const headers = new Headers(response.headers);
|
|
532
|
+
if (!headers.has("content-type")) {
|
|
533
|
+
headers.set("content-type", index_lite_default.getType(pathname) ?? "application/octet-stream");
|
|
534
|
+
}
|
|
535
|
+
if (isImmutable(pathname)) {
|
|
536
|
+
headers.set("cache-control", "public, max-age=31536000, immutable");
|
|
537
|
+
} else if (pathname.endsWith(".html")) {
|
|
538
|
+
headers.set("cache-control", "no-cache");
|
|
539
|
+
} else {
|
|
540
|
+
headers.set("cache-control", "public, max-age=3600");
|
|
541
|
+
}
|
|
542
|
+
return new Response(response.body, {
|
|
543
|
+
status: response.status,
|
|
544
|
+
headers
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
export {
|
|
548
|
+
worker_default as default
|
|
549
|
+
};
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface AdapterOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Input directory containing the static files
|
|
4
|
+
* @default 'dist' | 'build' | 'out' | 'public' (auto-detected)
|
|
5
|
+
*/
|
|
6
|
+
input?: string;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Output directory for the OpenWorkers build
|
|
10
|
+
* @default 'dist-openworkers'
|
|
11
|
+
*/
|
|
12
|
+
out?: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Routing mode for serving files without extensions
|
|
16
|
+
* - 'directory': /page -> /page/index.html
|
|
17
|
+
* - 'flat': /page -> /page.html
|
|
18
|
+
* @default auto-detected based on file structure
|
|
19
|
+
*/
|
|
20
|
+
mode?: 'directory' | 'flat';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* SPA fallback file path (e.g., '/index.html' or '/200.html')
|
|
24
|
+
* When set, this file is served for all routes that don't match a file
|
|
25
|
+
* @default undefined (no fallback, returns 404)
|
|
26
|
+
*/
|
|
27
|
+
fallback?: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Glob patterns for immutable assets (hashed filenames)
|
|
31
|
+
* These files get long cache headers
|
|
32
|
+
* @default auto-detected (/_app/immutable/*, /assets/*, etc.)
|
|
33
|
+
*/
|
|
34
|
+
immutable?: string[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Build static site for OpenWorkers
|
|
39
|
+
*/
|
|
40
|
+
export function adapt(options?: AdapterOptions): Promise<void>;
|
|
41
|
+
|
|
42
|
+
export default adapt;
|
package/index.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { existsSync, writeFileSync, readFileSync, cpSync, readdirSync, statSync, mkdirSync, rmSync } from 'node:fs';
|
|
2
|
+
import { join, posix, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { build } from 'esbuild';
|
|
5
|
+
|
|
6
|
+
const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf-8'));
|
|
7
|
+
const name = '@openworkers/adapter-static';
|
|
8
|
+
const version = pkg.version;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} AdapterOptions
|
|
12
|
+
* @property {string} [input] - Input directory (default: 'dist' or 'build')
|
|
13
|
+
* @property {string} [out] - Output directory (default: 'dist-openworkers')
|
|
14
|
+
* @property {'directory' | 'flat'} [mode] - Routing mode (default: auto-detect)
|
|
15
|
+
* @property {string} [fallback] - SPA fallback file (e.g., '/index.html' or '/200.html')
|
|
16
|
+
* @property {string[]} [immutable] - Glob patterns for immutable assets
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Build static site for OpenWorkers
|
|
21
|
+
* @param {AdapterOptions} options
|
|
22
|
+
*/
|
|
23
|
+
export async function adapt(options = {}) {
|
|
24
|
+
const input = options.input ?? findInputDir();
|
|
25
|
+
const out = options.out ?? 'dist-openworkers';
|
|
26
|
+
const fallback = options.fallback ?? null;
|
|
27
|
+
|
|
28
|
+
if (!existsSync(input)) {
|
|
29
|
+
throw new Error(`Input directory not found: ${input}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const tmp = resolve(out, '.tmp');
|
|
33
|
+
|
|
34
|
+
// Clean and create output directories
|
|
35
|
+
rmSync(out, { recursive: true, force: true });
|
|
36
|
+
mkdirSync(out, { recursive: true });
|
|
37
|
+
mkdirSync(join(out, 'assets'), { recursive: true });
|
|
38
|
+
mkdirSync(tmp, { recursive: true });
|
|
39
|
+
|
|
40
|
+
// Copy all files to assets/
|
|
41
|
+
cpSync(input, join(out, 'assets'), { recursive: true });
|
|
42
|
+
|
|
43
|
+
// Detect routing mode
|
|
44
|
+
const mode = options.mode ?? detectMode(join(out, 'assets'));
|
|
45
|
+
|
|
46
|
+
// Detect immutable patterns
|
|
47
|
+
const immutable = options.immutable ?? detectImmutable(join(out, 'assets'));
|
|
48
|
+
|
|
49
|
+
// Generate routes config
|
|
50
|
+
const routesConfig = {
|
|
51
|
+
mode,
|
|
52
|
+
fallback,
|
|
53
|
+
immutable
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
writeFileSync(join(tmp, 'routes.js'), `export const routes = ${JSON.stringify(routesConfig, null, 2)};\n`);
|
|
57
|
+
|
|
58
|
+
// Bundle worker with esbuild
|
|
59
|
+
await build({
|
|
60
|
+
entryPoints: [fileURLToPath(new URL('./src/worker.js', import.meta.url).href)],
|
|
61
|
+
bundle: true,
|
|
62
|
+
format: 'esm',
|
|
63
|
+
platform: 'browser',
|
|
64
|
+
outfile: resolve(out, 'worker.js'),
|
|
65
|
+
alias: {
|
|
66
|
+
ROUTES: resolve(tmp, 'routes.js')
|
|
67
|
+
},
|
|
68
|
+
minify: false,
|
|
69
|
+
banner: {
|
|
70
|
+
js: `// Generated by ${name} v${version}\n`
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Generate routes.js manifest for edge router
|
|
75
|
+
const allFiles = listFiles(join(out, 'assets'));
|
|
76
|
+
const staticFiles = allFiles.filter((f) => !isImmutablePath(f, immutable));
|
|
77
|
+
|
|
78
|
+
const manifest = {
|
|
79
|
+
immutable,
|
|
80
|
+
static: staticFiles.map((f) => '/' + f),
|
|
81
|
+
fallback
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
writeFileSync(
|
|
85
|
+
join(out, 'routes.js'),
|
|
86
|
+
`// Generated by ${name} v${version}\n` +
|
|
87
|
+
`// Used by OpenWorkers edge router for static content\n\n` +
|
|
88
|
+
`export default ${JSON.stringify(manifest, null, '\t')};\n`
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Cleanup tmp
|
|
92
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
93
|
+
|
|
94
|
+
console.log(`Built static site for OpenWorkers:`);
|
|
95
|
+
console.log(` Input: ${input}`);
|
|
96
|
+
console.log(` Output: ${out}`);
|
|
97
|
+
console.log(` Mode: ${mode}`);
|
|
98
|
+
console.log(` Files: ${allFiles.length}`);
|
|
99
|
+
|
|
100
|
+
if (fallback) {
|
|
101
|
+
console.log(` SPA fallback: ${fallback}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Find input directory (dist or build)
|
|
107
|
+
* @returns {string}
|
|
108
|
+
*/
|
|
109
|
+
function findInputDir() {
|
|
110
|
+
if (existsSync('dist')) return 'dist';
|
|
111
|
+
if (existsSync('build')) return 'build';
|
|
112
|
+
if (existsSync('out')) return 'out';
|
|
113
|
+
if (existsSync('public')) return 'public';
|
|
114
|
+
|
|
115
|
+
throw new Error('Could not find input directory. Specify --input or create dist/build folder.');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Detect routing mode based on file structure
|
|
120
|
+
* @param {string} dir
|
|
121
|
+
* @returns {'directory' | 'flat'}
|
|
122
|
+
*/
|
|
123
|
+
function detectMode(dir) {
|
|
124
|
+
// Check if there are index.html files in subdirectories (directory mode)
|
|
125
|
+
const files = listFiles(dir);
|
|
126
|
+
const hasNestedIndex = files.some((f) => f.includes('/index.html') && f !== 'index.html');
|
|
127
|
+
|
|
128
|
+
if (hasNestedIndex) {
|
|
129
|
+
return 'directory';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Check if there are .html files at root level (flat mode)
|
|
133
|
+
const hasRootHtml = files.some((f) => !f.includes('/') && f.endsWith('.html') && f !== 'index.html');
|
|
134
|
+
|
|
135
|
+
if (hasRootHtml) {
|
|
136
|
+
return 'flat';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Default to directory mode
|
|
140
|
+
return 'directory';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Detect immutable asset patterns
|
|
145
|
+
* @param {string} dir
|
|
146
|
+
* @returns {string[]}
|
|
147
|
+
*/
|
|
148
|
+
function detectImmutable(dir) {
|
|
149
|
+
const patterns = [];
|
|
150
|
+
|
|
151
|
+
// Common patterns for hashed assets
|
|
152
|
+
const commonImmutable = [
|
|
153
|
+
'_app/immutable', // SvelteKit
|
|
154
|
+
'assets', // Vite
|
|
155
|
+
'_next/static', // Next.js
|
|
156
|
+
'_astro' // Astro
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
for (const pattern of commonImmutable) {
|
|
160
|
+
if (existsSync(join(dir, pattern))) {
|
|
161
|
+
patterns.push(`/${pattern}/*`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return patterns;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Check if a path matches immutable patterns
|
|
170
|
+
* @param {string} filepath
|
|
171
|
+
* @param {string[]} patterns
|
|
172
|
+
* @returns {boolean}
|
|
173
|
+
*/
|
|
174
|
+
function isImmutablePath(filepath, patterns) {
|
|
175
|
+
for (const pattern of patterns) {
|
|
176
|
+
if (pattern.endsWith('/*')) {
|
|
177
|
+
const prefix = pattern.slice(1, -2); // Remove leading / and trailing /*
|
|
178
|
+
|
|
179
|
+
if (filepath.startsWith(prefix)) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* List all files in a directory recursively
|
|
190
|
+
* @param {string} dir
|
|
191
|
+
* @param {string} [base='']
|
|
192
|
+
* @returns {string[]}
|
|
193
|
+
*/
|
|
194
|
+
function listFiles(dir, base = '') {
|
|
195
|
+
const results = [];
|
|
196
|
+
const entries = readdirSync(dir);
|
|
197
|
+
|
|
198
|
+
for (const entry of entries) {
|
|
199
|
+
const fullPath = join(dir, entry);
|
|
200
|
+
const relativePath = base ? posix.join(base, entry) : entry;
|
|
201
|
+
const stat = statSync(fullPath);
|
|
202
|
+
|
|
203
|
+
if (stat.isDirectory()) {
|
|
204
|
+
results.push(...listFiles(fullPath, relativePath));
|
|
205
|
+
} else {
|
|
206
|
+
results.push(relativePath);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return results;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export default adapt;
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openworkers/adapter-static",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Static site adapter for OpenWorkers",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"adapter",
|
|
7
|
+
"openworkers",
|
|
8
|
+
"edge",
|
|
9
|
+
"workers",
|
|
10
|
+
"static",
|
|
11
|
+
"hosting"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/openworkers/adapter-static.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"type": "module",
|
|
19
|
+
"bin": {
|
|
20
|
+
"adapter-static": "./bin/cli.js"
|
|
21
|
+
},
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./index.d.ts",
|
|
25
|
+
"import": "./index.js"
|
|
26
|
+
},
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
},
|
|
29
|
+
"types": "index.d.ts",
|
|
30
|
+
"files": [
|
|
31
|
+
"bin",
|
|
32
|
+
"files",
|
|
33
|
+
"index.js",
|
|
34
|
+
"index.d.ts"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "esbuild src/worker.js --bundle --outfile=files/worker.js --external:ROUTES --format=esm",
|
|
38
|
+
"prepublishOnly": "bun run build",
|
|
39
|
+
"format": "prettier --write ."
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"esbuild": "^0.24.0",
|
|
43
|
+
"mime": "^4.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@openworkers/workers-types": "^0.1.7",
|
|
47
|
+
"prettier": "^3.8.1"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public",
|
|
51
|
+
"registry": "https://registry.npmjs.org/"
|
|
52
|
+
}
|
|
53
|
+
}
|