@iyulab/enterprise 0.14.0 โ†’ 0.16.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/CHANGELOG.md CHANGED
@@ -1,5 +1,69 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.16.0] - 2026-09-22
4
+
5
+ ### Documentation
6
+
7
+ - ๐Ÿ”ด **`styles/preset.css` now says why its documented usage used to do nothing.** The header's
8
+ third clause said layer order is decided by load order and is therefore already under the
9
+ consumer's control. It was not: the defaults layer is injected at runtime by
10
+ `@iyulab/components`' `Theme.init()`, so until that package's **1.44.0** it landed *after* a
11
+ statically imported sheet and won. The one-line `import` this file documents had **no effect at
12
+ all**, silently โ€” and because the two sheets agree on `body`/`label`/`caption`/`overline` and
13
+ differ only on the upper type steps and the radii, it still looked applied. The clause now
14
+ states that, names the version where the documented usage starts working, and says what to do
15
+ on an older one.
16
+ - **`docs/lob-layers.md` carried the same third clause, and the same false statement with it.**
17
+ A rule that lives in two published documents goes stale in two places; that one now names the
18
+ premise this package cannot hold on its own -- load order is decided by whoever injects the
19
+ defaults layer -- and says which version makes the documented arrangement true.
20
+ - **The header also called the `@iyulab/components` peer optional. It is not** โ€” this package's
21
+ runtime code imports `Locale`, `format` and `icons` from it, so it is required whether or not
22
+ you load the preset. The prose was the wrong half of that mismatch and has been corrected.
23
+
24
+ ### Changed
25
+
26
+ - ๐Ÿ”ด **The `@iyulab/components` peer range is now `>=1.44.0`** (was `>=1.27.0`). Every version
27
+ below that places the defaults layer last, which is exactly the arrangement in which this
28
+ package's documented preset usage is silently void. A range that admits those versions lets a
29
+ consumer install a combination where the preset does nothing and nothing says so โ€” declaring
30
+ the floor is what turns that from a silent failure into an install-time answer.
31
+
32
+ โš  **This is the only reason for the minor.** No API changed.
33
+
34
+ ## [0.15.0] - 2026-09-22
35
+
36
+ ### Fixed
37
+
38
+ - **`fetchRaw` now matches its own declaration.** It was documented as returning the raw
39
+ response, but the implementation ran every response through `throwIfError` and threw on any
40
+ non-2xx โ€” and it invoked the session hook while doing so. A connection probe that only asks
41
+ "did a response arrive at all" therefore counted a `401` as *unreachable*, when the server was
42
+ in fact alive and refusing, so every signed-out user saw a permanent "cannot reach the server".
43
+ The declaration was the right one, so the implementation changed to match it: `fetchRaw` returns
44
+ the response as-is and calls no session hook.
45
+ โš  **If you relied on the throw**, check `res.ok` yourself, or call `apiGet` when you want the
46
+ error policy applied. Nothing else in the service changed its throwing behavior.
47
+
48
+ ### Added
49
+
50
+ - **Per-call control over the `401` hook.** `onUnauthorized` was all-or-nothing for the whole
51
+ service, but a sign-in call is the one place where `401` means "wrong credentials" rather than
52
+ "your session expired" โ€” so a failed sign-in fired the global hook and threw a message about an
53
+ expired session, leaving the screen to invent a reason for a failure it had been told the wrong
54
+ cause of. Every request method now takes an optional trailing `ODataRequestOptions`; passing
55
+ `{ onUnauthorized: false }` keeps that call out of the global hook and throws with the message
56
+ the server actually sent. Omitting it changes nothing.
57
+ - The option is accepted by **all** request methods, not only the ones with a use for it today.
58
+ The failure being fixed is precisely that a single method had no way to express this, and drawing
59
+ the line again one method further along would reproduce it.
60
+
61
+ ### Notes
62
+
63
+ - **No `authenticate()` primitive was added**, though one was proposed. That name would have to
64
+ assume an endpoint path, a request body shape and a token convention โ€” none of which this
65
+ library owns โ€” so it would encode one caller's server into a general client.
66
+
3
67
  ## [0.14.0] - 2026-09-20
4
68
 
5
69
  ### Fixed
package/README.md CHANGED
@@ -107,6 +107,14 @@ await svc.apiPut<Order>('orders/7', { name: 'A (revised)' }) // ๋ฆฌ์†Œ์Šค ์ „
107
107
  await svc.apiPatch<Order>('orders/7', { note: 'urgent' })
108
108
  await svc.apiDelete('orders/7') // 204 ์•ˆ์ „
109
109
 
110
+ // ๋กœ๊ทธ์ธ โ€” 401 ์ด ใ€Œ์„ธ์…˜ ๋งŒ๋ฃŒใ€๊ฐ€ ์•„๋‹ˆ๋ผ ใ€Œ์ž๊ฒฉ ์ฆ๋ช… ํ‹€๋ฆผใ€์ธ ์œ ์ผํ•œ ํ˜ธ์ถœ์ด๋‹ค.
111
+ // ์ „์—ญ onUnauthorized ๋ฅผ ์ด ํ˜ธ์ถœ์—์„œ๋งŒ ๋„๋ฉด, ์„œ๋ฒ„๊ฐ€ ์ค€ ์‚ฌ์œ ๊ฐ€ ๊ทธ๋Œ€๋กœ ApiError.message ๋กœ ์˜จ๋‹ค.
112
+ await svc.apiPost('auth/login', creds, { onUnauthorized: false })
113
+
114
+ // ์—ฐ๊ฒฐ ํ”„๋กœ๋ธŒ โ€” ใ€Œ์‘๋‹ต์ด ์™”๋Š”๊ฐ€ใ€๋งŒ ๋ฌป๋Š”๋‹ค. fetchRaw ๋Š” ๋˜์ง€์ง€๋„, 401 ํ›…์„ ๋ถ€๋ฅด์ง€๋„ ์•Š๋Š”๋‹ค.
115
+ const probe = await svc.fetchRaw(svc.apiUrl('ping'))
116
+ const reachable = true // ์—ฌ๊ธฐ ๋‹ฟ์•˜๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ๋‹ต์ด๋‹ค(probe.status ๋Š” ๋ณผ ํ•„์š” ์—†๋‹ค)
117
+
110
118
  // body๊ฐ€ FormData ์ธ์Šคํ„ด์Šค๋ฉด ๊ทธ๋Œ€๋กœ(์ง๋ ฌํ™” ์—†์ด) ๋ฉ€ํ‹ฐํŒŒํŠธ๋กœ ์ „์†ก๋œ๋‹ค โ€”
111
119
  // Content-Type์€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ boundary์™€ ํ•จ๊ป˜ ์ž๋™ ์„ค์ •ํ•œ๋‹ค. apiPost/apiPut/apiPatch ์ „๋ถ€ ๋™์ผ.
112
120
  const form = new FormData()
@@ -144,6 +152,38 @@ await svc.apiPost<Order>('orders/7/attachments', form)
144
152
  - **์ด๋ฏธ ์ž๊ธฐ ๋ž˜ํผ๋กœ ํ†ต์ง€ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด `*Quiet` ๋กœ ๋ฐ”๊พผ๋‹ค.** ์ด์ค‘ ํ† ์ŠคํŠธ๋ฅผ ๋ง‰๋Š” ํƒˆ์ถœ๊ตฌ์ด๊ณ ,
145
153
  `odata*Quiet` ์™€ ๊ฐ™์€ ๊ด€์šฉ๊ตฌ๋‹ค(ํ•œ ์‚ฌ์šฉ์ž ์•ก์…˜์ด ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ๋‚ผ ๋•Œ๋„ ๊ฐ™์€ ๊ฒƒ์„ ์“ด๋‹ค).
146
154
 
155
+ #### 401 ์ถ• โ€” ์ „์—ญ ์ •์ฑ…๊ณผ ๊ทธ ํ˜ธ์ถœ ๋‹จ์œ„ ์˜ˆ์™ธ
156
+
157
+ `onUnauthorized` ๋Š” **์„œ๋น„์Šค ์ „์—ญ ์ •์ฑ…**์ด๋‹ค: 401 ์ด ์˜ค๋ฉด ํ›…์„ ๋ถ€๋ฅด๊ณ  `messages.sessionExpired`
158
+ ๋กœ ๋‹จ๋ฝํ•œ๋‹ค. ์ด ๊ธฐ๋ณธ๊ฐ’์€ ๊ฑฐ์˜ ํ•ญ์ƒ ์˜ณ์ง€๋งŒ **๋‘ ์ž๋ฆฌ์—์„œ ํ‹€๋ฆฐ๋‹ค.**
159
+
160
+ | ์ž๋ฆฌ | ์™œ ํ‹€๋ฆฌ๋Š”๊ฐ€ | ํ•ด๋ฒ• |
161
+ |---|---|---|
162
+ | **๋กœ๊ทธ์ธ ์ž์ฒด** | 401 ์ด ใ€Œ์„ธ์…˜์ด ๋Š๊ฒผ๋‹คใ€๊ฐ€ ์•„๋‹ˆ๋ผ ใ€Œ์ž๊ฒฉ ์ฆ๋ช…์ด ํ‹€๋ ธ๋‹คใ€๋ฅผ ๋œปํ•œ๋‹ค. ์ „์—ญ ํ›…์ด ๋ฐœํ™”ํ•˜๋ฉด ๋กœ๊ทธ์ธ ํ™”๋ฉด์—์„œ ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋˜๊ณ , ๋˜์ ธ์ง€๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ `sessionExpired` ๋ผ ํ™”๋ฉด์ด ์‹คํŒจ ์‚ฌ์œ ๋ฅผ **์ง€์–ด๋‚ด์•ผ** ํ•œ๋‹ค | `{ onUnauthorized: false }` |
163
+ | **์—ฐ๊ฒฐ ํ”„๋กœ๋ธŒ** | *ใ€Œ์‘๋‹ต์ด ์™”๋Š”๊ฐ€ใ€* ๋งŒ ๋ฌป๋Š” ํ˜ธ์ถœ์ด๋ผ, 401 ์€ **์„œ๋ฒ„๊ฐ€ ์‚ด์•„์„œ ๊ฑฐ์ ˆํ•œ ๊ฒƒ** = ใ€Œ๋‹ฟ์•˜๋‹คใ€๋‹ค. ํ›…+์˜ˆ์™ธ๋ฅผ ํƒ€๋ฉด ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋Š˜ ใ€Œ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹คใ€๊ฐ€ ๋œฌ๋‹ค | `fetchRaw` |
164
+
165
+ ```ts
166
+ // 401 ์„ ยซ๊ทธ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผยป ๋กœ ๋ฐ›๋Š”๋‹ค โ€” ํ›… ์—†์Œ, ๋ฉ”์‹œ์ง€ ๋ฎ์–ด์“ฐ๊ธฐ ์—†์Œ.
167
+ await svc.apiPost('auth/login', creds, { onUnauthorized: false })
168
+ ```
169
+
170
+ - **๋ชจ๋“  ์š”์ฒญ ๋ฉ”์„œ๋“œ๊ฐ€ ์ด ์˜ต์…˜์„ ๋ฐ›๋Š”๋‹ค**(๋งˆ์ง€๋ง‰ ์„ ํƒ ์ธ์ž). ๋ถ€๋ถ„์ง‘ํ•ฉ์œผ๋กœ ๋‘๋ฉด ๋‹ค์Œ ์†Œ๋น„์ž๊ฐ€
171
+ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ์—์„œ ๊ฐ™์€ ๋ฒฝ์„ ๋งŒ๋‚œ๋‹ค.
172
+ - **๋„๋Š” ์ถ•๋งŒ ์žˆ๋‹ค.** ์ƒˆ ๋™์ž‘์„ ์ผœ๋Š” ์Šค์œ„์น˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ „์—ญ ์ •์ฑ…์˜ ํƒˆ์ถœ๊ตฌ์ด๋ฏ€๋กœ, ์˜ต์…˜์„ ์ƒ๋žตํ•œ
173
+ ํ˜ธ์ถœ์€ ์ด ์˜ต์…˜์ด ์ƒ๊ธฐ๊ธฐ ์ „๊ณผ **ํ•œ ๊ธ€์ž๋„ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.**
174
+ - **`authenticate()` ๊ฐ™์€ ์ด๋ฆ„ ์žˆ๋Š” ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋Š” ๋‘์ง€ ์•Š๋Š”๋‹ค** โ€” ๊ทธ๊ฒƒ์€ ์—”๋“œํฌ์ธํŠธ ๊ฒฝ๋กœยท๋ฐ”๋””
175
+ ๋ชจ์–‘ยทํ† ํฐ ์ฒ˜๋ฆฌ ๊ทœ์•ฝ์„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์•ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” **๋„๋ฉ”์ธ ์ด๋ฆ„**์ด๋‹ค. ๊ทธ ๊ทœ์•ฝ์€ ์•ฑ๋งˆ๋‹ค
176
+ ๋‹ค๋ฅด๋ฏ€๋กœ adapter ์— ๋‚จ๊ธฐ๊ณ , ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ฒ”์šฉ ์ถ•๋งŒ ์—ฐ๋‹ค.
177
+
178
+ #### `fetchRaw` โ€” ใ€Œrawใ€ ๋Š” ์ •์ฑ…์„ ํƒœ์šฐ์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ด๋‹ค
179
+
180
+ ์‘๋‹ต์„ **๊ทธ๋Œ€๋กœ** ๋Œ๋ ค์ค€๋‹ค. **๋น„-2xx ์—๋„ ๋˜์ง€์ง€ ์•Š๊ณ  `onUnauthorized` ๋„ ๋ถ€๋ฅด์ง€ ์•Š๋Š”๋‹ค** โ€”
181
+ ์ƒํƒœ ํŒ๋‹จ์€ ํ˜ธ์ถœ๋ถ€์˜ ๋ชซ์ด๋‹ค. ์ƒํƒœ์— ๋”ฐ๋ผ ์˜ˆ์™ธยทํ† ์ŠคํŠธยท์„ธ์…˜ ์ฒ˜๋ฆฌ๋ฅผ ์›ํ•˜๋ฉด `apiGet` ์„ ์“ด๋‹ค.
182
+
183
+ > โš **0.15.0 ์ด์ „์—๋Š” ์ด ๋ฌธ์žฅ์ด ์„ ์–ธ์— ์ ํ˜€ ์žˆ์œผ๋ฉด์„œ ์‹ค์ œ๋กœ๋Š” ๋น„-2xx ์— ๋˜์กŒ๋‹ค.** ์„ ์–ธ์ด ์˜ณ๊ณ 
184
+ > ๊ตฌํ˜„์ด ํ‹€๋ ธ๋˜ ์ž๋ฆฌ๋ผ ๊ตฌํ˜„์„ ๊ณ ์ณค๋‹ค. `fetchRaw` ์˜ throw ์— ๊ธฐ๋Œ€๊ณ  ์žˆ์—ˆ๋‹ค๋ฉด ํ˜ธ์ถœ๋ถ€์—์„œ
185
+ > `if (!res.ok) throw โ€ฆ` ๋กœ ๋ฐ”๊พธ๊ฑฐ๋‚˜ `apiGet` ์œผ๋กœ ์˜ฎ๊ธด๋‹ค.
186
+
147
187
  > ๋„๋ฉ”์ธ ์•ก์…˜(์ƒํƒœ ์ „์ด ๋“ฑ)ยท์—”ํ‹ฐํ‹ฐ ๋ชฉ๋กยท๊ถŒํ•œ ์ฝ”๋“œ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋„ฃ์ง€ ๋ง๊ณ  ์•ฑ adapter ์— ๋‘”๋‹ค.
148
188
 
149
189
  #### ์‹คํŒจ ์‘๋‹ต โ€” `ApiError`