@simplysm/sd-claude 14.0.98 โ 14.0.99
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/claude/references/sd-simplysm14/README.md +16 -16
- package/claude/references/sd-simplysm14/apis/angular/README.md +81 -153
- package/claude/references/sd-simplysm14/apis/angular/controls.md +179 -205
- package/claude/references/sd-simplysm14/apis/angular/crud.md +71 -57
- package/claude/references/sd-simplysm14/apis/angular/directives.md +49 -109
- package/claude/references/sd-simplysm14/apis/angular/features.md +58 -86
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +32 -40
- package/claude/references/sd-simplysm14/apis/angular/layout.md +38 -52
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +86 -110
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +54 -86
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +82 -74
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +56 -80
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +15 -15
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +21 -21
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +79 -53
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +9 -11
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +15 -15
- package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +20 -20
- package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +18 -18
- package/claude/references/sd-simplysm14/apis/core-common/README.md +20 -49
- package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +66 -55
- package/claude/references/sd-simplysm14/apis/core-common/collection-ext.md +83 -56
- package/claude/references/sd-simplysm14/apis/core-common/errors.md +32 -21
- package/claude/references/sd-simplysm14/apis/core-common/obj.md +57 -39
- package/claude/references/sd-simplysm14/apis/core-common/serialization.md +36 -30
- package/claude/references/sd-simplysm14/apis/core-common/value-types.md +69 -41
- package/claude/references/sd-simplysm14/apis/core-node/README.md +4 -4
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +15 -13
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +11 -7
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +8 -8
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +29 -20
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +14 -6
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +3 -3
- package/claude/references/sd-simplysm14/apis/excel/README.md +3 -3
- package/claude/references/sd-simplysm14/apis/excel/cell.md +32 -32
- package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +23 -24
- package/claude/references/sd-simplysm14/apis/excel/style.md +24 -30
- package/claude/references/sd-simplysm14/apis/excel/utils.md +20 -23
- package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +60 -71
- package/claude/references/sd-simplysm14/apis/excel/wrapper.md +36 -36
- package/claude/references/sd-simplysm14/apis/lint/README.md +7 -9
- package/claude/references/sd-simplysm14/apis/lint/recommended.md +59 -37
- package/claude/references/sd-simplysm14/apis/lint/rules.md +81 -74
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -6
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +112 -78
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +131 -75
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +126 -82
- package/claude/references/sd-simplysm14/apis/orm-common/schema.md +170 -113
- package/claude/references/sd-simplysm14/apis/orm-common/types.md +102 -48
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +12 -13
- package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +3 -3
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +5 -5
- package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +67 -65
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +130 -123
- package/claude/references/sd-simplysm14/apis/service-client/README.md +63 -63
- package/claude/references/sd-simplysm14/apis/service-client/orm.md +22 -22
- package/claude/references/sd-simplysm14/apis/service-client/transport.md +30 -26
- package/claude/references/sd-simplysm14/apis/service-common/README.md +8 -8
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +13 -6
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +1 -1
- package/claude/references/sd-simplysm14/apis/service-server/README.md +43 -47
- package/claude/references/sd-simplysm14/apis/service-server/built-in-services.md +35 -0
- package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +20 -19
- package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +23 -25
- package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +9 -9
- package/claude/references/sd-simplysm14/apis/storage/README.md +26 -26
- package/claude/references/sd-simplysm14/manuals/client-component.md +9 -1
- package/claude/references/sd-simplysm14/manuals/client-crud.md +1 -1
- package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -0
- package/claude/references/sd-simplysm14/manuals/client-service.md +1 -0
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +1 -0
- package/claude/references/sd-simplysm14/manuals/client-ssg.md +1 -0
- package/claude/sd-system-prompt.md +11 -26
- package/claude/skills/sd-docs/references/subagent-prompt.md +4 -3
- package/claude/skills/sd-spec/SKILL.md +87 -18
- package/claude/skills/sd-spec/references/format.md +2 -2
- package/package.json +1 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# @simplysm/service-server
|
|
2
2
|
|
|
3
|
-
Fastify
|
|
3
|
+
Fastify ์์์ ๋์ํ๋ RPC ์๋ฒ. `defineService` ๋ก ์ ์ํ ์๋น์ค๋ฅผ WebSocketยทHTTP(`/api/:service/:method`) ๋ ์ ์ก์ผ๋ก ๋
ธ์ถํ๊ณ , JWT ์ธ์ฆยท์ ์ ํ์ผ ์๋นยทํ์ผ ์
๋ก๋ยท์๋ฒ์ธก ์ด๋ฒคํธ ๋ธ๋ก๋์บ์คํธยท๋ด์ฅ ORM/์๋์
๋ฐ์ดํธ ์๋น์ค๋ฅผ ํ ํ๋ก์ธ์ค์์ ์ ๊ณตํ๋ค.
|
|
4
4
|
|
|
5
5
|
## ์ฌ์ฉ ํธ๋ฆฌ๊ฑฐ ์ธ๋ฑ์ค
|
|
6
6
|
|
|
7
|
-
- **์๋ฒ ๋ถํธ์คํธ๋ฉ** (`createServiceServer
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
- **๋ด์ฅ ์๋น์ค**
|
|
11
|
-
- **์ ์ก ๊ณ์ธต ๋ด๋ถ**
|
|
12
|
-
- **V1
|
|
7
|
+
- **์๋ฒ ๋ถํธ์คํธ๋ฉ** (์ด ๋ฌธ์ ์ธ๋ผ์ธ): `createServiceServer` / `ServiceServer` / `ServiceServerOptions` / `ServerEventProxy` โ ์๋ฒ ์ฑ ์ง์
์ ์์ ์ต์
์ ์ฃผ๊ณ ๊ธฐ๋ยท์ข
๋ฃํ๊ฑฐ๋, ์๋น์ค ๋ฉ์๋์์ ํด๋ผ์ด์ธํธ๋ก ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํฌ ๋.
|
|
8
|
+
- **JWT ์ธ์ฆ ํ ํฐ** (์ด ๋ฌธ์ ์ธ๋ผ์ธ): `AuthTokenPayload` / `signJwt` / `verifyJwt` / `decodeJwt` โ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ์์ ํ ํฐ์ ์๋ช
ยท๊ฒ์ฆํ ๋.
|
|
9
|
+
- **์๋น์ค ์์ฑ** โ `defineService` / `auth` / `getServiceAuthPermissions` / `ServiceContext` / `createServiceContext` / `ServiceDefinition` / `ServiceMethods`. ์์ธํ: [service-authoring.md](./service-authoring.md)
|
|
10
|
+
- **๋ด์ฅ ์๋น์ค** โ `OrmService` / `OrmServiceMethods` / `AutoUpdateService` / `AutoUpdateServiceMethods`. ์์ธํ: [built-in-services.md](./built-in-services.md)
|
|
11
|
+
- **์ ์ก ๊ณ์ธต ๋ด๋ถ** โ `executeServiceMethod` / `createServiceContext` / `ServiceSocket` / `createServiceSocket` / `WebSocketHandler` / `createWebSocketHandler` / `ServerProtocolWrapper` / `createServerProtocolWrapper` / `handleHttpRequest` / `handleUpload` / `handleStaticFile` / `getConfig`. ์์ธํ: [transport-internals.md](./transport-internals.md)
|
|
12
|
+
- **V1 ๋ ๊ฑฐ์** โ `handleV1Connection` / `V1ConnectionOptions` / `V1Request` / `V1Response` / `V1AutoUpdateMethods` / `V1RequestHandler` / `V1RequestHandlerResult` / `V1RequestHandlerContext`. ์์ธํ: [v1-legacy.md](./v1-legacy.md)
|
|
13
13
|
|
|
14
14
|
## ์๋ฒ ๋ถํธ์คํธ๋ฉ
|
|
15
15
|
|
|
@@ -17,24 +17,40 @@ Fastify ๊ธฐ๋ฐ RPC ์๋น์ค ์๋ฒ. WebSocket/HTTP ๋ ์ ์ก์ผ๋ก ์๋น์ค
|
|
|
17
17
|
|
|
18
18
|
### createServiceServer / ServiceServer
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
```ts
|
|
21
|
+
function createServiceServer<TAuthInfo = unknown>(options: ServiceServerOptions): ServiceServer<TAuthInfo>;
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
์ต์
์ผ๋ก ์๋ฒ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค(์ด ์์ ์ ์์ง ๋ฆฌ์จํ์ง ์์). `new ServiceServer<TAuthInfo>(options)` ์ง์ ์์ฑ๊ณผ ๋์ผํ๋ค.
|
|
25
|
+
|
|
26
|
+
- `TAuthInfo` โ ์ธ์ฆ ํ ํฐ `data` ํ์ด๋ก๋ ํ์
. `signAuthToken`ยท`verifyAuthToken`ยท`ServiceContext.authInfo` ๊ฐ ๋ชจ๋ ์ด ํ์
์ผ๋ก ๋ฌถ์ธ๋ค.
|
|
21
27
|
|
|
22
28
|
`ServiceServerOptions` ํ๋:
|
|
23
29
|
|
|
24
30
|
- `rootPath: string` โ ์๋ฒ ์์
๋ฃจํธ. ์ ์ ํ์ผยท์
๋ก๋ยท์๋์
๋ฐ์ดํธ๋ `rootPath/www` ํ์๋ฅผ, ์ค์ ์ `rootPath/.config.json` ์ ๊ธฐ์ค์ผ๋ก ํ๋ค. ์ ๋๊ฒฝ๋ก ๊ถ์ฅ.
|
|
25
|
-
- `port: number` โ ๋ฆฌ์จ ํฌํธ(`
|
|
26
|
-
- `ssl?: { pfxBytes: Uint8Array; passphrase
|
|
27
|
-
- `
|
|
28
|
-
- `
|
|
29
|
-
- `
|
|
31
|
+
- `port: number` โ ๋ฆฌ์จ ํฌํธ(๋ฐ์ธ๋ฉ ํธ์คํธ๋ `"0.0.0.0"` ๊ณ ์ ). `0` ์ ์ฃผ๋ฉด OS ๊ฐ ์์ ํฌํธ๋ฅผ ํ ๋นํ๋ฏ๋ก ํ
์คํธ์ ์ฐ๊ณ , ์ค์ ํฌํธ๋ `server.fastify.server.address()` ๋ก ํ์ธํ๋ค.
|
|
32
|
+
- `ssl?: { pfxBytes: Uint8Array; passphrase?: string } | { pemKeyBytes: Uint8Array; certBytes: Uint8Array; caBytes?: Uint8Array; passphrase?: string } | { letsencrypt: { domains: string[]; email: string; staging?: boolean } }` โ HTTPS ์ธ์ฆ์. ํ์์ ๋ค์ด์จ ํ๋๋ก ๊ตฌ๋ถํ๋ค.
|
|
33
|
+
- `pfxBytes` ๊ฐ ์์ผ๋ฉด PFX ๋ฐฉ์(์ธ์ฆ์+ํค ๋ฒ๋ค, `passphrase` ๋ PFX ๋น๋ฐ๋ฒํธ).
|
|
34
|
+
- `pemKeyBytes`+`certBytes` ๊ฐ ์์ผ๋ฉด PEM ๋ฐฉ์(`pemKeyBytes` ๊ฐ์ธํคยท`certBytes` ์ธ์ฆ์, ์ ํ์ ์ผ๋ก `caBytes` ์ค๊ฐ CA ์ฒด์ธยท`passphrase` ์ํธํ๋ ํค ๋น๋ฐ๋ฒํธ). ๋ฐ์ดํธ๋ ๋ด๋ถ์์ `Buffer` ๋ก ๋ณํ.
|
|
35
|
+
- `letsencrypt` ๊ฐ ์์ผ๋ฉด Let's Encrypt ์๋ ๋ฐ๊ธ/๊ฐฑ์ . `domains` ์ธ์ฆ์๋ฅผ TLS-ALPN-01 ์ฑ๋ฆฐ์ง๋ก ๋ฐ๊ธํด `rootPath/.acme/`(๊ณ์ ํคยท์ธ์ฆ์ยทํค)์ ์ ์ฅํ๊ณ , ๋ง๋ฃ 30์ผ ์ ์๋ ๊ฐฑ์ ํ ๋ฌด์ค๋จ ๊ต์ฒดํ๋ค. `email` ์ LE ๊ณ์ ์ฐ๋ฝ์ฒ, `staging: true` ๋ฉด LE ์คํ
์ด์ง(๋ ์ดํธ๋ฆฌ๋ฐ ํํผ, ํ
์คํธ์ฉ)์ ์ด๋ค. ์บ์๋ ์ ํจ ์ธ์ฆ์๊ฐ ์์ผ๋ฉด ์ฆ์ ์ ์ฉํ๊ณ , ์์ผ๋ฉด ์ต์ด ๋ฐ๊ธ ์๋ฃ๊น์ง `listen()` ์ด ๋๊ธฐํ๋ฉฐ ๋ฐ๊ธ ์คํจ ์ throw ํ๋ค(`SD_ACME_DIRECTORY_URL` ํ๊ฒฝ๋ณ์๋ก ACME ๋๋ ํ ๋ฆฌ URL ์ฌ์ ์ ๊ฐ๋ฅ โ ์ฌ์ค CAยทํ
์คํธ์ฉ).
|
|
36
|
+
|
|
37
|
+
์ง์ ์(์ด๋ ๋ฐฉ์์ด๋ ) HTTPS ๋ก ๊ธฐ๋ํ๊ณ HSTSยท`crossOriginOpenerPolicy` ๋ณด์ ํค๋๊ฐ ์ผ์ง๋ค. ๋ฏธ์ง์ ์ HTTP(ํ๋ฌธ)๋ก ๋จ๊ณ `upgrade-insecure-requests` CSP ๊ฐ ํด์ ๋๋ค. ์ฌ๋ด๋ง ํ๋ฌธ์ด๋ฉด ์๋ต, ์ธ๋ถ ๋
ธ์ถ์ด๋ฉด ์ง์ .
|
|
38
|
+
|
|
39
|
+
`letsencrypt` ์ ์ (์ฝ๋ ๋ฐ, ์ด์์ ์ฑ
์):
|
|
40
|
+
- **Node 20.18.0+ ๋๋ 22.9.0+** โ ํธ๋์
ฐ์ดํฌ ์ค ์ธ์ฆ์๋ฅผ ์ฃผ์
ํ๋ `TLSSocket.setKeyCert` ๊ฐ ํ์ํ๋ค. ๋ฏธ๋ง์ด๋ฉด ๊ธฐ๋ ์ throw.
|
|
41
|
+
- TLS-ALPN-01 ์ **์์ผ๋์นด๋ ๋ถ๊ฐ** โ `domains` ๋ ์ ํํ FQDN.
|
|
42
|
+
- ๊ฒ์ฆ connection ์ด ํฌํธ 443 ์ผ๋ก ์ธ์
๋์ด ์ด ์๋ฒ์ ๋๋ฌํด์ผ ํ๋ค: ๊ณต๊ฐ DNS A ๋ ์ฝ๋ โ ์๋ฒ, ์๋จ์ L4 ํ๋ก์๊ฐ ์์ผ๋ฉด SNI ๊ธฐ์ค์ผ๋ก ์ด ์๋ฒ์ ํจ์ค์ค๋ฃจ(์: nginx `stream` + `ssl_preread`). ๋๋ฉ์ธ CAA ๊ฐ `letsencrypt.org` ๋ฅผ ํ์ฉํ๊ณ , ์๋ฒ์์ LE API ๋ก ์์๋ฐ์ด๋๊ฐ ๊ฐ๋ฅํด์ผ ํ๋ค.
|
|
43
|
+
- `auth?: { jwtSecret: string } | false` โ JWT ์ธ์ฆ ์ค์ . ๊ฐ์ฒด๋ฉด `jwtSecret` ์ผ๋ก ํ ํฐ์ ์๋ช
ยท๊ฒ์ฆํ๋ค. `false` ๋ฉด ์ธ์ฆ์ **์๋์ ์ผ๋ก ๋นํ์ฑํ**(`auth(...)` ๋ํ ๋ฉ์๋๋ ์ธ์ฆ ๊ฒ์ฌ ์คํต). `undefined`(๋ฏธ์ง์ )์ธ๋ฐ ๊ถํ ์๊ตฌ(`auth(...)` ๋ํ) ์๋น์ค๊ฐ ํ๋๋ผ๋ ๋ฑ๋ก๋ผ ์์ผ๋ฉด `listen()` ์ด throw โ ์ค์ ๋๋ฝ๊ณผ ์๋์ ๋นํ์ฑํ๋ฅผ ๊ตฌ๋ถํ๋ค.
|
|
44
|
+
- `services: ServiceDefinition[]` โ `defineService` ๋ก ๋ง๋ ์๋น์ค ์ ์ ๋ฐฐ์ด. RPC ๋ก ๋
ธ์ถํ ์๋น์ค ์ ๋ถ๋ฅผ ์ฌ๊ธฐ ๋ฑ๋กํ๋ค. ๋ผ์ฐํ
์ ์ ์์ `names` ๋งค์นญ์ผ๋ก ์ด๋ค์ง๋ค.
|
|
45
|
+
- `legacyV1Handlers?: V1RequestHandler[]` โ V1(verโ 2) ๋ ๊ฑฐ์ ํด๋ผ์ด์ธํธ์ฉ ์ปค์คํ
์์ฒญ ํธ๋ค๋ฌ(์ ํ). ์์ธํ: [v1-legacy.md](./v1-legacy.md).
|
|
30
46
|
|
|
31
47
|
`ServiceServer<TAuthInfo>` ๋ฉค๋ฒ(`EventEmitter<{ ready: void; close: void }>` ์์):
|
|
32
48
|
|
|
33
49
|
- `readonly options: ServiceServerOptions` โ ์์ฑ ์ ๋ฐ์ ์ต์
์๋ณธ.
|
|
34
|
-
- `readonly fastify: FastifyInstance` โ ๋ด๋ถ Fastify ์ธ์คํด์ค. ํฌํธ ์กฐํยท์ถ๊ฐ ๋ผ์ฐํธ ๋ฑ๋ก ๋ฑ์ ์ง์
|
|
35
|
-
- `isOpen: boolean` โ
|
|
36
|
-
- `listen(): Promise<void>` โ ํ๋ฌ๊ทธ์ธ ๋ฑ๋ก(websocket
|
|
37
|
-
- `close(): Promise<void>` โ ๋ชจ๋ WebSocket ์ข
๋ฃ ํ Fastify ์ข
๋ฃ, `"close"` ์ด๋ฒคํธ ๋ฐ์.
|
|
50
|
+
- `readonly fastify: FastifyInstance` โ ๋ด๋ถ Fastify ์ธ์คํด์ค. ์ค์ ํฌํธ ์กฐํยท์ถ๊ฐ ๋ผ์ฐํธ ๋ฑ๋ก ๋ฑ์ ์ง์ ์ ๊ทผํ๋ค.
|
|
51
|
+
- `isOpen: boolean` โ `listen()` ์ฑ๊ณต ํ `true`, `close()` ํ `false`. ์ ์ ์ข
๋ฃ ํธ๋ค๋ฌ๊ฐ ์ค๋ณต close ๋ฅผ ๋ง๋ ๋ฐ ์ด๋ค.
|
|
52
|
+
- `listen(): Promise<void>` โ ํ๋ฌ๊ทธ์ธ ๋ฑ๋ก(websocketยทhelmetยทmultipartยทstaticยทcors) โ ๋ผ์ฐํธ ๋ฐ์ธ๋ฉ โ ๋ฆฌ์จ โ ์ ์ ์ข
๋ฃ ํธ๋ค๋ฌ(`SIGINT`/`SIGTERM`, 10์ด ๋ด ๋ฏธ์ข
๋ฃ ์ ๊ฐ์ `process.exit(1)`) ๋ฑ๋ก ํ `"ready"` ์ด๋ฒคํธ ๋ฐ์. `auth` ๋ฏธ์ค์ ์ธ๋ฐ ๊ถํ ์๊ตฌ ์๋น์ค๊ฐ ์์ผ๋ฉด ์์ ์ throw.
|
|
53
|
+
- `close(): Promise<void>` โ ๋ชจ๋ WebSocket ์ฐ๊ฒฐ ์ข
๋ฃ ํ Fastify ์ข
๋ฃ, `"close"` ์ด๋ฒคํธ ๋ฐ์.
|
|
38
54
|
- `signAuthToken(payload: AuthTokenPayload<TAuthInfo>): Promise<string>` โ `auth.jwtSecret` ์ผ๋ก ํ ํฐ ์๋ช
. ์ํฌ๋ฆฟ ๋ฏธ์ค์ ์ throw.
|
|
39
55
|
- `verifyAuthToken(token: string): Promise<AuthTokenPayload<TAuthInfo>>` โ ํ ํฐ ๊ฒ์ฆยท๋์ฝ๋. ์ํฌ๋ฆฟ ๋ฏธ์ค์ ์ throw.
|
|
40
56
|
- `getEvent`/`emitEvent` โ ์๋ "์๋ฒ์ธก ์ด๋ฒคํธ ๋ฐ์" ์ฐธ์กฐ.
|
|
@@ -50,14 +66,14 @@ const server = createServiceServer<AuthInfo>({
|
|
|
50
66
|
await server.listen();
|
|
51
67
|
```
|
|
52
68
|
|
|
53
|
-
์ฃผ์: `auth` ๋ฅผ ๋ฏธ์ง์ ํ ์ฑ ๊ถํ ์๊ตฌ ์๋น์ค๋ฅผ ๋ฑ๋กํ๋ฉด `listen()` ์ด ์ฆ์ throw ํ๋ค. ์ธ์ฆ์ ๋๋ ค๋ฉด `auth: false` ๋ฅผ
|
|
69
|
+
์ฃผ์: `auth` ๋ฅผ ๋ฏธ์ง์ ํ ์ฑ ๊ถํ ์๊ตฌ ์๋น์ค๋ฅผ ๋ฑ๋กํ๋ฉด `listen()` ์ด ์ฆ์ throw ํ๋ค. ์ธ์ฆ์ ๋๋ ค๋ฉด `auth: false` ๋ฅผ ๋ช
์ํ๋ค.
|
|
54
70
|
|
|
55
71
|
### ์๋ฒ์ธก ์ด๋ฒคํธ ๋ฐ์
|
|
56
72
|
|
|
57
73
|
์๋น์ค ๋ฉ์๋ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๊ตฌ๋
์ค์ธ ํด๋ผ์ด์ธํธ์ ๋ธ๋ก๋์บ์คํธํ ๋. ์ด๋ฒคํธ ์ ์ ๊ฐ์ฒด(`@simplysm/service-common` ์ `defineEvent`)๋ ํด๋ผ์ด์ธํธยท์๋ฒ๊ฐ ๊ณต์ ํ๋ค.
|
|
58
74
|
|
|
59
|
-
- `emitEvent<TEventDef>(eventDef: TEventDef, infoSelector: (info: TEventDef["$info"]) => boolean, data: TEventDef["$data"]): Promise<void>` โ `eventDef.eventName` ์ ๊ตฌ๋
ํ ์ ํด๋ผ์ด์ธํธ ๋ฆฌ์ค๋ ์ค `infoSelector(info)` ๊ฐ `true` ์ธ ๋์์๊ฒ๋ง `data` ์ ์ก. ์ ์ฒด ์ ์ก์ `() => true`, ์ด๋ ๊ตฌ๋
์๋ ์ ๊ฑธ๋ฆฌ๋ฉด ์ ์ก ์์ฒด๊ฐ
|
|
60
|
-
- `getEvent<TEventDef>(eventDef): ServerEventProxy<TEventDef>` โ ๊ฐ์ ์ด๋ฒคํธ๋ฅผ ๋ฐ๋ณต ๋ฐ์์ํฌ ๋ ์ฐ๋ ํ๋ก์. `proxy.emit(infoSelector, data)` ๋ `emitEvent` ์
|
|
75
|
+
- `emitEvent<TEventDef>(eventDef: TEventDef, infoSelector: (info: TEventDef["$info"]) => boolean, data: TEventDef["$data"]): Promise<void>` โ `eventDef.eventName` ์ ๊ตฌ๋
ํ ์ ํด๋ผ์ด์ธํธ ๋ฆฌ์ค๋ ์ค `infoSelector(info)` ๊ฐ `true` ์ธ ๋์์๊ฒ๋ง `data` ์ ์ก. ์ ์ฒด ์ ์ก์ `() => true`, ์ด๋ ๊ตฌ๋
์๋ ์ ๊ฑธ๋ฆฌ๋ฉด ์ ์ก ์์ฒด๊ฐ ์๋ต๋๋ค.
|
|
76
|
+
- `getEvent<TEventDef>(eventDef): ServerEventProxy<TEventDef>` โ ๊ฐ์ ์ด๋ฒคํธ๋ฅผ ๋ฐ๋ณต ๋ฐ์์ํฌ ๋ ์ฐ๋ ํ๋ก์. `proxy.emit(infoSelector, data)` ๋ `emitEvent` ์ ๋์ผํ๊ฒ ๋์ํ๋ค.
|
|
61
77
|
- `ServerEventProxy<TEventDef>` โ `{ emit(infoSelector, data): Promise<void> }` ํํ. ๊ตฌ๋
(๋ฆฌ์ค๋ ๋ฑ๋ก)์ ํด๋ผ์ด์ธํธ ์ ์ฉ์ด๋ผ ์๋ฒ์๋ ๋ฐ์ ๋ฉ์๋๋ง ์๋ค.
|
|
62
78
|
|
|
63
79
|
```ts
|
|
@@ -75,14 +91,14 @@ export const OrderService = defineService("Order", (ctx) => ({
|
|
|
75
91
|
|
|
76
92
|
## JWT ์ธ์ฆ ํ ํฐ
|
|
77
93
|
|
|
78
|
-
๋ก๊ทธ์ธ ์๋น์ค ๋ฉ์๋์์ ์๊ฒฉ ํ์ธ ํ ํ ํฐ์ ๋ฐ๊ธํ๊ณ , ๋ค๋ฅธ ๋ฉ์๋์์ ํ ํฐ์ ๊ฒ์ฆํ ๋. ๋ณดํต์ `server.signAuthToken`/`server.verifyAuthToken`(์ํฌ๋ฆฟ ์๋ ์ฌ์ฉ)์ ์ฐ๊ณ , ์ํฌ๋ฆฟ์ ์ง์ ๋ค๋ฃฐ ๋๋ง ์๋ ํจ์๋ฅผ
|
|
94
|
+
๋ก๊ทธ์ธ ์๋น์ค ๋ฉ์๋์์ ์๊ฒฉ ํ์ธ ํ ํ ํฐ์ ๋ฐ๊ธํ๊ณ , ๋ค๋ฅธ ๋ฉ์๋์์ ํ ํฐ์ ๊ฒ์ฆํ ๋. ๋ณดํต์ `server.signAuthToken`/`server.verifyAuthToken`(์ํฌ๋ฆฟ ์๋ ์ฌ์ฉ)์ ์ฐ๊ณ , ์ํฌ๋ฆฟ์ ์ง์ ๋ค๋ฃฐ ๋๋ง ์๋ ํจ์๋ฅผ ํธ์ถํ๋ค.
|
|
79
95
|
|
|
80
|
-
- `AuthTokenPayload<TAuthInfo>` โ JWT ํ์ด๋ก๋. `jose` ์ `JWTPayload`(`exp
|
|
81
|
-
- `roles: string[]` โ ๊ถํ ์ญํ ๋ชฉ๋ก. `auth(["admin"], ...)` ์ ๊ถํ ๋งค์นญ
|
|
82
|
-
- `data: TAuthInfo` โ
|
|
83
|
-
- `signJwt<TAuthInfo>(jwtSecret: string, payload: AuthTokenPayload<TAuthInfo>): Promise<string>` โ HS256 ์ผ๋ก ์๋ช
. `iat` ์๋ ์ค์ ,
|
|
84
|
-
- `verifyJwt<TAuthInfo>(jwtSecret: string, token: string): Promise<AuthTokenPayload<TAuthInfo>>` โ ์๋ช
ยท๋ง๋ฃ ๊ฒ์ฆ ํ ํ์ด๋ก๋ ๋ฐํ. ๋ง๋ฃ
|
|
85
|
-
- `decodeJwt<TAuthInfo>(token: string): AuthTokenPayload<TAuthInfo>` โ ์๋ช
๊ฒ์ฆ ์์ด ํ์ด๋ก๋๋ง ๋์ฝ๋(๋๊ธฐ).
|
|
96
|
+
- `AuthTokenPayload<TAuthInfo>` โ JWT ํ์ด๋ก๋. `jose` ์ `JWTPayload`(`exp`ยท`iat` ๋ฑ)๋ฅผ ํ์ฅํ๋ฉฐ ๋ค์์ ์ถ๊ฐํ๋ค.
|
|
97
|
+
- `roles: string[]` โ ๊ถํ ์ญํ ๋ชฉ๋ก. `auth(["admin"], ...)` ์ ๊ถํ ๋งค์นญ ๋์์ผ๋ก, ์๊ตฌ ์ญํ ์ค ํ๋๋ผ๋ ์ด ๋ฐฐ์ด์ ์์ผ๋ฉด ํต๊ณผ.
|
|
98
|
+
- `data: TAuthInfo` โ ์ฑ์ด ์ ์ํ๋ ์ฌ์ฉ์ ์ ๋ณด. `ctx.authInfo` ๋ก ๋
ธ์ถ๋๋ค.
|
|
99
|
+
- `signJwt<TAuthInfo>(jwtSecret: string, payload: AuthTokenPayload<TAuthInfo>): Promise<string>` โ HS256 ์ผ๋ก ์๋ช
. `iat` ์๋ ์ค์ , ๋ง๋ฃ๋ 12์๊ฐ ๊ณ ์ .
|
|
100
|
+
- `verifyJwt<TAuthInfo>(jwtSecret: string, token: string): Promise<AuthTokenPayload<TAuthInfo>>` โ ์๋ช
ยท๋ง๋ฃ ๊ฒ์ฆ ํ ํ์ด๋ก๋ ๋ฐํ. ๋ง๋ฃ(`ERR_JWT_EXPIRED`)๋ฉด `"ํ ํฐ์ด ๋ง๋ฃ๋์์ต๋๋ค."`, ๊ทธ ์ธ ๊ฒ์ฆ ์คํจ๋ฉด `"์ ํจํ์ง ์์ ํ ํฐ์
๋๋ค."` ๋ก throw.
|
|
101
|
+
- `decodeJwt<TAuthInfo>(token: string): AuthTokenPayload<TAuthInfo>` โ ์๋ช
๊ฒ์ฆ ์์ด ํ์ด๋ก๋๋ง ๋์ฝ๋(๋๊ธฐ). ์ด๋ฏธ ๊ฒ์ฆ๋ ํ ํฐ์ ๋ด์ฉ๋ง ๋ค์ ์ฝ์ ๋ ์ฐ๊ณ , ๋ง๋ฃยท์๋ณ์กฐ ํ์ ์๋ ์ฐ์ง ๋ง ๊ฒ.
|
|
86
102
|
|
|
87
103
|
```ts
|
|
88
104
|
const AuthService = defineService("Auth", (ctx) => ({
|
|
@@ -92,23 +108,3 @@ const AuthService = defineService("Auth", (ctx) => ({
|
|
|
92
108
|
},
|
|
93
109
|
}));
|
|
94
110
|
```
|
|
95
|
-
|
|
96
|
-
## ๋ด์ฅ ์๋น์ค
|
|
97
|
-
|
|
98
|
-
์๋ฒ ์ต์
`services` ๋ฐฐ์ด์ ๊ทธ๋๋ก ์ถ๊ฐํด ์ฐ๋ ๋ฏธ๋ฆฌ ์ ์๋ ์๋น์ค. ๋ ์ด๋ฆ(๋ณ์นญ)์ผ๋ก ๋
ธ์ถ๋๋ฉฐ, ํด๋ผ์ด์ธํธ ํ์
๊ณต์ ์ฉ `*Methods` ํ์
๋ ํจ๊ป export ๋๋ค.
|
|
99
|
-
|
|
100
|
-
- `OrmService` / `OrmServiceMethods` โ `["Orm", "SdOrmService"]` ๋ ์ด๋ฆ์ผ๋ก ๋
ธ์ถ. ์ ์ฒด๊ฐ `auth(...)` ๋ํ์ด๋ผ ๋ก๊ทธ์ธ ํ์ํ๊ณ , **WebSocket ์ ์ก ์ ์ฉ**(์์ผ ๋จ์๋ก DB ์ปค๋ฅ์
์ ํ๋งํ๋ฏ๋ก HTTP ํธ์ถ ์ throw). DB ์ ์ ์ ๋ณด๋ `ctx.getConfig("orm")[configName]` ์ผ๋ก `rootPath/.config.json` ์ `orm` ์น์
์์ ์ฝ๋๋ค. ์์ผ์ด ๋ซํ๋ฉด ๊ทธ ์์ผ์ ๋ชจ๋ ์ปค๋ฅ์
์ ์๋ ์ ๋ฆฌ. ๋ฉ์๋:
|
|
101
|
-
- `getInfo(opt)` โ dialectยทdatabaseยทschema ์กฐํ(`mssql-azure` ๋ `mssql` ๋ก ์ ๊ทํ).
|
|
102
|
-
- `connect(opt)` โ ์ DB ์ฐ๊ฒฐ์ ํ์ ์ถ๊ฐํ๊ณ ์ ์ `connId` ๋ฐํ.
|
|
103
|
-
- `close(connId)` โ ํด๋น ์ฐ๊ฒฐ ์ข
๋ฃ.
|
|
104
|
-
- `beginTransaction(connId, isolationLevel?)` / `commitTransaction(connId)` / `rollbackTransaction(connId)` โ connId ๋์ ํธ๋์ญ์
์ ์ด.
|
|
105
|
-
- `executeParametrized(connId, query, params?)` โ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ SQL ์คํ.
|
|
106
|
-
- `executeDefs(connId, defs, options?)` โ `QueryDef[]` ๋ฅผ dialect ์ ๋ง์ถฐ ๋น๋ยท์คํํ๊ณ , `options[i]` ๊ฐ ์์ผ๋ฉด ๊ฒฐ๊ณผ๋ฅผ ํ์ฑยท๋ฐํ(์ ๋ถ `null` ์ด๋ฉด ์ผ๊ด ์คํ๋ง).
|
|
107
|
-
- `bulkInsert(connId, tableName, columnDefs, records)` โ ๋๋ ์ฝ์
.
|
|
108
|
-
- `AutoUpdateService` / `AutoUpdateServiceMethods` โ `["AutoUpdate", "SdAutoUpdateService"]` ๋ ์ด๋ฆ์ผ๋ก ๋
ธ์ถ. ์ธ์ฆ ๋ถํ์. ๋ฉ์๋ `getLastVersion(platform: string)` ์ `rootPath/www/<clientName>/<platform>/updates` ์์ `android` ๋ฉด `.apk`, ๊ทธ ์ธ๋ฉด `.exe` ํ์ผ ์ค semver ์ต๋ ๋ฒ์ ์ ์ฐพ์ `{ version, downloadPath }` ๋ฐํ(๋์ ์์ผ๋ฉด `undefined`).
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
services: [OrmService, AutoUpdateService, ...์ฑ์๋น์ค๋ค]
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
์ฃผ์: ๋ ๋ด์ฅ ์๋น์ค๋ ํด๋ผ์ด์ธํธ๊ฐ ์งง์ ์ด๋ฆ(`getService("Orm")`/`getService("AutoUpdate")`) ๋๋ ๋ ๊ฑฐ์ ์ด๋ฆ(`SdOrmService`/`SdAutoUpdateService`) ์ด๋ ์ชฝ์ผ๋ก๋ ํธ์ถํ ์ ์๋ค.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @simplysm/service-server โ ๋ด์ฅ ์๋น์ค
|
|
2
|
+
|
|
3
|
+
์๋ฒ ์ต์
`services` ๋ฐฐ์ด์ ๊ทธ๋๋ก ์ถ๊ฐํด ์ฐ๋ ๋ฏธ๋ฆฌ ์ ์๋ `ServiceDefinition` ๋ ๊ฐ. ๊ฐ๊ฐ ๋ ์ด๋ฆ(๋ณ์นญ)์ผ๋ก ๋
ธ์ถ๋๋ฉฐ, ํด๋ผ์ด์ธํธ ํ์
๊ณต์ ์ฉ `*Methods` ํ์
๋ ํจ๊ป export ๋๋ค. ํด๋ผ์ด์ธํธ๋ ์งง์ ์ด๋ฆ ๋๋ ๋ ๊ฑฐ์ ์ด๋ฆ ์ด๋ ์ชฝ์ผ๋ก๋ ํธ์ถํ ์ ์๋ค.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
services: [OrmService, AutoUpdateService, ...์ฑ์๋น์ค๋ค]
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## OrmService / OrmServiceMethods
|
|
10
|
+
|
|
11
|
+
`["Orm", "SdOrmService"]` ๋ ์ด๋ฆ์ผ๋ก ๋
ธ์ถ. DB ์ ์์ ์๊ฒฉ ์คํ RPC ๋ก ์ ๊ณตํ๋ ์๋น์ค๋ก, ํด๋ผ์ด์ธํธ์ ORM ์ปค๋ฅํฐ๊ฐ ํธ์ถํ๋ค.
|
|
12
|
+
|
|
13
|
+
- ์ ์ฒด๊ฐ `auth(...)` ๋ํ์ด๋ผ **๋ก๊ทธ์ธ ํ์**.
|
|
14
|
+
- **WebSocket ์ ์ก ์ ์ฉ** โ ์์ผ ๋จ์๋ก DB ์ปค๋ฅ์
์ ํ๋ง(`WeakMap<ServiceSocket, Map<connId, DbConn>>`)ํ๋ฏ๋ก, `ctx.socket` ์ด ์๋ HTTP ํธ์ถ ์ `"WebSocket ์ฐ๊ฒฐ์ด ํ์ํฉ๋๋ค..."` throw.
|
|
15
|
+
- DB ์ ์ ์ ๋ณด๋ `ctx.getConfig<...>("orm")[configName]` ์ผ๋ก `rootPath/.config.json` ์ `orm` ์น์
์์ ์ฝ๊ณ , ํธ์ถ `opt.config` ๋ก ๋ฎ์ด์ด๋ค. ์ค์ ์ด ์์ผ๋ฉด throw.
|
|
16
|
+
- ์์ผ์ด ๋ซํ๋ฉด ๊ทธ ์์ผ์ ์ด๋ฆฐ ๋ชจ๋ ์ปค๋ฅ์
์ ์๋ ์ ๋ฆฌํ๋ค.
|
|
17
|
+
|
|
18
|
+
๋ฉ์๋(`OrmServiceMethods`):
|
|
19
|
+
|
|
20
|
+
- `getInfo(opt: DbConnOptions & { configName }): Promise<{ dialect; database?; schema? }>` โ ์ ์ ์ค์ ์ dialectยทdatabaseยทschema ์กฐํ. `dialect` ๊ฐ `"mssql-azure"` ๋ฉด `"mssql"` ๋ก ์ ๊ทํํด ๋๋ ค์ค๋ค.
|
|
21
|
+
- `connect(opt: DbConnOptions & { configName }): Promise<number>` โ ์ DB ์ฐ๊ฒฐ์ ํ์ ์ถ๊ฐํ๊ณ ์ ์ `connId` ๋ฐํ. ๊ฐ์ ์์ผ์ ์ฒซ ์ฐ๊ฒฐ ์ ์์ผ `close` ํธ๋ค๋ฌ๋ฅผ ๊ฑธ์ด ์ข
๋ฃ ์ ์ ๋ฆฌํ๋๋ก ๋ฑ๋กํ๋ค.
|
|
22
|
+
- `close(connId: number): Promise<void>` โ ํด๋น ์ฐ๊ฒฐ ์ข
๋ฃ. ์ข
๋ฃ ์ค ์๋ฌ๋ ๋ฌด์(warn ๋ก๊ทธ)๋๋ค.
|
|
23
|
+
- `beginTransaction(connId: number, isolationLevel?: IsolationLevel): Promise<void>` โ ํธ๋์ญ์
์์. `isolationLevel` ๋ฏธ์ง์ ์ ๋๋ผ์ด๋ฒ ๊ธฐ๋ณธ๊ฐ.
|
|
24
|
+
- `commitTransaction(connId: number): Promise<void>` / `rollbackTransaction(connId: number): Promise<void>` โ `connId` ๋์ ํธ๋์ญ์
์ปค๋ฐยท๋กค๋ฐฑ.
|
|
25
|
+
- `executeParametrized(connId: number, query: string, params?: unknown[]): Promise<unknown[][]>` โ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ SQL ์คํ.
|
|
26
|
+
- `executeDefs(connId: number, defs: QueryDef[], options?: (ResultMeta | undefined)[]): Promise<unknown[][]>` โ `QueryDef[]` ๋ฅผ dialect ์ ๋ง์ถฐ ๋น๋ยท์คํ. `options` ๊ฐ ์ ๋ถ `null`/`undefined` ๋ฉด ์ ์ฒด๋ฅผ ํ ๋ฒ์ ์ผ๊ด ์คํ๋ง ํ๊ณ ๋น ๊ฒฐ๊ณผ๋ฅผ ๋๋ ค์ฃผ๋ฉฐ, ๊ฐ `options[i]` ๊ฐ ์์ผ๋ฉด ํด๋น ๊ฒฐ๊ณผ์
์ ํ์ฑํด ๋ฐํํ๋ค.
|
|
27
|
+
- `bulkInsert(connId: number, tableName: string, columnDefs: Record<string, ColumnMeta>, records: Record<string, unknown>[]): Promise<void>` โ ๋๋ ์ฝ์
.
|
|
28
|
+
|
|
29
|
+
## AutoUpdateService / AutoUpdateServiceMethods
|
|
30
|
+
|
|
31
|
+
`["AutoUpdate", "SdAutoUpdateService"]` ๋ ์ด๋ฆ์ผ๋ก ๋
ธ์ถ. ์ธ์ฆ ๋ถํ์. ๋ฐฐํฌ๋ ์ฑ ํด๋ผ์ด์ธํธ๊ฐ ์ต์ ์ค์น๋ณธ์ ์กฐํํ๋ ๋ฐ ์ด๋ค.
|
|
32
|
+
|
|
33
|
+
- `getLastVersion(platform: string): Promise<{ version: string; downloadPath: string } | undefined>` โ `rootPath/www/<clientName>/<platform>/updates` ๋๋ ํฐ๋ฆฌ์์ ํ๋ณด ํ์ผ์ ๊ณจ๋ผ semver ์ต๋ ๋ฒ์ ์ ์ฐพ๋๋ค. `platform === "android"` ๋ฉด `.apk`, ๊ทธ ์ธ๋ฉด `.exe` ํ์ฅ์์ ํ์ผ๋ช
์ด `^[0-9.]*$` ์ธ ๊ฒ๋ง ํ๋ณด. ๋์ ๋ฒ์ ์ด ์์ผ๋ฉด `{ version, downloadPath }`(๋ค์ด๋ก๋ ๊ฒฝ๋ก๋ `/<clientName>/<platform>/updates/<ํ์ผ>` posix ๊ฒฝ๋ก), ์์ผ๋ฉด `undefined`. `ctx.clientPath` ๊ฐ ์์ผ๋ฉด throw.
|
|
34
|
+
|
|
35
|
+
์ฃผ์: `getLastVersion` ์ verโ 2 ๋ ๊ฑฐ์ ํด๋ผ์ด์ธํธ์ `SdAutoUpdateService.getLastVersion` fallback ์ผ๋ก๋ ์๋ ์ฐ๊ฒฐ๋๋ค(๋ ๊ฑฐ์ ํ๋ฆ์ [v1-legacy.md](./v1-legacy.md) ์ฐธ์กฐ).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @simplysm/service-server โ ์๋น์ค ์์ฑ
|
|
2
2
|
|
|
3
|
-
RPC ๋ก ๋
ธ์ถํ ์๋น์ค ๋ฉ์๋๋ฅผ ์ ์ํ๊ณ , ์ปจํ
์คํธ๋ก ์ธ์ฆ ์ ๋ณดยทํด๋ผ์ด์ธํธ ์ ๋ณดยท์ค์ ์ ์ ๊ทผํ๋ฉฐ, ์ธ์ฆยท๊ถํ์ ๋ถ์ผ ๋
|
|
3
|
+
RPC ๋ก ๋
ธ์ถํ ์๋น์ค ๋ฉ์๋๋ฅผ ์ ์ํ๊ณ , ์์ฒญ ์ปจํ
์คํธ๋ก ์ธ์ฆ ์ ๋ณดยทํด๋ผ์ด์ธํธ ์ ๋ณดยท์ค์ ์ ์ ๊ทผํ๋ฉฐ, ์ธ์ฆยท๊ถํ์ ๋ถ์ผ ๋ ์ฝ๋ ๋ฌถ์. ์๋ฒ ์ต์
`services` ์ ๋ฑ๋กํ `ServiceDefinition` ์ ๋ง๋๋ ๊ฒ์ด ๋ชฉํ๋ค.
|
|
4
4
|
|
|
5
5
|
## defineService
|
|
6
6
|
|
|
@@ -8,12 +8,13 @@ RPC ๋ก ๋
ธ์ถํ ์๋น์ค ๋ฉ์๋๋ฅผ ์ ์ํ๊ณ , ์ปจํ
์คํธ๋ก ์ธ์ฆ
|
|
|
8
8
|
function defineService<TMethods extends Record<string, (...args: any[]) => any>>(
|
|
9
9
|
name: string | string[],
|
|
10
10
|
factory: (ctx: ServiceContext) => TMethods,
|
|
11
|
-
): ServiceDefinition<TMethods
|
|
11
|
+
): ServiceDefinition<TMethods>;
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
- `name: string | string[]` โ ์๋น์ค ์ด๋ฆ. ๋ฐฐ์ด์ด๋ฉด ์ฌ๋ฌ ์ด๋ฆ(๋ณ์นญ)์ผ๋ก ๋์ ๋
ธ์ถํ๋ฉฐ ์ฒซ ์์๊ฐ ๋ํ ์ด๋ฆ(`definition.name`)
|
|
15
|
-
- `factory: (ctx) => TMethods` โ **์์ฒญ๋ง๋ค ํธ์ถ**๋์ด ๋ฉ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ํฉํ ๋ฆฌ. `ctx` ๋ก ๊ทธ ์์ฒญ์ ์ธ์ฆยทํด๋ผ์ด์ธํธ ์ ๋ณด๊ฐ ๋ค์ด์ค๋ฏ๋ก ๋ฉ์๋ ์์์ `ctx.*` ๋ฅผ
|
|
16
|
-
- ๋ฐํ `TMethods` ์ ๊ฐ
|
|
14
|
+
- `name: string | string[]` โ ์๋น์ค ์ด๋ฆ. ๋ฐฐ์ด์ด๋ฉด ์ฌ๋ฌ ์ด๋ฆ(๋ณ์นญ)์ผ๋ก ๋์ ๋
ธ์ถํ๋ฉฐ ์ฒซ ์์๊ฐ ๋ํ ์ด๋ฆ(`definition.name`)์ด ๋๋ค. ๋น ๋ฐฐ์ด์ด๋ฉด throw. ํด๋ผ์ด์ธํธ๋ ์ด ์ด๋ฆ์ผ๋ก `getService("<name>")` ํธ์ถํ๋ค. ์ ยท๊ตฌ ์ด๋ฆ์ ๊ฐ์ด ๋ฐ์ผ๋ ค๋ฉด `["New", "Old"]`.
|
|
15
|
+
- `factory: (ctx) => TMethods` โ **์์ฒญ๋ง๋ค ํธ์ถ**๋์ด ๋ฉ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ํฉํ ๋ฆฌ. `ctx` ๋ก ๊ทธ ์์ฒญ์ ์ธ์ฆยทํด๋ผ์ด์ธํธ ์ ๋ณด๊ฐ ๋ค์ด์ค๋ฏ๋ก ๋ฉ์๋ ์์์ `ctx.*` ๋ฅผ ์ฐธ์กฐํ๋ค. ์์ฒญ ๊ฐ ๊ณต์ ์ํ(์ปค๋ฅ์
ํ ๋ฑ)๋ ํฉํ ๋ฆฌ ๋ฐ๊นฅ ๋ชจ๋ ์ค์ฝํ์ ๋๋ค.
|
|
16
|
+
- ๋ฐํ `TMethods` ์ ๊ฐ ๊ฐ์ด ํด๋ผ์ด์ธํธ๊ฐ ํธ์ถํ ๋ฉ์๋. ๋๊ธฐยท๋น๋๊ธฐ ๋ชจ๋ ๊ฐ๋ฅํ๋ฉฐ ๋ฐํ๊ฐ์ด ๊ทธ๋๋ก ์๋ต์ผ๋ก ์ง๋ ฌํ๋๋ค.
|
|
17
|
+
- ๋ฐํ `ServiceDefinition` ์ `authPermissions` ๋ `factory` ๊ฐ `auth(...)` ๋ํ์ด๋ฉด ๊ทธ ๊ถํ ๋ฐฐ์ด, ์๋๋ฉด `undefined` ๋ก ์๋ ์ฑ์์ง๋ค.
|
|
17
18
|
|
|
18
19
|
```ts
|
|
19
20
|
export const UserService = defineService("User", (ctx) => ({
|
|
@@ -32,11 +33,11 @@ function auth<TFn extends (...args: any[]) => any>(fn: TFn): TFn;
|
|
|
32
33
|
function auth<TFn extends (...args: any[]) => any>(permissions: string[], fn: TFn): TFn;
|
|
33
34
|
```
|
|
34
35
|
|
|
35
|
-
- `auth(fn)` โ ๋ก๊ทธ์ธ๋ง ์๊ตฌ(๊ถํ ์ญํ ๋ฌด๊ด). ํ ํฐ์ด ์์ผ๋ฉด "๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค." throw.
|
|
36
|
-
- `auth(permissions, fn)` โ `permissions: string[]` ์ ์ญํ ์ค ํ๋๋ผ๋ ํ ํฐ `roles` ์ ์์ด์ผ ํต๊ณผ. ์์ผ๋ฉด "๊ถํ์ด ๋ถ์กฑํฉ๋๋ค." throw. ๋น ๋ฐฐ์ด์ `auth(fn)` ๊ณผ ๋์ผ(๋ก๊ทธ์ธ๋ง).
|
|
37
|
-
- **์๋น์ค
|
|
38
|
-
- **๋ฉ์๋
|
|
39
|
-
- ์ ์ฉ ์ฐ์ ์์: ๋ฉ์๋ ๋ํ ๊ถํ โ ์์ผ๋ฉด ์๋น์ค ๊ถํ. ์๋ฒ ์ต์
`auth` ๊ฐ `undefined` ๋ฉด ๊ถํ ์๊ตฌ ๋ฉ์๋ ํธ์ถ ์ ์ค์ ์ค๋ฅ throw, `false` ๋ฉด ์ธ์ฆ ๊ฒ์ฌ ์์ฒด๋ฅผ
|
|
36
|
+
- `auth(fn)` โ ๋ก๊ทธ์ธ๋ง ์๊ตฌ(๊ถํ ์ญํ ๋ฌด๊ด). ํ ํฐ์ด ์์ผ๋ฉด `"๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค."` throw.
|
|
37
|
+
- `auth(permissions, fn)` โ `permissions: string[]` ์ ์ญํ ์ค ํ๋๋ผ๋ ํ ํฐ `roles` ์ ์์ด์ผ ํต๊ณผ. ์์ผ๋ฉด `"๊ถํ์ด ๋ถ์กฑํฉ๋๋ค."` throw. ๋น ๋ฐฐ์ด์ `auth(fn)` ๊ณผ ๋์ผ(๋ก๊ทธ์ธ๋ง).
|
|
38
|
+
- **์๋น์ค ์์ค ์ ์ฉ**: `defineService("User", auth((ctx) => ({ ... })))` โ ๊ทธ ์๋น์ค์ ๋ชจ๋ ๋ฉ์๋์ ์ ์ฉ. `defineService` ๊ฐ ๊ถํ์ `authPermissions` ๋ก ์ถ์ถํ๋ค.
|
|
39
|
+
- **๋ฉ์๋ ์์ค ์ ์ฉ**: ๋ฐํ ๊ฐ์ฒด ์ ๊ฐ๋ณ ๋ฉ์๋๋ฅผ `auth(...)` ๋ก ๊ฐ์ผ๋ค. ๋ฉ์๋ ์์ค ๊ถํ์ด ์๋น์ค ์์ค๋ณด๋ค ์ฐ์ ํ๋ค.
|
|
40
|
+
- ์ ์ฉ ์ฐ์ ์์: ๋ฉ์๋ ๋ํ ๊ถํ โ ์์ผ๋ฉด ์๋น์ค ๊ถํ. ์๋ฒ ์ต์
`auth` ๊ฐ `undefined` ๋ฉด ๊ถํ ์๊ตฌ ๋ฉ์๋ ํธ์ถ ์ ์ค์ ์ค๋ฅ throw, `false` ๋ฉด ์ธ์ฆ ๊ฒ์ฌ ์์ฒด๋ฅผ ์คํตํ๋ค.
|
|
40
41
|
|
|
41
42
|
```ts
|
|
42
43
|
export const AdminService = defineService("Admin", auth((ctx) => ({
|
|
@@ -45,18 +46,18 @@ export const AdminService = defineService("Admin", auth((ctx) => ({
|
|
|
45
46
|
})));
|
|
46
47
|
```
|
|
47
48
|
|
|
48
|
-
## ServiceContext
|
|
49
|
+
## ServiceContext / createServiceContext
|
|
49
50
|
|
|
50
|
-
`factory` ๊ฐ ์์ฒญ๋ง๋ค ๋ฐ๋ ์ปจํ
์คํธ. ๋ฉ์๋ ์์์ ์ธ์ฆยทํด๋ผ์ด์ธํธยท์ค์ ยท์๋ฒ์ ์ ๊ทผํ๋
|
|
51
|
+
`factory` ๊ฐ ์์ฒญ๋ง๋ค ๋ฐ๋ ์ปจํ
์คํธ. ๋ฉ์๋ ์์์ ์ธ์ฆยทํด๋ผ์ด์ธํธยท์ค์ ยท์๋ฒ์ ์ ๊ทผํ๋ ํต๋ก๋ค. `createServiceContext(server, socket?, http?, legacy?)` ๊ฐ ์์ฑํ๋, ์ผ๋ฐ ์์ฑ์์๋ `factory` ์ ์ธ์๋ก ์๋ ์ฃผ์
๋๋ฏ๋ก ์ง์ ๋ง๋ค ์ผ์ ํ
์คํธ๋ฟ์ด๋ค.
|
|
51
52
|
|
|
52
53
|
- `server: ServiceServer<TAuthInfo>` โ ์๋ฒ ์ธ์คํด์ค. `ctx.server.emitEvent(...)` ๋ก ์ด๋ฒคํธ ๋ฐ์, `ctx.server.signAuthToken(...)` ๋ก ํ ํฐ ๋ฐ๊ธ.
|
|
53
|
-
- `socket?: ServiceSocket` โ WebSocket ์์ฒญ์ผ ๋๋ง ์กด์ฌํ๋ ์์ผ. HTTP ์์ฒญ์ด๋ฉด `undefined`(
|
|
54
|
+
- `socket?: ServiceSocket` โ WebSocket ์์ฒญ์ผ ๋๋ง ์กด์ฌํ๋ ์์ผ. HTTP ์์ฒญ์ด๋ฉด `undefined`(์์ผ์ด ํ์ํ ๊ธฐ๋ฅ์ ์กด์ฌ ๊ฒ์ฌ ํ์).
|
|
54
55
|
- `http?: { clientName: string; authTokenPayload?: AuthTokenPayload<TAuthInfo> }` โ HTTP ์์ฒญ์ผ ๋๋ง ์กด์ฌ.
|
|
55
56
|
- `legacy?: { clientName?: string }` โ V1 ๋ ๊ฑฐ์ ์ฐ๊ฒฐ ์ปจํ
์คํธ(์๋์
๋ฐ์ดํธ ์ ์ฉ).
|
|
56
|
-
- `get authInfo(): TAuthInfo | undefined` โ ๊ฒ์ฆ๋ ํ ํฐ์ `data` ํ์ด๋ก๋(์์ผโHTTP
|
|
57
|
-
- `get clientName(): string | undefined` โ ์์ฒญ ํด๋ผ์ด์ธํธ ์ด๋ฆ(์์ผโHTTPโ๋ ๊ฑฐ์ ์ ์ฐ์ ). ๋น ๋ฌธ์์ดยท`..`ยท์ฌ๋์(
|
|
58
|
-
- `get clientPath(): string | undefined` โ `rootPath/www/<clientName>` ์ ๋๊ฒฝ๋ก. clientName ์์ผ๋ฉด `undefined`.
|
|
59
|
-
- `getConfig<T>(section: string): Promise<T>` โ `rootPath/.config.json` ๋ฃจํธ ์ค์ ์ ํด๋ผ์ด์ธํธ๋ณ `www/<clientName>/.config.json` ์ ๋จธ์งํ ๋ค `section` ํค ๊ฐ์ ๋ฐํ. ์น์
์ด ์์ผ๋ฉด throw. ์ค์ ํ์ผ์ ๋ณ๊ฒฝ ์ ์๋
|
|
57
|
+
- `get authInfo(): TAuthInfo | undefined` โ ๊ฒ์ฆ๋ ํ ํฐ์ `data` ํ์ด๋ก๋(์์ผโHTTP ์์ผ๋ก ์กฐํ). ๋น๋ก๊ทธ์ธ ์์ฒญ์ด๋ฉด `undefined` โ ๊ฒฐ์ธก์ ๊ทธ๋๋ก ๋
ธ์ถํ๋ฏ๋ก ๋ฐ๋ ์ชฝ๋ ์ต์
๋๋ก ๋ค๋ฃฌ๋ค.
|
|
58
|
+
- `get clientName(): string | undefined` โ ์์ฒญ ํด๋ผ์ด์ธํธ ์ด๋ฆ(์์ผโHTTPโ๋ ๊ฑฐ์ ์ ์ฐ์ ). ๋น ๋ฌธ์์ดยท`..`ยท์ฌ๋์(`/`ยท`\`) ํฌํจ ๋ฑ ๊ฒฝ๋ก ํ์ถ ์ํ ๊ฐ์ด๋ฉด throw.
|
|
59
|
+
- `get clientPath(): string | undefined` โ `rootPath/www/<clientName>` ์ ๋๊ฒฝ๋ก. `clientName` ์ด ์์ผ๋ฉด `undefined`.
|
|
60
|
+
- `getConfig<T>(section: string): Promise<T>` โ `rootPath/.config.json` ๋ฃจํธ ์ค์ ์ ํด๋ผ์ด์ธํธ๋ณ `www/<clientName>/.config.json` ์ ๋จธ์งํ ๋ค `section` ํค ๊ฐ์ ๋ฐํ. ์น์
์ด ์์ผ๋ฉด throw. ์ค์ ํ์ผ์ ๋ณ๊ฒฝ ์ ์๋ ๋ฆฌ๋ก๋๋๋ค(ํ์ผ ์์ฒ + ์บ์).
|
|
60
61
|
|
|
61
62
|
```ts
|
|
62
63
|
export const ReportService = defineService("Report", auth((ctx) => ({
|
|
@@ -68,7 +69,7 @@ export const ReportService = defineService("Report", auth((ctx) => ({
|
|
|
68
69
|
## ServiceDefinition / ServiceMethods / getServiceAuthPermissions
|
|
69
70
|
|
|
70
71
|
- `ServiceDefinition<TMethods>` โ `defineService` ๋ฐํ ํ์
. `{ name: string; names: string[]; factory: (ctx) => TMethods; authPermissions?: string[] }`. `name` ์ ๋ํ ์ด๋ฆ, `names` ๋ ๋ณ์นญ ์ ์ฒด, `authPermissions` ๋ ์๋น์ค ์์ค `auth` ๊ถํ(์์ผ๋ฉด `undefined`).
|
|
71
|
-
- `type ServiceMethods<TDefinition>` โ `ServiceDefinition<M>` ์์ ๋ฉ์๋ ์๊ทธ๋์ฒ `M` ๋ง ์ถ์ถํ๋ ํ์
์ ํธ. ํด๋ผ์ด์ธํธ์ ์๋น์ค ํ์
์ ๊ณต์ ํ๋ ค๊ณ common ํจํค์ง์ `export type XxxServiceMethods = ServiceMethods<typeof XxxService>` ๋ก ์ฌ๋
ธ์ถํ๊ณ , ํด๋ผ์ด์ธํธ๋ `client.getService<XxxServiceMethods>("Xxx")` ๋ก
|
|
72
|
-
- `getServiceAuthPermissions(fn: Function): string[] | undefined` โ `auth(...)` ๋ก ๋ํ๋ ํจ์์์ ๊ถํ ๋ฐฐ์ด์
|
|
72
|
+
- `type ServiceMethods<TDefinition>` โ `ServiceDefinition<M>` ์์ ๋ฉ์๋ ์๊ทธ๋์ฒ `M` ๋ง ์ถ์ถํ๋ ํ์
์ ํธ. ํด๋ผ์ด์ธํธ์ ์๋น์ค ํ์
์ ๊ณต์ ํ๋ ค๊ณ common ํจํค์ง์ `export type XxxServiceMethods = ServiceMethods<typeof XxxService>` ๋ก ์ฌ๋
ธ์ถํ๊ณ , ํด๋ผ์ด์ธํธ๋ `client.getService<XxxServiceMethods>("Xxx")` ๋ก ์ด๋ค.
|
|
73
|
+
- `getServiceAuthPermissions(fn: Function): string[] | undefined` โ `auth(...)` ๋ก ๋ํ๋ ํจ์์์ ๊ถํ ๋ฐฐ์ด์ ์ฝ๋๋ค. ๋ํ ์ ๋์ผ๋ฉด `undefined`. ๋ด๋ถ ์คํ๊ธฐยท์ปค์คํ
์ ์ก์์๋ง ํ์ํ๊ณ ์ผ๋ฐ ์์ฑ์์๋ ์ฐ์ง ์๋๋ค.
|
|
73
74
|
|
|
74
75
|
์ฃผ์: ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๋ ์๋น์ค ์ด๋ฆ ๋ฌธ์์ด๊ณผ `ServiceMethods` ํ์
์ ๋จ์ผ ์์ค(`defineService` ์ด๋ฆ / `typeof XxxService`)๋ฅผ ๋ฐ๋ฅธ๋ค. ํธ์ถ๋ถ์์ ์ด๋ฆยท์ ๋ค๋ฆญ์ ์ค๋ณต ์ ์ํ์ง ๋ง ๊ฒ.
|
|
@@ -14,22 +14,20 @@ function executeServiceMethod(
|
|
|
14
14
|
socket?: ServiceSocket;
|
|
15
15
|
http?: { clientName: string; authTokenPayload?: AuthTokenPayload };
|
|
16
16
|
},
|
|
17
|
-
): Promise<unknown
|
|
17
|
+
): Promise<unknown>;
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
์์ฒญ 1๊ฑด์ ์ค์ ์๋น์ค ๋ฉ์๋๋ก ๋ผ์ฐํ
ยท์คํํ๋ ํต์ฌ ๊ฒ์ดํธํคํผ. WebSocket
|
|
20
|
+
์์ฒญ 1๊ฑด์ ์ค์ ์๋น์ค ๋ฉ์๋๋ก ๋ผ์ฐํ
ยท์คํํ๋ ํต์ฌ ๊ฒ์ดํธํคํผ. WebSocketยทHTTP ํธ๋ค๋ฌ๊ฐ ๋ชจ๋ ์ด ํจ์๋ก ์๋ ดํ๋ค.
|
|
21
21
|
|
|
22
|
-
- `serviceName` / `methodName` โ `server.options.services` ์ `names` ๋งค์นญ์ผ๋ก ์๋น์ค๋ฅผ, ๊ทธ ํฉํ ๋ฆฌ ์ฐ์ถ ๊ฐ์ฒด์์ ๋ฉ์๋๋ฅผ
|
|
23
|
-
- `params: unknown[]` โ ๋ฉ์๋ ์ธ์ ๋ฐฐ์ด. ์คํ๋ ๋๋์ด ๋ฉ์๋์
|
|
24
|
-
- `socket?` / `http?` โ ๋ ์ค ํ๋๋ก ์์ฒญ
|
|
25
|
-
-
|
|
22
|
+
- `serviceName` / `methodName` โ `server.options.services` ์ `names` ๋งค์นญ์ผ๋ก ์๋น์ค๋ฅผ, ๊ทธ ํฉํ ๋ฆฌ ์ฐ์ถ ๊ฐ์ฒด์์ ๋ฉ์๋๋ฅผ ์ฐพ๋๋ค. ์์ผ๋ฉด throw.
|
|
23
|
+
- `params: unknown[]` โ ๋ฉ์๋ ์ธ์ ๋ฐฐ์ด. ์คํ๋ ๋๋์ด ๋ฉ์๋์ ์ ๋ฌ๋๋ค.
|
|
24
|
+
- `socket?` / `http?` โ ๋ ์ค ํ๋๋ก ์์ฒญ ์ถ์ฒ๋ฅผ ์ ๋ฌ. `clientName` ์ `..`ยท์ฌ๋์(`/`ยท`\`)๊ฐ ์์ผ๋ฉด ๋ณด์ ์ฐจ๋จ throw.
|
|
25
|
+
- ๋์ ์์: ์ปจํ
์คํธ ์์ฑ โ ํฉํ ๋ฆฌ ํธ์ถ โ ๋ฉ์๋ ์กฐํ โ ์ธ์ฆยท๊ถํ ๊ฒ์ฌ(`auth` ๋ํ ๊ถํ ๊ธฐ์ค) โ ์คํ ํ ๋ฐํ๊ฐ ๋ฐํ. `auth: false` ๋ฉด ์ธ์ฆ ์คํต, `auth` ๋ฏธ์ค์ ์ธ๋ฐ ๊ถํ ์๊ตฌ ๋ฉ์๋๋ฉด ์ค์ ์ค๋ฅ throw.
|
|
26
26
|
|
|
27
27
|
## createServiceContext
|
|
28
28
|
|
|
29
29
|
```ts
|
|
30
|
-
function createServiceContext<TAuthInfo>(
|
|
31
|
-
server, socket?, http?, legacy?,
|
|
32
|
-
): ServiceContext<TAuthInfo>
|
|
30
|
+
function createServiceContext<TAuthInfo>(server, socket?, http?, legacy?): ServiceContext<TAuthInfo>;
|
|
33
31
|
```
|
|
34
32
|
|
|
35
33
|
`ServiceContext`(์ธ์ฆยทํด๋ผ์ด์ธํธยท์ค์ ์ ๊ทผ์) ์ธ์คํด์ค๋ฅผ ๋ง๋ ๋ค.
|
|
@@ -39,23 +37,23 @@ function createServiceContext<TAuthInfo>(
|
|
|
39
37
|
- `http?: { clientName; authTokenPayload? }` โ HTTP ์์ฒญ ์ถ์ฒ.
|
|
40
38
|
- `legacy?: { clientName? }` โ V1 ๋ ๊ฑฐ์ ์ถ์ฒ(`clientName` ๋ง).
|
|
41
39
|
|
|
42
|
-
์ปจํ
์คํธ ํ๋ ์๋ฏธ๋ [service-authoring.md](./service-authoring.md) ์ ServiceContext ์ ์ฐธ์กฐ. ํ
์คํธ์์ ์ปจํ
์คํธ๋ฅผ ์ง์ ๋ง๋ค์ด ์๋น์ค ๋ฉ์๋๋ฅผ ๋จ์ ํธ์ถํ ๋
|
|
40
|
+
์ปจํ
์คํธ ํ๋ ์๋ฏธ๋ [service-authoring.md](./service-authoring.md) ์ ServiceContext ์ ์ฐธ์กฐ. ํ
์คํธ์์ ์ปจํ
์คํธ๋ฅผ ์ง์ ๋ง๋ค์ด ์๋น์ค ๋ฉ์๋๋ฅผ ๋จ์ ํธ์ถํ ๋ ์ ์ฉํ๋ค.
|
|
43
41
|
|
|
44
42
|
## ServiceSocket / createServiceSocket
|
|
45
43
|
|
|
46
|
-
๋จ์ผ WebSocket ์ฐ๊ฒฐ์ ๊ฐ์ธ ํ๋กํ ์ฝ ์ธ์ฝ๋ฉยทping/pong ์ฐ๊ฒฐ ์ ์งยท์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ์ ์ ๋ด๋นํ๋ ์ธํฐํ์ด์ค. `createServiceSocket(socket, clientId, clientName, connReq)` ๋ก
|
|
44
|
+
๋จ์ผ WebSocket ์ฐ๊ฒฐ์ ๊ฐ์ธ ํ๋กํ ์ฝ ์ธ์ฝ๋ฉยทping/pong ์ฐ๊ฒฐ ์ ์งยท์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ์ ์ ๋ด๋นํ๋ ์ธํฐํ์ด์ค. `createServiceSocket(socket, clientId, clientName, connReq)` ๋ก ์์ฑํ๋ค.
|
|
47
45
|
|
|
48
46
|
- `readonly connectedAtDateTime: DateTime` โ ์ฐ๊ฒฐ ์ฑ๋ฆฝ ์๊ฐ.
|
|
49
47
|
- `readonly clientName: string` โ ์ฐ๊ฒฐ ์ ๋ฐ์ ํด๋ผ์ด์ธํธ ์ด๋ฆ.
|
|
50
48
|
- `readonly connReq: FastifyRequest` โ ์๋ณธ ์ฐ๊ฒฐ ์์ฒญ(์๊ฒฉ ์ฃผ์ ๋ฑ).
|
|
51
49
|
- `authTokenPayload?: AuthTokenPayload` โ ์์ผ `auth` ๋ฉ์์ง๋ก ๊ฒ์ฆ๋ ํ ํฐ. ์ดํ ๊ทธ ์์ผ ์์ฒญ์ `ctx.authInfo` ์ถ์ฒ(set ์ผ๋ก ๊ฐฑ์ ).
|
|
52
50
|
- `close(): void` โ ์์ผ ์ฆ์ ์ข
๋ฃ(terminate).
|
|
53
|
-
- `send(uuid, msg): Promise<number>` โ ์๋ฒ ๋ฉ์์ง๋ฅผ ํ๋กํ ์ฝ๋ก ์ธ์ฝ๋ฉํด
|
|
54
|
-
- `addListener(key, eventName, info): void` โ ์ด๋ฒคํธ ๊ตฌ๋
๋ฑ๋ก. `key`
|
|
51
|
+
- `send(uuid, msg): Promise<number>` โ ์๋ฒ ๋ฉ์์ง๋ฅผ ํ๋กํ ์ฝ๋ก ์ธ์ฝ๋ฉํด ์ ์กํ๊ณ ๋ณด๋ธ ๋ฐ์ดํธ ์ ๋ฐํ(์์ผ ๋ฏธ๊ฐ๋ฐฉ์ด๋ฉด `0`).
|
|
52
|
+
- `addListener(key, eventName, info): void` โ ์ด๋ฒคํธ ๊ตฌ๋
๋ฑ๋ก. `key` ๋ ๊ตฌ๋
์๋ณ์, `info` ๋ selector ๋งค์นญ์ฉ ๋ฉํ.
|
|
55
53
|
- `removeListener(key): void` โ `key` ๋ก ๊ตฌ๋
1๊ฑด ํด์ .
|
|
56
|
-
- `getEventListeners(eventName): { key
|
|
54
|
+
- `getEventListeners(eventName): { key; info }[]` โ ํด๋น ์ด๋ฒคํธ์ ๊ตฌ๋
๋ชฉ๋ก ์กฐํ.
|
|
57
55
|
- `filterEventTargetKeys(targetKeys): string[]` โ ์ฃผ์ด์ง ํค ์ค ์ด ์์ผ์ ์กด์ฌํ๋ ๊ฒ๋ง ๋ฐํ.
|
|
58
|
-
- `on("error" | "close" | "message", handler): void` โ ์์ผ ์ด๋ฒคํธ ํํน. 5์ด
|
|
56
|
+
- `on("error" | "close" | "message", handler): void` โ ์์ผ ์ด๋ฒคํธ ํํน. 5์ด ์ฃผ๊ธฐ๋ก ping ํ๊ณ pong ๋ฏธ์์ ์ ์๋ terminate ํ๋ค.
|
|
59
57
|
|
|
60
58
|
## WebSocketHandler / createWebSocketHandler
|
|
61
59
|
|
|
@@ -63,36 +61,36 @@ function createServiceContext<TAuthInfo>(
|
|
|
63
61
|
function createWebSocketHandler(
|
|
64
62
|
runMethod: (def) => Promise<unknown>,
|
|
65
63
|
jwtSecret: string | undefined,
|
|
66
|
-
): WebSocketHandler
|
|
64
|
+
): WebSocketHandler;
|
|
67
65
|
```
|
|
68
66
|
|
|
69
67
|
์ฌ๋ฌ `ServiceSocket` ์ `clientId` ๋ก ๊ด๋ฆฌํ๊ณ , ํด๋ผ์ด์ธํธ ๋ฉ์์ง๋ฅผ `runMethod`(๋ณดํต `executeServiceMethod` ๋ฐ์ธ๋ฉ)๋ก ๋ผ์ฐํ
ํ๋ฉฐ, ์ด๋ฒคํธ๋ฅผ ๋ธ๋ก๋์บ์คํธํ๋ค.
|
|
70
68
|
|
|
71
|
-
- `addSocket(socket, clientId, clientName, connReq): void` โ ์ฐ๊ฒฐ ๋ฑ๋ก. ๊ฐ์ `clientId` ์ ๊ธฐ์กด ์ฐ๊ฒฐ์ ๋ซ๊ณ
|
|
69
|
+
- `addSocket(socket, clientId, clientName, connReq): void` โ ์ฐ๊ฒฐ ๋ฑ๋ก. ๊ฐ์ `clientId` ์ ๊ธฐ์กด ์ฐ๊ฒฐ์ ๋ซ๊ณ ๊ต์ฒดํ๋ค. ์์ฑ ์ค ์์ธ ์ ์์ผ terminate.
|
|
72
70
|
- `closeAll(): void` โ ๋ชจ๋ ์ฐ๊ฒฐ ์ข
๋ฃ(์๋ฒ `close()` ์ ํธ์ถ).
|
|
73
71
|
- `emit<TEventDef>(eventName, infoSelector, data): Promise<void>` โ ์ ์์ผ์ ํด๋น ์ด๋ฒคํธ ๊ตฌ๋
์ค `infoSelector(info)` ๊ฐ `true` ์ธ ํค์๊ฒ๋ง `evt:on` ๋ฉ์์ง ์ ์ก. `ServiceServer.emitEvent` ์ ์ค์ ๊ตฌํ.
|
|
74
|
-
- ์ฒ๋ฆฌํ๋ ํด๋ผ์ด์ธํธ ๋ฉ์์ง ์ข
๋ฅ: `"<service>.<method>"`(RPC ํธ์ถ), `evt:add
|
|
72
|
+
- ์ฒ๋ฆฌํ๋ ํด๋ผ์ด์ธํธ ๋ฉ์์ง ์ข
๋ฅ: `"<service>.<method>"`(RPC ํธ์ถ), `evt:add`ยท`evt:remove`ยท`evt:gets`ยท`evt:emit`(์ด๋ฒคํธ ๊ตฌ๋
ยทํด์ ยท์กฐํยท๋ฐ์), `auth`(์์ผ ํ ํฐ ๊ฒ์ฆ). ๊ทธ ์ธ๋ `BAD_MESSAGE` ์๋ฌ ์๋ต. ์ฒ๋ฆฌ ์ค ์์ธ๋ `INTERNAL_ERROR` ์๋ต์ด๋ฉฐ, `DEV` ํ๊ฒฝ์์๋ง ์๋ฌ ์คํ์ ํฌํจํ๋ค.
|
|
75
73
|
|
|
76
74
|
## HTTP / ์ ์ / ์
๋ก๋ ํธ๋ค๋ฌ
|
|
77
75
|
|
|
78
|
-
`fastify` ๋ผ์ฐํธ์ ์ง์ ๋ฌผ๋ฆฌ๋ ์ ์์ค ํจ์๋ค. ์ปค์คํ
๋ผ์ฐํธ๋ฅผ ์งค ๋๋ง ์ง์
|
|
76
|
+
`fastify` ๋ผ์ฐํธ์ ์ง์ ๋ฌผ๋ฆฌ๋ ์ ์์ค ํจ์๋ค. ์ปค์คํ
๋ผ์ฐํธ๋ฅผ ์งค ๋๋ง ์ง์ ์ฌ์ฉํ๋ค.
|
|
79
77
|
|
|
80
|
-
- `handleHttpRequest(req, reply, jwtSecret, runMethod)` โ `/api/:service/:method` ์ฒ๋ฆฌ. `x-sd-client-name` ํค๋ ํ์, `Authorization: Bearer <token>` ๊ฒ์ฆ(์คํจ ์ 401). GET ์ `?json=` ์ฟผ๋ฆฌ, POST ๋ ๋ฐฐ์ด ๋ณธ๋ฌธ์์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ `runMethod`
|
|
81
|
-
- `handleUpload(req, reply, rootPath, jwtSecret)` โ `/upload` multipart ์ฒ๋ฆฌ. multipart ์๋๋ฉด 400, ์ธ์ฆ ํ ํฐ ํ์(์๊ฑฐ๋ ๋ฌดํจ๋ฉด 401). ํ์ผ์ `rootPath/www/uploads/<uuid><ext>` ๋ก ์ ์ฅํ๊ณ `ServiceUploadResult[]`(`{ path, filename, size }`) ๋ฐํ. ๋์ค
|
|
78
|
+
- `handleHttpRequest(req, reply, jwtSecret, runMethod)` โ `/api/:service/:method` ์ฒ๋ฆฌ. `x-sd-client-name` ํค๋ ํ์, `Authorization: Bearer <token>` ๊ฒ์ฆ(์คํจ ์ 401). GET ์ `?json=` ์ฟผ๋ฆฌ, POST ๋ ๋ฐฐ์ด ๋ณธ๋ฌธ์์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ `runMethod` ๋ฅผ ์คํํ๋ค. ๋ณธ๋ฌธ์ด ๋ฐฐ์ด์ด ์๋๋ฉด 400, ๊ทธ ์ธ HTTP ๋ฉ์๋๋ 405.
|
|
79
|
+
- `handleUpload(req, reply, rootPath, jwtSecret)` โ `/upload` multipart ์ฒ๋ฆฌ. multipart ๊ฐ ์๋๋ฉด 400, ์ธ์ฆ ํ ํฐ ํ์(์๊ฑฐ๋ ๋ฌดํจ๋ฉด 401). ํ์ผ์ `rootPath/www/uploads/<uuid><ext>` ๋ก ์ ์ฅํ๊ณ `ServiceUploadResult[]`(`{ path, filename, size }`) ๋ฐํ. ๋์ค ์คํจํ๋ฉด ๊ทธ ์์ฒญ์์ ์ ์ฅํ ํ์ผ์ ๋ชจ๋ ๋กค๋ฐฑ ์ญ์ ํ 500.
|
|
82
80
|
- `handleStaticFile(req, reply, rootPath, urlPath)` โ `rootPath/www` ํ์ ์ ์ ํ์ผ ์ ์ก. `www` ๋ฐ ๊ฒฝ๋ก๋ ์ฐจ๋จ(throw), ๋๋ ํฐ๋ฆฌ๋ฉด ์ฌ๋์ ๋ฆฌ๋ค์ด๋ ํธ ํ `index.html`, `.` ์ผ๋ก ์์ํ๋ ์จ๊น ํ์ผ์ 403, ๋ฏธ์กด์ฌ๋ 404, ๊ทธ ์ธ ์ ์ก ์คํจ๋ 500 HTML ์๋ต. SPA ํด๋ฐฑ: ๋ฏธ์กด์ฌ + ํ์ฅ์ ์๋ ํ์ด์ง ์์ฒญ์ด๋ฉด `www` ๋ฃจํธ ๋ฐฉํฅ์ผ๋ก ๊ฐ์ฅ ๊ฐ๊น์ด `index.csr.html`(SSG ํด๋ผ์ด์ธํธ์ SPA ์
ธ)์ ์ฐพ์ ๋ฐํ โ ์
ธ ํ์ผ์ด ์๋ ๊ธฐ์กด ํด๋ผ์ด์ธํธ๋ ๊ทธ๋๋ก 404.
|
|
83
81
|
|
|
84
82
|
## ServerProtocolWrapper / createServerProtocolWrapper
|
|
85
83
|
|
|
86
|
-
๋ฉ์์ง
|
|
84
|
+
๋ฉ์์ง ์ธ์ฝ๋ฉยท๋์ฝ๋ฉ์ ํฌ๊ธฐยท๋ด์ฉ์ ๋ฐ๋ผ worker ์ค๋ ๋์ ๋ฉ์ธ ์ค๋ ๋๋ก ์๋ ๋ถ๋ฐฐํ๋ ๋ํผ. `createServerProtocolWrapper()` ๋ก ์์ฑํ๋ค(worker ๋ ์ง์ฐ ์ฑ๊ธํด์ด๋ผ ์์ผ ๊ฐ ๊ณต์ ).
|
|
87
85
|
|
|
88
|
-
- `encode(uuid, message): Promise<{ chunks: Bytes[]; totalSize: number }>` โ `body` ์ `Uint8Array` ๊ฐ ์์ผ๋ฉด(
|
|
89
|
-
- `decode(bytes): Promise<ServiceMessageDecodeResult<ServiceMessage>>` โ ์ฒญํฌ ์ฌ์กฐ๋ฆฝ(stateful)์ ํญ์ ๋ฉ์ธ ์ค๋ ๋ ๋จ์ผ
|
|
86
|
+
- `encode(uuid, message): Promise<{ chunks: Bytes[]; totalSize: number }>` โ `body` ์ `Uint8Array` ๊ฐ ์์ผ๋ฉด(๋จ์ผ์ด๊ฑฐ๋ ๋ฐฐ์ด ์์ ์ค ํ๋๋ผ๋) worker, ์๋๋ฉด ๋ฉ์ธ ์ค๋ ๋์์ ์ธ์ฝ๋ฉ.
|
|
87
|
+
- `decode(bytes): Promise<ServiceMessageDecodeResult<ServiceMessage>>` โ ์ฒญํฌ ์ฌ์กฐ๋ฆฝ(stateful)์ ํญ์ ๋ฉ์ธ ์ค๋ ๋ ๋จ์ผ ๋์ ๊ธฐ์์ ์ํํ๊ณ , ์ฌ์กฐ๋ฆฝ ์๋ฃ ํ 30KB ์ด๊ณผ JSON ํ์ฑ(stateless)๋ง worker ์ ์์. ์งํ ์ค์ด๋ฉด `{ type: "progress" }`, ์๋ฃ๋ฉด `{ type: "complete", uuid, message }`.
|
|
90
88
|
- `dispose(): void` โ ํ๋กํ ์ฝ ๋ฆฌ์์ค ํด์ .
|
|
91
89
|
|
|
92
90
|
## getConfig
|
|
93
91
|
|
|
94
92
|
```ts
|
|
95
|
-
function getConfig<TConfig>(filePath: string): Promise<TConfig | undefined
|
|
93
|
+
function getConfig<TConfig>(filePath: string): Promise<TConfig | undefined>;
|
|
96
94
|
```
|
|
97
95
|
|
|
98
96
|
`filePath` JSON ์ค์ ์ ์ฝ์ด ์บ์ยทํ์ผ์์นํ๋ค. `ServiceContext.getConfig` ์ ๋ด๋ถ ๊ตฌํ. ์บ์ ํํธ ์ ์ฆ์ ๋ฐํ(์ ๊ทผ ์ ๋ง๋ฃ ์๊ฐ ๊ฐฑ์ ), ํ์ผ ๋ณ๊ฒฝ ์ ์๋ ๋ฆฌ๋ก๋, 1์๊ฐ ๋ฌด์ ๊ทผ ์ ์บ์ยท์์ฒ GC. ํ์ผ์ด ์์ผ๋ฉด `undefined`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @simplysm/service-server โ V1 ๋ ๊ฑฐ์ ์ง์
|
|
2
2
|
|
|
3
|
-
`ver !== "2"`(๊ตฌ๋ฒ์ ) WebSocket ํด๋ผ์ด์ธํธ๋ฅผ ๋ฐ๊ธฐ ์ํ ๋ ๊ฑฐ์ ํธ๋ค๋ฌ. ์ฃผ๋ก ๊ตฌ๋ฒ์ ์ฑ์ ์๋์
๋ฐ์ดํธ(`SdAutoUpdateService.getLastVersion`) ์์ฒญ์ ์ฒ๋ฆฌํ๋ค. `ServiceServer` ๋ ver=2 ๊ฐ ์๋ ์ฐ๊ฒฐ์ ์๋์ผ๋ก ์ด ํธ๋ค๋ฌ๋ก
|
|
3
|
+
`ver !== "2"`(๊ตฌ๋ฒ์ ) WebSocket ํด๋ผ์ด์ธํธ๋ฅผ ๋ฐ๊ธฐ ์ํ ๋ ๊ฑฐ์ ํธ๋ค๋ฌ. ์ฃผ๋ก ๊ตฌ๋ฒ์ ์ฑ์ ์๋์
๋ฐ์ดํธ(`SdAutoUpdateService.getLastVersion`) ์์ฒญ์ ์ฒ๋ฆฌํ๋ค. `ServiceServer` ๋ ver=2 ๊ฐ ์๋ ์ฐ๊ฒฐ์ ์๋์ผ๋ก ์ด ํธ๋ค๋ฌ๋ก ๋๊ธฐ๋ฉฐ(`AutoUpdate` ์๋น์ค๋ `legacyV1Handlers` ๊ฐ ์์ ๋๋ง, ๋ ๋ค ์์ผ๋ฉด ์ฝ๋ 1008 ๋ก ์ฐ๊ฒฐ ๊ฑฐ๋ถ), `ServiceServerOptions.legacyV1Handlers` ๋ก ์ปค์คํ
ํธ๋ค๋ฌ๋ฅผ ๋ผ์ธ ๋๋ง ์ง์ ๋ค๋ฃฌ๋ค.
|
|
4
4
|
|
|
5
5
|
## handleV1Connection
|
|
6
6
|
|
|
@@ -9,27 +9,27 @@ function handleV1Connection(socket, autoUpdateMethods: V1AutoUpdateMethods, clie
|
|
|
9
9
|
function handleV1Connection(socket, options: V1ConnectionOptions): void;
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
V1 WebSocket ์ฐ๊ฒฐ 1๊ฑด์ ๋ฐ์ ์ฐ๊ฒฐ ์๋ฆผ(`{ name: "connected" }`)
|
|
12
|
+
V1 WebSocket ์ฐ๊ฒฐ 1๊ฑด์ ๋ฐ์ ์ฐ๊ฒฐ ์๋ฆผ(`{ name: "connected" }`)์ ๋ณด๋ธ ๋ค ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ๋ค. ์ฒ๋ฆฌ ์์: ์ปค์คํ
ํธ๋ค๋ฌ๋ค โ (๋ฏธ์ฒ๋ฆฌ ์) `SdAutoUpdateService.getLastVersion` fallback โ ๊ทธ๋๋ ๋ฏธ์ฒ๋ฆฌ๋ฉด `UPGRADE_REQUIRED` ์๋ฌ ์๋ต. ๋ฉ์์ง ํ์ฑยท์ฒ๋ฆฌ ์ค ์์ธ๋ ์ก์ warn ๋ก๊ทธ๋ง ๋จ๊ธฐ๊ณ ์๋ตํ์ง ์๋๋ค.
|
|
13
13
|
|
|
14
14
|
- `socket: WebSocket` โ `ws` ์ ์์ ์์ผ.
|
|
15
|
-
- 2๋ฒ์งธ ์ธ์ โ `V1AutoUpdateMethods` ๊ฐ์ฒด(์๋์
๋ฐ์ดํธ๋ง ์๋)์ด๊ฑฐ๋ `V1ConnectionOptions`(ํธ๋ค๋ฌยทํฉํ ๋ฆฌ ํฌํจ). `"getLastVersion" in arg` ๋ก
|
|
16
|
-
- `clientNameSetter?` โ ์ฒซ
|
|
15
|
+
- 2๋ฒ์งธ ์ธ์ โ `V1AutoUpdateMethods` ๊ฐ์ฒด(์๋์
๋ฐ์ดํธ๋ง ์๋)์ด๊ฑฐ๋ `V1ConnectionOptions`(ํธ๋ค๋ฌยทํฉํ ๋ฆฌ ํฌํจ). `"getLastVersion" in arg` ๋ก ๋ถ๊ธฐํ๋ค.
|
|
16
|
+
- `clientNameSetter?` โ ์ฒซ ์๊ทธ๋์ฒ์์๋ง ๋ฐ๋๋ค. ์์ฒญ์ `clientName` ์ ์ธ๋ถ์ ํต์งํ๋ ์ฝ๋ฐฑ.
|
|
17
17
|
|
|
18
18
|
## V1ConnectionOptions
|
|
19
19
|
|
|
20
20
|
- `serviceContext?: ServiceContext` โ ๋ชจ๋ ์์ฒญ์์ ๊ณต์ ํ ๊ณ ์ ์ปจํ
์คํธ.
|
|
21
|
-
- `serviceContextFactory?: (request: V1Request) => ServiceContext` โ ์์ฒญ๋ง๋ค ์ปจํ
์คํธ๋ฅผ ์๋ก ๋ง๋ค ๋. `serviceContext` ๋ณด๋ค
|
|
22
|
-
- `handlers?: V1RequestHandler[]` โ ์ปค์คํ
์์ฒญ ํธ๋ค๋ฌ ๋ชฉ๋ก. ์์์๋ถํฐ ํธ์ถ๋๋ฉฐ ์ฒซ `handled: true` ์์
|
|
21
|
+
- `serviceContextFactory?: (request: V1Request) => ServiceContext` โ ์์ฒญ๋ง๋ค ์ปจํ
์คํธ๋ฅผ ์๋ก ๋ง๋ค ๋. `serviceContext` ๋ณด๋ค ์ฐ์ ํ๋ค.
|
|
22
|
+
- `handlers?: V1RequestHandler[]` โ ์ปค์คํ
์์ฒญ ํธ๋ค๋ฌ ๋ชฉ๋ก. ์์์๋ถํฐ ํธ์ถ๋๋ฉฐ ์ฒซ `handled: true` ์์ ๋ฉ์ถ๋ค. ํธ๋ค๋ฌ๊ฐ ์๋๋ฐ ์ปจํ
์คํธ๊ฐ ์์ผ๋ฉด throw.
|
|
23
23
|
- `autoUpdateMethods?: V1AutoUpdateMethods` โ ์๋์
๋ฐ์ดํธ fallback ๊ตฌํ(๊ณ ์ ).
|
|
24
|
-
- `autoUpdateMethodsFactory?: (ctx: V1RequestHandlerContext) => V1AutoUpdateMethods` โ ์์ฒญ๋ง๋ค fallback
|
|
24
|
+
- `autoUpdateMethodsFactory?: (ctx: V1RequestHandlerContext) => V1AutoUpdateMethods` โ ์์ฒญ๋ง๋ค fallback ๊ตฌํ์ ์์ฑ. ์ง์ ์ `autoUpdateMethods` ๋์ ์ฌ์ฉํ๋ฉฐ ์ปจํ
์คํธ๊ฐ ์์ผ๋ฉด throw.
|
|
25
25
|
- `clientNameSetter?: (clientName: string | undefined) => void` โ ๋งค ์์ฒญ `clientName` ํต์ง ์ฝ๋ฐฑ.
|
|
26
26
|
|
|
27
27
|
## V1RequestHandler ์ ๊ด๋ จ ํ์
|
|
28
28
|
|
|
29
29
|
- `V1Request` โ `{ uuid: string; command: string; params: unknown[]; clientName?: string }`. ๊ตฌ๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ด๋ ์์ฒญ ํํ. `command` ๋ `"<service>.<method>"` ํํ์ ๋ช
๋ น ํค.
|
|
30
|
-
- `V1Response` โ `{ name: "response"; reqUuid: string; state: "success" | "error"; body: unknown }`. ์๋ฒ๊ฐ ๋๋ ค๋ณด๋ด๋ ์๋ต ํํ. `state`
|
|
30
|
+
- `V1Response` โ `{ name: "response"; reqUuid: string; state: "success" | "error"; body: unknown }`. ์๋ฒ๊ฐ ๋๋ ค๋ณด๋ด๋ ์๋ต ํํ. `state` ๋ ์๋ต ์ํ๋ก `"success"`(์ ์)ยท`"error"`(์ค๋ฅ)๋ฅผ ๊ตฌ๋ถ.
|
|
31
31
|
- `V1RequestHandlerContext` โ `{ request: V1Request; serviceContext: ServiceContext }`. ํธ๋ค๋ฌ๊ฐ ๋ฐ๋ ์ธ์.
|
|
32
|
-
- `V1RequestHandlerResult` โ `{ handled: true; state?: "success" | "error"; body: unknown } | { handled: false }`. `handled`
|
|
32
|
+
- `V1RequestHandlerResult` โ `{ handled: true; state?: "success" | "error"; body: unknown } | { handled: false }`. `handled` ๋ ์ด ํธ๋ค๋ฌ๊ฐ ์์ฒญ์ ์ฒ๋ฆฌํ๋์ง ์ฌ๋ถ. `false` ๋ฉด ๋ค์ ํธ๋ค๋ฌยทfallback ์ผ๋ก ๋์ด๊ฐ๊ณ , `true` ๋ฉด ๊ทธ `state`(๊ธฐ๋ณธ `"success"`)ยท`body` ๋ก ์ฆ์ ์๋ตํ๋ค.
|
|
33
33
|
- `V1RequestHandler` โ `(ctx: V1RequestHandlerContext) => V1RequestHandlerResult | Promise<V1RequestHandlerResult>`. ๋๊ธฐยท๋น๋๊ธฐ ๋ชจ๋ ๊ฐ๋ฅ.
|
|
34
34
|
- `V1AutoUpdateMethods` โ `{ getLastVersion: (platform: string) => Promise<unknown> | unknown }`. `SdAutoUpdateService.getLastVersion` ๋ช
๋ น์ fallback ์ธํฐํ์ด์ค.
|
|
35
35
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# @simplysm/storage
|
|
2
2
|
|
|
3
|
-
Node
|
|
3
|
+
Node ์ ์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ. FTP/FTPS/SFTP ์๊ฒฉ ์คํ ๋ฆฌ์ง์ ์ ์ํด ํ์ผยท๋๋ ํ ๋ฆฌ๋ฅผ ์
๋ก๋ยท๋ค์ด๋ก๋ยท์กฐํยท์ญ์ ํ๋ค. ํ๋กํ ์ฝ๋ณ ๊ตฌํ(`basic-ftp`ยท`ssh2-sftp-client`)์ ๋จ์ผ ์ธํฐํ์ด์ค `StorageClient` ๋ก ํต์ผํ๊ณ , `StorageFactory.connect` ์ฝ๋ฐฑ ํจํด์ผ๋ก ์ฐ๊ฒฐ/์ข
๋ฃ๋ฅผ ์๋ ๊ด๋ฆฌํ๋ค. `fs`/`os`/`path`/`stream` ์ ์์กดํ๋ฏ๋ก ๋ธ๋ผ์ฐ์ ์์๋ ์ฌ์ฉ ๋ถ๊ฐ.
|
|
4
4
|
|
|
5
5
|
## ์ฌ์ฉ ํธ๋ฆฌ๊ฑฐ ์ธ๋ฑ์ค
|
|
6
6
|
|
|
7
|
-
- **StorageFactory
|
|
8
|
-
- **StorageClient** โ connect ์ฝ๋ฐฑ์ด ๋ฐ๋ ํ์ผ ์์
์ธํฐํ์ด์ค(mkdir/list/
|
|
7
|
+
- **StorageFactory** โ ํ๋กํ ์ฝยท์ ์์ ๋ณด๋ก ์ฐ๊ฒฐ์ ์ด๊ณ ์ฝ๋ฐฑ ์์์ ํ์ผ ์์
ํ ์๋ ์ข
๋ฃํ ๋. ๊ถ์ฅ ์ง์
์ .
|
|
8
|
+
- **StorageClient** โ connect ์ฝ๋ฐฑ์ด ๋ฐ๋ ํ์ผ ์์
์ธํฐํ์ด์ค(connect/mkdir/rename/list/readFile/exists/put/uploadDir/remove/close). ํธ์ถ ๊ฐ๋ฅํ ๋ฉ์๋๋ฅผ ํ์ธํ ๋.
|
|
9
9
|
- **StorageConnConfig / StorageProtocol / FileInfo** โ connect ์ธ์ ํํ, ์ง์ ํ๋กํ ์ฝ ๋ฆฌํฐ๋ด, list ๋ฐํ ํญ๋ชฉ ํํ๋ฅผ ํ์ธํ ๋.
|
|
10
|
-
- **FtpStorageClient / SftpStorageClient** โ ํฉํ ๋ฆฌ ์์ด
|
|
10
|
+
- **FtpStorageClient / SftpStorageClient** โ ํฉํ ๋ฆฌ ์์ด ์ฐ๊ฒฐ ์๋ช
์ ์ง์ ์ ์ดํ๊ฑฐ๋ ํ๋กํ ์ฝ๋ณ ์ธ์ฆยท๋์ ์ฐจ์ด๋ฅผ ํ์ธํ ๋. ๋น๊ถ์ฅ.
|
|
11
11
|
|
|
12
12
|
## StorageFactory (์ง์
์ )
|
|
13
13
|
|
|
14
|
-
์คํ ๋ฆฌ์ง ์ ์ ์ง์
์ .
|
|
14
|
+
์คํ ๋ฆฌ์ง ์ ์ ์ง์
์ . ์ธ์คํด์คํ ์์ด ์ ์ `connect` ๋ง ํธ์ถํ๋ค. ์ฐ๊ฒฐ ์์ฑ โ ์ฝ๋ฐฑ ์คํ โ ์๋ ์ข
๋ฃ๋ฅผ ํ ๋ฒ์ ๋ฌถ์ด ์ฒ๋ฆฌํ๋ค.
|
|
15
15
|
|
|
16
16
|
```ts
|
|
17
17
|
class StorageFactory {
|
|
@@ -23,10 +23,10 @@ class StorageFactory {
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
- `type: StorageProtocol` โ ์ฌ์ฉํ ํ๋กํ ์ฝ. ๋ด๋ถ์์ `"sftp"` โ `SftpStorageClient`, `"ftps"` โ `FtpStorageClient(
|
|
26
|
+
- `type: StorageProtocol` โ ์ฌ์ฉํ ํ๋กํ ์ฝ. ๋ด๋ถ์์ `"sftp"` โ `new SftpStorageClient()`, `"ftps"` โ `new FtpStorageClient(true)`, `"ftp"` โ `new FtpStorageClient(false)` ๋ก ํด๋ผ์ด์ธํธ๋ฅผ ์์ฑ. ๋ณด์ ์ ์ก์ด ํ์ํ๋ฉด `"ftps"`/`"sftp"`.
|
|
27
27
|
- `config: StorageConnConfig` โ ์ ์ ์ค์ (host/port/user/password). ์๋ StorageConnConfig ์ฐธ์กฐ.
|
|
28
|
-
- `fn: (storage: StorageClient) => R | Promise<R>` โ ์ฐ๊ฒฐ๋ `StorageClient` ๋ฅผ ๋ฐ์ ํ์ผ ์์
์ ์ํํ๋ ์ฝ๋ฐฑ. ๋ฐํ๊ฐ์ด ๊ทธ๋๋ก `connect` ์ ๊ฒฐ๊ณผ(`Promise<R>`)
|
|
29
|
-
- ๋์: `client.connect(config)` ํ `fn` ์คํ, `finally` ์์ `client.close()` ํธ์ถํ๋ฉฐ ์ข
๋ฃ ์ค ์ค๋ฅ๋ ๋ฌด์(์ด๋ฏธ ์ข
๋ฃ๋ ๊ฒฝ์ฐ ๋๋น). ์ฝ๋ฐฑ์์ ์์ธ๊ฐ ๋๋ ์ฐ๊ฒฐ์ ๋ฐ๋์ ๋ซํ๊ณ ์์ธ๋ ๊ทธ๋๋ก ์ ํ๋จ.
|
|
28
|
+
- `fn: (storage: StorageClient) => R | Promise<R>` โ ์ฐ๊ฒฐ๋ `StorageClient` ๋ฅผ ๋ฐ์ ํ์ผ ์์
์ ์ํํ๋ ์ฝ๋ฐฑ. ๋ฐํ๊ฐ์ด ๊ทธ๋๋ก `connect` ์ ๊ฒฐ๊ณผ(`Promise<R>`)๊ฐ ๋จ. ๋๊ธฐยท๋น๋๊ธฐ ๋ชจ๋ ํ์ฉ.
|
|
29
|
+
- ๋์: `client.connect(config)` ์ฑ๊ณต ํ `fn` ์คํ, `finally` ์์ `client.close()` ํธ์ถํ๋ฉฐ ์ข
๋ฃ ์ค ์ค๋ฅ๋ `.catch(() => {})` ๋ก ๋ฌด์(์ด๋ฏธ ์ข
๋ฃ๋ ๊ฒฝ์ฐ ๋๋น). ์ฝ๋ฐฑ์์ ์์ธ๊ฐ ๋๋ ์ฐ๊ฒฐ์ ๋ฐ๋์ ๋ซํ๊ณ ์์ธ๋ ๊ทธ๋๋ก ์ ํ๋จ.
|
|
30
30
|
|
|
31
31
|
```ts
|
|
32
32
|
const names = await StorageFactory.connect("sftp", { host: "10.0.0.1", user: "u", password: "p" }, async (s) => {
|
|
@@ -49,9 +49,9 @@ interface StorageConnConfig { host: string; port?: number; user?: string; passwo
|
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
- `host: string` โ ์ ์ ๋์ ์๋ฒ ํธ์คํธ๋ช
๋๋ IP. ํ์.
|
|
52
|
-
- `port?: number` โ ์ ์ ํฌํธ. ๋ฏธ์ง์ ์ ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
|
|
53
|
-
- `user?: string` โ ๋ก๊ทธ์ธ
|
|
54
|
-
- `password?: string` โ ๋ก๊ทธ์ธ ๋น๋ฐ๋ฒํธ. **SFTP ์์ ์ด ๊ฐ์ด
|
|
52
|
+
- `port?: number` โ ์ ์ ํฌํธ. ๋ฏธ์ง์ ์ ๊ทธ๋๋ก `undefined` ๋ก ์ ๋ฌ๋์ด ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธฐ๋ณธ ํฌํธ(`basic-ftp`/`ssh2-sftp-client` ๊ธฐ๋ณธ๊ฐ)๋ฅผ ์ฌ์ฉ. ๋นํ์ค ํฌํธ๋ฉด ๋ช
์.
|
|
53
|
+
- `user?: string` โ ๋ก๊ทธ์ธ ์ฌ์ฉ์๋ช
(FTP `user`, SFTP `username` ์ผ๋ก ๋งคํ). ๋ฏธ์ง์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ธฐ๋ณธ ์ฌ์ฉ์.
|
|
54
|
+
- `password?: string` โ ๋ก๊ทธ์ธ ๋น๋ฐ๋ฒํธ. **SFTP ์์ ์ด ๊ฐ์ด `null`(๋ฏธ์ง์ )์ด๋ฉด** password ์ธ์ฆ ๋์ `~/.ssh/id_ed25519` ๊ฐ์ธํค๋ก ์ธ์ฆ์ ์๋ํ๊ณ (`SSH_AUTH_SOCK` ํ๊ฒฝ๋ณ์๊ฐ ์์ผ๋ฉด `agent` ์ต์
๋ ํจ๊ป ์ฌ์ฉ), ํค ํ์ฑ์ด ์คํจํ๋ฉด(์ํธํ๋ ํค ๋ฑ) agent ๋จ๋
์ผ๋ก ์ฌ์๋ํ๋ค. FTP/FTPS ๋ ๋ฏธ์ง์ ์ ๊ทธ๋๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์. SFTP ํค ์ธ์ฆ์ ์ฐ๋ ค๋ฉด password ๋ฅผ ๋๊ธฐ์ง ๋ง ๊ฒ.
|
|
55
55
|
|
|
56
56
|
### StorageProtocol
|
|
57
57
|
|
|
@@ -59,9 +59,9 @@ interface StorageConnConfig { host: string; port?: number; user?: string; passwo
|
|
|
59
59
|
type StorageProtocol = "ftp" | "ftps" | "sftp";
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
- `"ftp"` โ ํ๋ฌธ FTP.
|
|
63
|
-
- `"ftps"` โ TLS ๋ก ์ํธํ๋ FTP
|
|
64
|
-
- `"sftp"` โ SSH ๊ธฐ๋ฐ SFTP
|
|
62
|
+
- `"ftp"` โ ํ๋ฌธ FTP. `FtpStorageClient(false)` ์์ฑ(`secure=false`, TLS ์์). ๋ด๋ถ๋งยทํ
์คํธ์์๋ง ๊ถ์ฅ.
|
|
63
|
+
- `"ftps"` โ TLS ๋ก ์ํธํ๋ FTP. `FtpStorageClient(true)` ์์ฑ(`secure=true`). ์ธ๋ถ๋ง FTP ์ ์ ์.
|
|
64
|
+
- `"sftp"` โ SSH ๊ธฐ๋ฐ SFTP. `SftpStorageClient` ์์ฑ. ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๋ณด์ ์ ์ก.
|
|
65
65
|
|
|
66
66
|
### FileInfo
|
|
67
67
|
|
|
@@ -72,11 +72,11 @@ interface FileInfo { name: string; isFile: boolean; }
|
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
- `name: string` โ ํญ๋ชฉ ์ด๋ฆ(ํ์ผ๋ช
๋๋ ๋๋ ํ ๋ฆฌ๋ช
, ๊ฒฝ๋ก ์๋).
|
|
75
|
-
- `isFile: boolean` โ ํ์ผ์ด๋ฉด `true`, ๋๋ ํ ๋ฆฌ๋ฉด `false`. ๋๋ ํ ๋ฆฌ ํ์ ์ ํ์ผ๋ง ๊ณจ๋ผ ์ฒ๋ฆฌํ๋ ๋ถ๊ธฐ ๊ธฐ์ค์ผ๋ก ์ฌ์ฉ. FTP ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ `isFile
|
|
75
|
+
- `isFile: boolean` โ ํ์ผ์ด๋ฉด `true`, ๋๋ ํ ๋ฆฌ๋ฉด `false`. ๋๋ ํ ๋ฆฌ ํ์ ์ ํ์ผ๋ง ๊ณจ๋ผ ์ฒ๋ฆฌํ๋ ๋ถ๊ธฐ ๊ธฐ์ค์ผ๋ก ์ฌ์ฉ. FTP ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ `isFile` ๊ฐ์ ๊ทธ๋๋ก ์ฌ์ฉ, SFTP ๋ ํญ๋ชฉ `type` ์ด `"-"`(์ผ๋ฐ ํ์ผ)์ผ ๋๋ง `true`(๋๋ ํ ๋ฆฌยท์ฌ๋ณผ๋ฆญ ๋งํฌ๋ `false`).
|
|
76
76
|
|
|
77
77
|
### StorageClient
|
|
78
78
|
|
|
79
|
-
`connect` ์ฝ๋ฐฑ ์์์ ๋ฐ๋ ํ์ผ ์์
์ธํฐํ์ด์ค. `FtpStorageClient`ยท`SftpStorageClient` ๊ฐ ๊ตฌํ. ๋ชจ๋ ๋ฉ์๋๋ `Promise` ๋ฐํ.
|
|
79
|
+
`connect` ์ฝ๋ฐฑ ์์์ ๋ฐ๋ ํ์ผ ์์
์ธํฐํ์ด์ค. `FtpStorageClient`ยท`SftpStorageClient` ๊ฐ ๊ตฌํ. ๋ชจ๋ ๋ฉ์๋๋ `Promise` ๋ฐํ. ๊ฒฝ๋ก ์ธ์๋ ์๊ฒฉ ๊ธฐ์ค ๊ฒฝ๋ก ๋ฌธ์์ด.
|
|
80
80
|
|
|
81
81
|
```ts
|
|
82
82
|
interface StorageClient {
|
|
@@ -93,15 +93,15 @@ interface StorageClient {
|
|
|
93
93
|
}
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
- `connect(config)` โ ์๋ฒ์ ์ฐ๊ฒฐ. ์ด๋ฏธ ์ฐ๊ฒฐ๋ ์ธ์คํด์ค์์ ์ฌํธ์ถํ๋ฉด `SdError` throw(๋จผ์ `close()` ํ์).
|
|
97
|
-
- `mkdir(dirPath)` โ ๋๋ ํ ๋ฆฌ ์์ฑ. ๋ถ๋ชจ ๋๋ ํ ๋ฆฌ๊ฐ ์์ผ๋ฉด ํจ๊ป ์์ฑ(FTP `ensureDir`, SFTP ์ฌ๊ท `mkdir`).
|
|
98
|
-
- `rename(fromPath, toPath)` โ
|
|
96
|
+
- `connect(config)` โ ์๋ฒ์ ์ฐ๊ฒฐ. ์ด๋ฏธ ์ฐ๊ฒฐ๋ ์ธ์คํด์ค์์ ์ฌํธ์ถํ๋ฉด `SdError`("์ด๋ฏธ ์ฐ๊ฒฐ๋์ด ์์ต๋๋ค") throw(๋จผ์ `close()` ํ์). ์ฐ๊ฒฐ ๋์ค ์คํจํ๋ฉด ๋ด๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฐ๊ฒฐ์ ๋ซ๊ณ (FTP `close()`, SFTP `end()`) ์์ธ๋ฅผ ๋ค์ throw. `StorageFactory.connect` ์ฌ์ฉ ์ ์ง์ ํธ์ถ ๋ถํ์.
|
|
97
|
+
- `mkdir(dirPath)` โ ๋๋ ํ ๋ฆฌ ์์ฑ. ๋ถ๋ชจ ๋๋ ํ ๋ฆฌ๊ฐ ์์ผ๋ฉด ํจ๊ป ์์ฑ(FTP `ensureDir`, SFTP ์ฌ๊ท `mkdir(path, true)`).
|
|
98
|
+
- `rename(fromPath, toPath)` โ ํ์ผ/๋๋ ํ ๋ฆฌ๋ฅผ `fromPath` ์์ `toPath` ๋ก ์ด๋ยท์ด๋ฆ ๋ณ๊ฒฝ.
|
|
99
99
|
- `list(dirPath)` โ ๋๋ ํ ๋ฆฌ ๋ด ํญ๋ชฉ์ `FileInfo[]` ๋ก ๋ฐํ. ๋ชฉ๋ก์ ํ์ผ/ํด๋๋ก ๊ฐ๋ผ ์ฒ๋ฆฌํ ๋.
|
|
100
|
-
- `readFile(filePath)` โ ์๊ฒฉ ํ์ผ ์ ์ฒด๋ฅผ `Bytes`(Uint8Array)
|
|
101
|
-
- `exists(filePath)` โ ํ์ผ/๋๋ ํ ๋ฆฌ ์กด์ฌ ์ฌ๋ถ. **๋ชจ๋ ์์ธ(๋ถ๋ชจ ์์ยท๊ถํยท๋คํธ์ํฌ ์ค๋ฅ ํฌํจ)
|
|
102
|
-
- `put(localPathOrBuffer, storageFilePath)` โ ๋จ์ผ ํ์ผ ์
๋ก๋. ์ฒซ ์ธ์๊ฐ `string` ์ด๋ฉด ๋ก์ปฌ ํ์ผ
|
|
103
|
-
- `uploadDir(fromPath, toPath)` โ ๋ก์ปฌ ๋๋ ํ ๋ฆฌ ์ ์ฒด๋ฅผ ์๊ฒฉ
|
|
104
|
-
- `remove(filePath)` โ ์๊ฒฉ ํ์ผ
|
|
100
|
+
- `readFile(filePath)` โ ์๊ฒฉ ํ์ผ ์ ์ฒด๋ฅผ `Bytes`(Uint8Array)๋ก ๋ฉ๋ชจ๋ฆฌ์ ๋ค์ด๋ก๋(์คํธ๋ฆฌ๋ฐ ์๋ โ ํฐ ํ์ผ์ ๋ฉ๋ชจ๋ฆฌ ๋ถ๋ด). ํ
์คํธ๊ฐ ํ์ํ๋ฉด ํธ์ถ ์ธก์์ ๋์ฝ๋ฉ(์: `new TextDecoder().decode(...)`). SFTP ๋ ์๋ต์ด ์์ ํ์
(Uint8Array/string)์ด ์๋๋ฉด `SdError`("์์ํ์ง ๋ชปํ ์๋ต ํ์
์
๋๋ค") throw.
|
|
101
|
+
- `exists(filePath)` โ ํ์ผ/๋๋ ํ ๋ฆฌ ์กด์ฌ ์ฌ๋ถ. **๋ชจ๋ ์์ธ(๋ถ๋ชจ ๋๋ ํ ๋ฆฌ ์์ยท๊ถํยท๋คํธ์ํฌ ์ค๋ฅ ํฌํจ)์ ๋ํด `false` ๋ฐํ** โ throw ํ์ง ์์ผ๋ฏ๋ก `true` ๋ง "ํ์คํ ์กด์ฌ"๋ก ์ ๋ขฐํ๋ค. FTP ๋ `size()` ๋ก ํ์ผ์ O(1) ํ์ธ ํ ์คํจ ์ ๋ถ๋ชจ ๋๋ ํ ๋ฆฌ ๋ชฉ๋ก(`list`)์ผ๋ก ๋๋ ํ ๋ฆฌ/ํ์ผ์ ์ฌํ์ธ(์ฌ๋์ ์๋ ๊ฒฝ๋ก๋ ๋ฃจํธ `/` ๊ธฐ์ค โ ํญ๋ชฉ์ด ๋ง์ ๋๋ ํ ๋ฆฌ์์๋ ๋๋ ค์ง ์ ์์). SFTP ๋ `exists()` ๊ฒฐ๊ณผ๊ฐ ๋ฌธ์์ด(`'d'` ๋๋ ํ ๋ฆฌ/`'-'` ํ์ผ/`'l'` ์ฌ๋ณผ๋ฆญ ๋งํฌ)์ด๋ฉด ์กด์ฌ๋ก ํ์ . ์์
์ ๋ถ๊ธฐ ํ์ธ์ ์ฌ์ฉ.
|
|
102
|
+
- `put(localPathOrBuffer, storageFilePath)` โ ๋จ์ผ ํ์ผ ์
๋ก๋. ์ฒซ ์ธ์๊ฐ `string` ์ด๋ฉด ๋ก์ปฌ ํ์ผ ๊ฒฝ๋ก์์(FTP `uploadFrom`, SFTP `fastPut`), `Bytes` ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํธ์์ ์
๋ก๋(FTP ๋ `Readable.from` ์คํธ๋ฆผ, SFTP ๋ `Buffer.from` ๋ณํ). ์์ฑํ ์ฝํ
์ธ ๋ฅผ ๋ฐ๋ก ์ฌ๋ฆด ๋ `Bytes` ๋ก ์ ๋ฌ.
|
|
103
|
+
- `uploadDir(fromPath, toPath)` โ ๋ก์ปฌ ๋๋ ํ ๋ฆฌ `fromPath` ์ ์ฒด๋ฅผ ์๊ฒฉ ๋๋ ํ ๋ฆฌ `toPath` ๋ก ์ฌ๊ท ์
๋ก๋. ๋น๋ ์ฐ์ถ๋ฌผ ํด๋๋ฅผ ํต์งธ๋ก ๋ฐฐํฌํ ๋.
|
|
104
|
+
- `remove(filePath)` โ ์๊ฒฉ ํ์ผ ์ญ์ (FTP `remove`, SFTP `delete`).
|
|
105
105
|
- `close()` โ ์ฐ๊ฒฐ ์ข
๋ฃ. ์ด๋ฏธ ์ข
๋ฃ/๋ฏธ์ฐ๊ฒฐ ์ํ์์ ํธ์ถํด๋ ์ค๋ฅ ์์. ์ข
๋ฃ ํ ๊ฐ์ ์ธ์คํด์ค์์ `connect()` ๋ก ์ฌ์ฐ๊ฒฐ ๊ฐ๋ฅ. `StorageFactory.connect` ์ฌ์ฉ ์ ์ง์ ํธ์ถ ๋ถํ์.
|
|
106
106
|
|
|
107
107
|
๋ฏธ์ฐ๊ฒฐ ์ํ์์ ์์
๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ๋ชจ๋ ๊ตฌํ์ฒด๊ฐ `SdError`("์ฐ๊ฒฐ๋์ด ์์ง ์์ต๋๋ค") throw.
|
|
@@ -115,9 +115,9 @@ new FtpStorageClient(secure?: boolean) // secure=true โ FTPS, ์๋ต/false
|
|
|
115
115
|
new SftpStorageClient()
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
- `FtpStorageClient` ์ `secure` ์์ฑ์ ์ธ์ โ `true` ๋ฉด TLS(FTPS), ์๋ต/`false`(๊ธฐ๋ณธ)
|
|
118
|
+
- `FtpStorageClient` ์ `secure` ์์ฑ์ ์ธ์ โ `true` ๋ฉด TLS(FTPS), ์๋ต/`false`(๊ธฐ๋ณธ)๋ฉด ํ๋ฌธ FTP. ํฉํ ๋ฆฌ๋ `"ftps"`โ`true`, `"ftp"`โ`false` ๋ก ๋งคํ.
|
|
119
119
|
- `SftpStorageClient` ๋ ์์ฑ์ ์ธ์ ์์. password ๋ฏธ์ง์ ์ ํค/agent ์ธ์ฆ ๊ฒฝ๋ก๋ฅผ ํ๋ค(StorageConnConfig ์ `password` ํ์ด ์ฐธ์กฐ).
|
|
120
|
-
- ์ง์ ์ฌ์ฉ ์ `connect()` โ ์์
โ `close()` ์์ผ๋ก ํธ์ถํ๊ณ , ์์ธ ๋ฐ์ ์์๋ `close()` ๊ฐ ํธ์ถ๋๋๋ก `try/finally` ๋ก ๊ฐ์ ๊ฒ. ๋์ผ ์ธ์คํด์ค์์ `close()` ์์ด `connect()` ๋ฅผ ์ฌํธ์ถํ๋ฉด ์ฐ๊ฒฐ
|
|
120
|
+
- ์ง์ ์ฌ์ฉ ์ `connect()` โ ์์
โ `close()` ์์ผ๋ก ํธ์ถํ๊ณ , ์์ธ ๋ฐ์ ์์๋ `close()` ๊ฐ ํธ์ถ๋๋๋ก `try/finally` ๋ก ๊ฐ์ ๊ฒ. ๋์ผ ์ธ์คํด์ค์์ `close()` ์์ด `connect()` ๋ฅผ ์ฌํธ์ถํ๋ฉด `SdError` throw(์ฐ๊ฒฐ ๋์ ๋ฐฉ์ง).
|
|
121
121
|
|
|
122
122
|
```ts
|
|
123
123
|
const client = new SftpStorageClient();
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# ํด๋ผ์ด์ธํธ ํ๋ฉด ์์ฑ ๋งค๋ด์ผ
|
|
2
2
|
|
|
3
|
+
ํ๋ฆฌ๋ ๋(SSG) ๋์ ํ๋ฉด์ ์์ฑํ ๋๋ [client-ssg.md](./client-ssg.md) ์ SSR-safeยท์๋ฒ ์ฐ๊ฒฐ ์ ์ฝ์ ํจ๊ป ์ ์ฉ.
|
|
4
|
+
|
|
3
5
|
## ํ์ผ๋ช
ยท์ญํ ยท์์น
|
|
4
6
|
|
|
5
7
|
ํ๋ฉด ํ์ผ๋ช
์ `<domain>.<์ญํ >.ts` ํ์. ์ญํ ์ ๋ฏธ์ฌ๋ก ์ฑ
์์ ํ์.
|
|
@@ -643,7 +645,13 @@ async onSubmit(): Promise<void> {
|
|
|
643
645
|
|
|
644
646
|
```html
|
|
645
647
|
<sd-crud-list ...>
|
|
646
|
-
<ng-template #filterTpl
|
|
648
|
+
<ng-template #filterTpl>
|
|
649
|
+
<!-- sd-crud-list ๊ฐ ์ด๋ฏธ form-box-inline ์ผ๋ก ๊ฐ์ธ๋ฏ๋ก ์ฌ๊ธฐ์ ๋ค์ ๋ฌถ์ง ์์ -->
|
|
650
|
+
<div>
|
|
651
|
+
<label>๊ฒ์์ด</label>
|
|
652
|
+
<sd-textfield [type]="'text'" [(value)]="filter().searchText" (valueChange)="mark(filter)" />
|
|
653
|
+
</div>
|
|
654
|
+
</ng-template>
|
|
647
655
|
|
|
648
656
|
<sd-sheet-column [key]="..." [header]="...">
|
|
649
657
|
<ng-template [cell]="items()" let-item="item">...</ng-template>
|