jskelet 0.6.8 → 0.6.9

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
@@ -16,8 +16,10 @@ one is listed under a **Breaking** heading.
16
16
  `build.assets.upload`) is set, production `jskelet build` PutObjects
17
17
  `public/assets/` (and optional `include` dirs) to S3 after precompress.
18
18
  Credentials prefer standard `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` /
19
- `AWS_SESSION_TOKEN`, then `JSKELET_S3_*`. Missing bucket or credentials fail
20
- the build; watch mode never uploads. `.br` / `.gz` siblings are skipped.
19
+ `AWS_SESSION_TOKEN`, then `JSKELET_S3_*`. The Assets upload step always
20
+ appears on production builds; when off it logs a one-line reason
21
+ (`skipped (no JSKELET_ASSETS_BUCKET)`, `skipped (credentials missing)`, …).
22
+ Watch mode never uploads. `.br` / `.gz` siblings are skipped.
21
23
 
22
24
  ### Changed
23
25
 
@@ -638,10 +638,11 @@ değişmez** — asset'ler origin'den servis edilir.
638
638
  | `assets.upload.cacheControl` | `string` | `public, max-age=31536000, immutable` | PutObject `Cache-Control`. |
639
639
 
640
640
  Credential config'e yazılmaz. Öncelik: `AWS_ACCESS_KEY_ID` /
641
- `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`, yoksa `JSKELET_S3_*`. Upload açık
642
- iken bucket veya credential yoksa **build düşer**. Watch turunda upload yok.
643
- `.br` / `.gz` yüklenmez. Ayrıntı: [08-build.md](./08-build.md),
644
- [10-dagitim.md](./10-dagitim.md).
641
+ `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`, yoksa `JSKELET_S3_*`. Production
642
+ build'de Assets upload adımı her zaman görünür; kapalıysa
643
+ `skipped (no JSKELET_ASSETS_BUCKET)` / `skipped (credentials missing)` gibi tek
644
+ satır sebep basılır (build düşmez). Watch turunda adım yok. `.br` / `.gz`
645
+ yüklenmez. Ayrıntı: [08-build.md](./08-build.md), [10-dagitim.md](./10-dagitim.md).
645
646
 
646
647
  ```js
647
648
  build: {
package/docs/08-build.md CHANGED
@@ -20,7 +20,7 @@ davranışı burada. Çıktının çalışma anında nasıl servis edildiği
20
20
  5. Images config.images !== false, watch değil ve sharp kurulu ise
21
21
  6. Manifest .jskelet/manifest.json
22
22
  7. Precompress watch değilse
23
- 8. Assets upload build.assets.upload açıksa (watch değil)
23
+ 8. Assets upload watch değilse (kapalıysa `skipped (sebep)`)
24
24
  ```
25
25
 
26
26
  Şablon derlemesi asset taramasından **önce** biter; istek yolunda parse yoktur.
@@ -34,7 +34,8 @@ Sıra rastgele değil:
34
34
  - **Precompress, upload'tan hemen önce:** origin hâlâ `.br`/`.gz` üretir; S3
35
35
  adımı yalnızca ham dosyaları kopyalar.
36
36
  - **Görseller watch turunda hiç çalışmaz:** `sharp` ile yeniden kodlama pahalı.
37
- - **Assets upload watch'ta yok:** yalnızca production `jskelet build`.
37
+ - **Assets upload watch'ta yok:** yalnızca production `jskelet build`; kapalıysa
38
+ yine satır basılır (`skipped (no JSKELET_ASSETS_BUCKET)` vb.).
38
39
 
39
40
  Görevler yalnızca ilgili yapılandırma varsa çalışır. Font tanımlamayan bir proje
40
41
  font adımını hiç görmez; bu, "framework her projeye kendi varsayımlarını
@@ -70,9 +70,9 @@ AWS_SECRET_ACCESS_KEY=…
70
70
 
71
71
  `jskelet build` bitince `public/assets/` (ve config'te `include` edilen
72
72
  dizinler) S3'e kopyalanır; origin'deki dosyalar da durur. Bucket veya
73
- credential eksikken upload açıksa build düşer. Watch / `jskelet dev` upload
74
- yapmaz. CSP kullanıyorsanız CDN origin'ini `script-src` / `style-src` /
75
- `img-src` ve `preconnect` listesine ekleyin.
73
+ credential yoksa adım `skipped (…)` ile sebep basar, build devam eder. Watch /
74
+ `jskelet dev` upload yapmaz. CSP kullanıyorsanız CDN origin'ini `script-src` /
75
+ `style-src` / `img-src` ve `preconnect` listesine ekleyin.
76
76
 
77
77
  Production'da dosya veya S3 sink açıldığında HTTP access log middleware
78
78
  otomatik mount edilir (`logs.kinds` içinde `http` varsa). Admin paneli ring'i
@@ -652,9 +652,12 @@ changes** — assets stay on the origin.
652
652
 
653
653
  Credentials are not written in the config. Preference order:
654
654
  `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`, then
655
- `JSKELET_S3_*`. When upload is on, a missing bucket or credentials **fails the
656
- build**. No upload on watch passes. `.br` / `.gz` siblings are not uploaded.
657
- Details: [08-build.md](./08-build.md), [10-deployment.md](./10-deployment.md).
655
+ `JSKELET_S3_*`. On a production build the Assets upload step always appears;
656
+ when off it logs a one-line reason such as
657
+ `skipped (no JSKELET_ASSETS_BUCKET)` or `skipped (credentials missing)` (the
658
+ build does not fail). No upload on watch passes. `.br` / `.gz` siblings are not
659
+ uploaded. Details: [08-build.md](./08-build.md),
660
+ [10-deployment.md](./10-deployment.md).
658
661
 
659
662
  ```js
660
663
  build: {
@@ -20,7 +20,7 @@ build is in [09-dev-tools.md](./09-dev-tools.md).
20
20
  5. Images if config.images !== false, not watch, and sharp is installed
21
21
  6. Manifest .jskelet/manifest.json
22
22
  7. Precompress if not watch
23
- 8. Assets upload if build.assets.upload is on (not watch)
23
+ 8. Assets upload if not watch (logs `skipped (reason)` when off)
24
24
  ```
25
25
 
26
26
  Template compilation finishes **before** asset scanning; there is no parse on
@@ -34,7 +34,8 @@ The order is not arbitrary:
34
34
  - **Precompress runs just before upload:** the origin still gets `.br`/`.gz`;
35
35
  the S3 step copies only the raw files.
36
36
  - **Images never run on a watch pass:** re-encoding with `sharp` is expensive.
37
- - **Assets upload never runs on watch:** only production `jskelet build`.
37
+ - **Assets upload never runs on watch:** only production `jskelet build`; when
38
+ off the step still prints (`skipped (no JSKELET_ASSETS_BUCKET)`, etc.).
38
39
 
39
40
  Tasks only run if the relevant configuration exists. A project that does not
40
41
  define any fonts never sees the font step; this is the build-side counterpart of
@@ -70,10 +70,10 @@ AWS_SECRET_ACCESS_KEY=…
70
70
  ```
71
71
 
72
72
  When `jskelet build` finishes, files under `public/assets/` (and any other
73
- `include` directories) are copied to S3; origin copies remain. If upload is on
74
- and the bucket or credentials are missing, the build fails. Watch /
75
- `jskelet dev` never upload. If you use CSP, add the CDN origin to
76
- `script-src` / `style-src` / `img-src` and to `preconnect`.
73
+ `include` directories) are copied to S3; origin copies remain. If the bucket or
74
+ credentials are missing, the step logs `skipped (…)` with the reason and the
75
+ build continues. Watch / `jskelet dev` never upload. If you use CSP, add the CDN
76
+ origin to `script-src` / `style-src` / `img-src` and to `preconnect`.
77
77
 
78
78
  When a file or S3 sink is enabled in production, the HTTP access log middleware
79
79
  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.8",
3
+ "version": "0.6.9",
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",
@@ -110,8 +110,9 @@ if (!watch) {
110
110
  const { precompressAssets } = await import("./tasks/precompress.mjs");
111
111
  await task("Precompress", precompressAssets);
112
112
 
113
+ // Her production build'de satır görünür; kapalıysa `skipped (sebep)`.
113
114
  // CDN'e basılacak dosyalar precompress'ten sonra hazır; `.br`/`.gz` yüklenmez.
114
- if (config.build?.assets?.upload?.enabled) {
115
+ {
115
116
  const { uploadAssets } = await import("./tasks/assets-upload.mjs");
116
117
  await task("Assets upload", () => uploadAssets(config));
117
118
  }
@@ -2,8 +2,8 @@
2
2
  * Production build sonunda hash'li varlıkları S3'e PutObject ile kopyalar.
3
3
  *
4
4
  * Watch turunda çalışmaz (çağıran sorumlu). Credential env'den gelir
5
- * (`AWS_*` önce, `JSKELET_S3_*` yedek). Bucket yoksa veya credential yoksa
6
- * build düşer — CDN prefix ile boş bucket'a deploy olmasın diye.
5
+ * (`AWS_*` önce, `JSKELET_S3_*` yedek). Bucket / credential yoksa veya upload
6
+ * kapalıysa adım yine görünür: `skipped (…)` ile sebep basılır, build düşmez.
7
7
  *
8
8
  * `.br` / `.gz` kardeşleri yüklenmez: edge kendi sıkıştırmasını yapsın;
9
9
  * origin precompress Express için kalır.
@@ -12,6 +12,7 @@ import fs from "node:fs";
12
12
  import path from "node:path";
13
13
  import { readS3CredentialsFromEnv } from "../../config/index.js";
14
14
  import { putObject } from "../../server/logs/s3-put.js";
15
+ import * as log from "../../log.mjs";
15
16
  import { paths } from "../paths.mjs";
16
17
 
17
18
  const CONCURRENCY = 8;
@@ -87,27 +88,46 @@ function resolveIncludeDir(name) {
87
88
  }
88
89
 
89
90
  /**
91
+ * Upload yapılmayacaksa kısa sebep; yapılacaksa `null`.
92
+ *
90
93
  * @param {import('../../config/index.js').ResolvedConfig} config
91
- * @param {{ put?: typeof putObject }} [options]
92
- * @returns {Promise<string>} Özet satır (log.task için)
94
+ * @returns {string | null}
93
95
  */
94
- export async function uploadAssets(config, options = {}) {
96
+ export function assetsUploadSkipReason(config) {
95
97
  const upload = config.build?.assets?.upload;
96
- if (!upload?.enabled) return "skipped";
97
98
 
98
- if (!upload.bucket) {
99
- throw new Error(
100
- "[assets] upload enabled but no bucket — set JSKELET_ASSETS_BUCKET " +
101
- "or build.assets.upload.bucket",
102
- );
99
+ if (!upload?.enabled) {
100
+ // Bucket yoksa asıl eksik env'i söyle — `enabled: false` çoğu zaman
101
+ // bucket tanımlanmadığı için dolaylıdır.
102
+ if (!upload?.bucket) return "no JSKELET_ASSETS_BUCKET";
103
+ return "build.assets.upload.enabled is false";
104
+ }
105
+
106
+ if (!upload.bucket) return "no JSKELET_ASSETS_BUCKET";
107
+
108
+ if (!readS3CredentialsFromEnv()) return "credentials missing";
109
+
110
+ return null;
111
+ }
112
+
113
+ /**
114
+ * @param {import('../../config/index.js').ResolvedConfig} config
115
+ * @param {{ put?: typeof putObject }} [options]
116
+ * @returns {Promise<void>}
117
+ */
118
+ export async function uploadAssets(config, options = {}) {
119
+ const reason = assetsUploadSkipReason(config);
120
+ if (reason) {
121
+ log.detail(`skipped (${reason})`);
122
+ return;
103
123
  }
104
124
 
125
+ const upload = config.build.assets.upload;
105
126
  const credentials = readS3CredentialsFromEnv();
106
- if (!credentials) {
107
- throw new Error(
108
- "[assets] upload enabled but credentials missing — set " +
109
- "AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY or JSKELET_S3_*",
110
- );
127
+ // skipReason null iken credential ve bucket vardır; TS/akış için daralt.
128
+ if (!upload.bucket || !credentials) {
129
+ log.detail("skipped (credentials missing)");
130
+ return;
111
131
  }
112
132
 
113
133
  const put = options.put ?? putObject;
@@ -131,7 +151,10 @@ export async function uploadAssets(config, options = {}) {
131
151
  }
132
152
  }
133
153
 
134
- if (!jobs.length) return "0 files";
154
+ if (!jobs.length) {
155
+ log.detail("0 files");
156
+ return;
157
+ }
135
158
 
136
159
  let uploaded = 0;
137
160
  let index = 0;
@@ -163,5 +186,5 @@ export async function uploadAssets(config, options = {}) {
163
186
 
164
187
  const target = `${upload.bucket}/${keyPrefix}`.replace(/\/+/g, "/");
165
188
  const via = upload.endpoint ? ` @ ${upload.endpoint}` : "";
166
- return `${uploaded} → s3://${target}${via}`;
189
+ log.detail(`${uploaded} → s3://${target}${via}`);
167
190
  }