jskelet 0.6.11 → 0.6.12
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/CHANGELOG.md
CHANGED
|
@@ -19,9 +19,11 @@ one is listed under a **Breaking** heading.
|
|
|
19
19
|
`JSKELET_S3_*`, then ECS task-role / EC2 instance-profile metadata). The
|
|
20
20
|
Assets upload step always appears on production builds; when off it logs a
|
|
21
21
|
one-line reason (`skipped (no build.assets.upload.bucket)`,
|
|
22
|
-
`skipped (credentials missing
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
`skipped (credentials missing (no env keys, no ECS task role …))`, …).
|
|
23
|
+
Docker/`RUN jskelet build` has no task role — upload needs CI role or a
|
|
24
|
+
runtime upload. A URL in `upload.bucket` is rejected with a warning (CDN
|
|
25
|
+
origin belongs in `prefix`). Watch mode never uploads. `.br` / `.gz`
|
|
26
|
+
siblings are skipped.
|
|
25
27
|
|
|
26
28
|
### Changed
|
|
27
29
|
|
package/docs/10-dagitim.md
CHANGED
|
@@ -55,34 +55,41 @@ ayarlamayı düşünmeniz gerekenler:
|
|
|
55
55
|
|
|
56
56
|
### Asset'leri S3 / CloudFront'a basmak
|
|
57
57
|
|
|
58
|
-
Varsayılan kapalıdır. Config'te prefix + bucket;
|
|
58
|
+
Varsayılan kapalıdır. Config'te prefix + bucket; credential env key **veya**
|
|
59
|
+
IAM role:
|
|
59
60
|
|
|
60
61
|
```js
|
|
61
|
-
// jskelet.config.mjs
|
|
62
|
+
// jskelet.config.mjs — uygulama env'lerini buraya bağla
|
|
62
63
|
build: {
|
|
63
64
|
assets: {
|
|
64
|
-
prefix:
|
|
65
|
+
prefix: process.env.NEXT_PUBLIC_STATIC_ASSETS_BASE_URL, // https://static.…
|
|
65
66
|
upload: {
|
|
66
|
-
bucket:
|
|
67
|
+
bucket: process.env.S3_BUCKET_NAME, // static.investvio.com
|
|
67
68
|
keyPrefix: "js",
|
|
68
|
-
region: "eu-central-1",
|
|
69
|
+
region: process.env.AWS_REGION || "eu-central-1",
|
|
70
|
+
endpoint: process.env.AWS_S3_ENDPOINT || undefined,
|
|
69
71
|
},
|
|
70
72
|
},
|
|
71
73
|
},
|
|
72
74
|
```
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
**Task role ne zaman çalışır?** ECS task role /
|
|
77
|
+
`AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` yalnızca **görev çalışırken** vardır.
|
|
78
|
+
Dockerfile içindeki `RUN jskelet build` veya CI build agent'ında bu URI
|
|
79
|
+
yoktur → `skipped (credentials missing (no env keys, no ECS task role …))`.
|
|
80
|
+
AWS SDK'nın runtime'da rolü görmesi, build adımının rolü görmesi demek değildir.
|
|
81
|
+
|
|
82
|
+
Pratik seçenekler:
|
|
83
|
+
|
|
84
|
+
1. **CI'da rol ile build** (CodeBuild / GitHub OIDC) — static key yok, upload
|
|
85
|
+
build job'unda biter.
|
|
86
|
+
2. **Image'da yalnızca derle**, upload'u ECS start'ta ayrı koş (task role o an
|
|
87
|
+
vardır).
|
|
88
|
+
3. CI'da geçici `AWS_*` key (tercih edilmez).
|
|
80
89
|
|
|
81
|
-
`jskelet build` bitince `public/assets/`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
`jskelet dev` upload yapmaz. CSP kullanıyorsanız CDN origin'ini `script-src` /
|
|
85
|
-
`style-src` / `img-src` ve `preconnect` listesine ekleyin.
|
|
90
|
+
`jskelet build` bitince `public/assets/` S3'e kopyalanır; origin kopyası durur.
|
|
91
|
+
Bucket/credential yoksa adım `skipped (…)` basar. Watch / `jskelet dev` upload
|
|
92
|
+
yapmaz. CSP'ye CDN origin ekleyin.
|
|
86
93
|
|
|
87
94
|
Production'da dosya veya S3 sink açıldığında HTTP access log middleware
|
|
88
95
|
otomatik mount edilir (`logs.kinds` içinde `http` varsa). Admin paneli ring'i
|
package/docs/en/10-deployment.md
CHANGED
|
@@ -56,34 +56,40 @@ considering in production:
|
|
|
56
56
|
|
|
57
57
|
### Publishing assets to S3 / CloudFront
|
|
58
58
|
|
|
59
|
-
Off by default. Prefix + bucket in config; credentials
|
|
59
|
+
Off by default. Prefix + bucket in config; credentials from env keys **or** an
|
|
60
|
+
IAM role:
|
|
60
61
|
|
|
61
62
|
```js
|
|
62
|
-
// jskelet.config.mjs
|
|
63
|
+
// jskelet.config.mjs — wire your app env vars here
|
|
63
64
|
build: {
|
|
64
65
|
assets: {
|
|
65
|
-
prefix:
|
|
66
|
+
prefix: process.env.NEXT_PUBLIC_STATIC_ASSETS_BASE_URL, // https://static.…
|
|
66
67
|
upload: {
|
|
67
|
-
bucket:
|
|
68
|
+
bucket: process.env.S3_BUCKET_NAME, // static.example.com
|
|
68
69
|
keyPrefix: "js",
|
|
69
|
-
region: "eu-central-1",
|
|
70
|
+
region: process.env.AWS_REGION || "eu-central-1",
|
|
71
|
+
endpoint: process.env.AWS_S3_ENDPOINT || undefined,
|
|
70
72
|
},
|
|
71
73
|
},
|
|
72
74
|
},
|
|
73
75
|
```
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
**When does the task role work?** The ECS task role /
|
|
78
|
+
`AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` exist only while the **task is
|
|
79
|
+
running**. A `RUN jskelet build` inside Docker or a CI build agent has no such
|
|
80
|
+
URI → `skipped (credentials missing (no env keys, no ECS task role …))`. The AWS
|
|
81
|
+
SDK seeing the role at runtime does not mean the build step sees it.
|
|
82
|
+
|
|
83
|
+
Practical options:
|
|
84
|
+
|
|
85
|
+
1. **Build with a CI role** (CodeBuild / GitHub OIDC) — no static keys; upload
|
|
86
|
+
finishes in the job.
|
|
87
|
+
2. **Compile in the image**, run upload at ECS start (task role is present then).
|
|
88
|
+
3. Temporary `AWS_*` keys in CI (not preferred).
|
|
81
89
|
|
|
82
|
-
When `jskelet build` finishes,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
build continues. Watch / `jskelet dev` never upload. If you use CSP, add the CDN
|
|
86
|
-
origin to `script-src` / `style-src` / `img-src` and to `preconnect`.
|
|
90
|
+
When `jskelet build` finishes, `public/assets/` is copied to S3; origin copies
|
|
91
|
+
remain. Missing bucket/credentials log `skipped (…)`. Watch / `jskelet dev`
|
|
92
|
+
never upload. Add the CDN origin to CSP.
|
|
87
93
|
|
|
88
94
|
When a file or S3 sink is enabled in production, the HTTP access log middleware
|
|
89
95
|
mounts automatically (if `http` is in `logs.kinds`). The admin panel ring is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jskelet",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.12",
|
|
4
4
|
"description": "A framework that feels like no framework: Express 5 + build-time .jsk SSR (optional EJS peer), vanilla JS islands, Tailwind v4 and an in-process HTML TTL cache.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import fs from "node:fs";
|
|
14
14
|
import path from "node:path";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
resolveS3Credentials,
|
|
17
|
+
s3CredentialsMissingReason,
|
|
18
|
+
} from "../../server/logs/s3-credentials.js";
|
|
16
19
|
import { putObject } from "../../server/logs/s3-put.js";
|
|
17
20
|
import * as log from "../../log.mjs";
|
|
18
21
|
import { paths } from "../paths.mjs";
|
|
@@ -127,7 +130,7 @@ export async function uploadAssets(config, options = {}) {
|
|
|
127
130
|
const resolve = options.resolveCredentials ?? resolveS3Credentials;
|
|
128
131
|
const credentials = await resolve();
|
|
129
132
|
if (!upload.bucket || !credentials) {
|
|
130
|
-
log.detail(
|
|
133
|
+
log.detail(`skipped (${s3CredentialsMissingReason()})`);
|
|
131
134
|
return;
|
|
132
135
|
}
|
|
133
136
|
|
|
@@ -16,7 +16,9 @@ import process from "node:process";
|
|
|
16
16
|
* sessionToken: string | null }} AwsCredentials
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// Local'de IMDS yokken hızlı vazgeç; ECS'te URI varken biraz daha sabır.
|
|
20
|
+
const IMDS_TIMEOUT_MS = 400;
|
|
21
|
+
const ECS_TIMEOUT_MS = 2_000;
|
|
20
22
|
const ECS_METADATA_HOST = "http://169.254.170.2";
|
|
21
23
|
const EC2_METADATA_HOST = "http://169.254.169.254";
|
|
22
24
|
|
|
@@ -72,7 +74,7 @@ function fromAwsCredentialJson(data) {
|
|
|
72
74
|
* @param {number} [timeoutMs]
|
|
73
75
|
* @returns {Promise<unknown | null>}
|
|
74
76
|
*/
|
|
75
|
-
async function fetchJson(url, init = {}, timeoutMs =
|
|
77
|
+
async function fetchJson(url, init = {}, timeoutMs = IMDS_TIMEOUT_MS) {
|
|
76
78
|
const controller = new AbortController();
|
|
77
79
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
78
80
|
try {
|
|
@@ -92,7 +94,7 @@ async function fetchJson(url, init = {}, timeoutMs = METADATA_TIMEOUT_MS) {
|
|
|
92
94
|
* @param {number} [timeoutMs]
|
|
93
95
|
* @returns {Promise<string | null>}
|
|
94
96
|
*/
|
|
95
|
-
async function fetchText(url, init = {}, timeoutMs =
|
|
97
|
+
async function fetchText(url, init = {}, timeoutMs = IMDS_TIMEOUT_MS) {
|
|
96
98
|
const controller = new AbortController();
|
|
97
99
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
98
100
|
try {
|
|
@@ -125,7 +127,7 @@ export async function readS3CredentialsFromEcs() {
|
|
|
125
127
|
readTokenFile(process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE);
|
|
126
128
|
if (token) headers.Authorization = token;
|
|
127
129
|
|
|
128
|
-
const data = await fetchJson(url, { headers });
|
|
130
|
+
const data = await fetchJson(url, { headers }, ECS_TIMEOUT_MS);
|
|
129
131
|
if (!data || typeof data !== "object") return null;
|
|
130
132
|
return fromAwsCredentialJson(/** @type {Record<string, unknown>} */ (data));
|
|
131
133
|
}
|
|
@@ -179,6 +181,21 @@ export async function readS3CredentialsFromImds() {
|
|
|
179
181
|
return fromAwsCredentialJson(/** @type {Record<string, unknown>} */ (data));
|
|
180
182
|
}
|
|
181
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Credential neden bulunamadı — upload skip satırı için.
|
|
186
|
+
*
|
|
187
|
+
* @returns {string}
|
|
188
|
+
*/
|
|
189
|
+
export function s3CredentialsMissingReason() {
|
|
190
|
+
if (
|
|
191
|
+
envText(process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) ||
|
|
192
|
+
envText(process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI)
|
|
193
|
+
) {
|
|
194
|
+
return "credentials missing (ECS metadata failed)";
|
|
195
|
+
}
|
|
196
|
+
return "credentials missing (no env keys, no ECS task role — upload needs runtime/CI role, not docker build)";
|
|
197
|
+
}
|
|
198
|
+
|
|
182
199
|
/**
|
|
183
200
|
* Env → ECS task role → EC2 instance profile.
|
|
184
201
|
*
|
|
@@ -19,6 +19,12 @@ export declare function readS3CredentialsFromEcs(): Promise<AwsCredentials | nul
|
|
|
19
19
|
* @returns {Promise<AwsCredentials | null>}
|
|
20
20
|
*/
|
|
21
21
|
export declare function readS3CredentialsFromImds(): Promise<AwsCredentials | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Credential neden bulunamadı — upload skip satırı için.
|
|
24
|
+
*
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
export declare function s3CredentialsMissingReason(): string;
|
|
22
28
|
/**
|
|
23
29
|
* Env → ECS task role → EC2 instance profile.
|
|
24
30
|
*
|