@k-msg/cli 0.9.13 → 0.11.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 +36 -0
- package/README.md +23 -6
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @k-msg/cli
|
|
2
2
|
|
|
3
|
+
## 0.11.0 — 2026-09-27
|
|
4
|
+
|
|
5
|
+
### Minor changes
|
|
6
|
+
|
|
7
|
+
- [48a6cf0d](https://github.com/k-otp/k-msg/commit/48a6cf0ddc815799e51037e703d7c3e1c6e6296f) `k-msg db schema print` and `generate` take the schema options the SQL stores and queues use: `--message-id-type`, `--id-type`, `--short-text-type`, `--timestamp-type` and `--json-type` (the tracking store's `typeStrategy`), `--tracking-table`, `--queue-table`, and `--store-raw`. Before, they always printed the default schema, which a store with, say, `typeStrategy: { timestamp: "date" }` does not match. `columnMap`, `indexNames` and field-crypto schemas still need the schema builders in code. — Thanks @imjlk!
|
|
8
|
+
|
|
9
|
+
### Patch changes
|
|
10
|
+
|
|
11
|
+
- [455e09e1](https://github.com/k-otp/k-msg/commit/455e09e1e32ee2de6c231a250abc49c23065fe73) Stop requiring a Kakao `plusId` for SOLAPI AlimTalk. SOLAPI identifies the channel by pfId (`kakao.profileId` or `config.kakaoPfId`) and never sends a plusId, but its onboarding spec declared `plusIdPolicy: "required_if_no_inference"` with inference unsupported, so `KMsg.send()` rejected every SOLAPI AlimTalk without `kakao.plusId` before calling the provider, and `k-msg alimtalk preflight` failed on it. The spec now declares the plusId optional and the CLI no longer asks for one for SOLAPI. Since SOLAPI has no template API for preflight to probe, `k-msg alimtalk preflight` now checks the pfId instead: `--sender-key`, a Kakao channel alias, or `solapi.config.kakaoPfId`. The setup checklist and READMEs point at the pfId binding. — Thanks @imjlk!
|
|
12
|
+
- [afd0e69c](https://github.com/k-otp/k-msg/commit/afd0e69c5d9bc86e7dea167bd48d2f5f17c9a659) Keep a provider's request context and transport capabilities when its config entry uses a custom id. The CLI wraps such a provider to rename it, and the wrapper's `send` dropped the `{ signal, fetch }` argument and left out `transportCapabilities`, so a provider that honors an abort signal never saw one. — Thanks @imjlk!
|
|
13
|
+
- [0fb8eff7](https://github.com/k-otp/k-msg/commit/0fb8eff77a9fc0dd7ef3cfde56577d3bed62ba79) Stop `KakaoChannelBindingResolver.resolve()` from giving one provider the Kakao channel of another. It took the senderKey and plusId of the named alias, or of the `defaults.kakao.channel` alias, without checking which provider the alias was bound to. It now skips the senderKey, plusId and name of an alias bound to a provider other than the one it resolves for, and falls through to that provider's own config (`senderKey`, SOLAPI `kakaoPfId`, `profileId`, `plusId`) or leaves them unset. `defaults.kakao.senderKey` and `defaults.kakao.plusId` name no provider and still apply to all of them.
|
|
14
|
+
|
|
15
|
+
CLI commands that resolve a binding for a provider other than the alias's change with it:
|
|
16
|
+
|
|
17
|
+
- `k-msg alimtalk send` and `k-msg alimtalk preflight` no longer use the default channel alias, or a `--channel` alias, of another provider. With the `config init --template full` config, whose default alias `main` is bound to aligo, `alimtalk send --provider solapi` sent `ALIGO_SENDER_KEY` as SOLAPI's pfId even when `solapi.config.kakaoPfId` was set; it now sends that pfId. Preflight checks the provider with its own senderKey and plusId, so for Aligo it infers the plusId of Aligo's own channel. `--channel` still does not choose the provider, which is `--provider` or else the default AlimTalk provider, so pass `--provider` with an alias of any other provider.
|
|
18
|
+
- `k-msg alimtalk send --interactive` asks for the senderKey, and a plusId where the provider requires one, instead of taking them from the default alias of another provider.
|
|
19
|
+
- `k-msg kakao template` commands with a `--provider` other than the alias's use that provider's own senderKey, if it has one, as the template context.
|
|
20
|
+
- `k-msg kakao channel binding resolve` reports the provider's own binding and leaves out the name of a skipped alias. — Thanks @imjlk!
|
|
21
|
+
- [59933acf](https://github.com/k-otp/k-msg/commit/59933acf0bf4702b68a3bb76b2d1fdb5001a9549) The field-crypto backfill encrypts rows on Postgres. `applyFieldCryptoMigration()` and `retryFieldCryptoMigration()`, which `k-msg db tracking migrate apply` and `retry` run, read their cursor through unquoted camelCase aliases, which Postgres folds to lowercase. They found no rows and marked the run completed with nothing encrypted. Such a run never moved its cursor, so running `apply` again with the same plan now encrypts the table. The backfill also wrote `metadata_hashes` through postgres.js and Bun.SQL as a JSON string, the bug the tracking store had before its JSON parameters were cast, and now stores it as a JSON document. Metadata that those drivers stored as a JSON string is now read as its object, as the store reads it, instead of being encrypted as missing. — Thanks @imjlk!
|
|
22
|
+
- [4fa441fa](https://github.com/k-otp/k-msg/commit/4fa441fa53cff64c29cc966f99614553930bdc72) Let onboarding checks name the message types they prepare for. `ProviderOnboardingCheckSpec.messageTypes` is a new optional field, and `k-msg providers doctor` skips a check that names only types the provider cannot send, reporting it as not applicable. The IWINV Kakao channel, template capability and template list checks declare `["ALIMTALK"]`, so an SMS-only IWINV configuration no longer fails `doctor` on the Kakao channel prerequisite. `k-msg alimtalk preflight` still evaluates every AlimTalk check. — Thanks @imjlk!
|
|
23
|
+
- [5101def8](https://github.com/k-otp/k-msg/commit/5101def82fbabc3aec3b5f4aaf0f92f25190240a) Allow an SMS-only `IWINVProvider`. The AlimTalk `apiKey` was required even to send SMS/LMS/MMS, which authenticate with `smsApiKey` and `smsAuthKey`. `IWINVConfig.apiKey` is now optional: a provider needs `apiKey`, or both SMS keys, and lists only the message types its keys can send. Without `apiKey`, AlimTalk sends, AlimTalk history and balance, and the template APIs fail with `INVALID_REQUEST`, and `getBalance()` defaults to the SMS balance.
|
|
24
|
+
|
|
25
|
+
In the CLI, an `iwinv` entry needs `apiKey`, or both `smsApiKey` and `smsAuthKey` (`Set apiKey, or smsApiKey + smsAuthKey`; `anyOf` in the JSON schema, from the new `providerConfigKeyAlternatives` export), and the `iwinv_config_required` onboarding check runs only in the AlimTalk preflight. Routes seeded by `config provider add` and `config init` follow each entry's credentials, through the new optional `ProviderCliMetadata.routingSeedTypesForConfig`. Those commands fill in `apiKey: "env:IWINV_API_KEY"` by default, so for SMS-only use remove `apiKey` and the entry's `ALIMTALK` route from the config. — Thanks @imjlk!
|
|
26
|
+
- [2e92adb1](https://github.com/k-otp/k-msg/commit/2e92adb151067ef1e963858c9074276790144e8d) `k-msg db schema print` and `generate` print a MySQL schema that MySQL can create with the default type flags: the primary key and the indexed tracking columns are `VARCHAR` whatever `--message-id-type`, `--id-type` and `--short-text-type` say. The MySQL Drizzle output now follows `--id-type` and `--json-type` like the SQL output, instead of always using `varchar(255)` ids and `text` JSON columns. — Thanks @imjlk!
|
|
27
|
+
- Updated dependencies: channel@0.32.0, core@0.32.0, messaging@0.32.0, provider@0.32.0, template@0.32.0, k-msg@0.32.0
|
|
28
|
+
|
|
29
|
+
## 0.10.0 — 2026-09-26
|
|
30
|
+
|
|
31
|
+
### Minor changes
|
|
32
|
+
|
|
33
|
+
- [b4d1b9b6](https://github.com/k-otp/k-msg/commit/b4d1b9b6ec18bc652c052e4f6ab95fb51e8e9cbd) Encrypt the field-crypto migration backfill instead of copying plaintext: `applyFieldCryptoMigration` and `retryFieldCryptoMigration` now require the tracking store's `fieldCrypto` options and encrypt rows whose `crypto_state` is empty, `plain`, or `degraded` through the same write path as the store. The backfill can run alongside live writes: it updates a row only while the row's state, recipient, sender, provider, and metadata still match what it read, re-encrypts the row's current values otherwise, and confirms each write by re-reading the row when the driver reports no affected-row count. Chunks after the first no longer fail on SQLite, D1, and MySQL, a failed row read or state write marks the run failed instead of leaving it running, and a row with no plain recipient fails its chunk instead of being skipped. `retryFieldCryptoMigration` only changes a run that has failed chunks to reprocess, so it no longer flips completed or read-failed runs back to running. The CLI `db tracking migrate apply/retry` commands read the keys from `KMSG_FIELD_CRYPTO_KEYS` and `KMSG_ACTIVE_KID`, accepting base64url or standard base64 keys and rejecting truncated ones before the backfill starts, and `KMSG_FIELD_CRYPTO_AAD_FIELDS` mirrors a store's `aadFields`. Both commands exit with code 3 when the run fails. — Thanks @imjlk!
|
|
34
|
+
|
|
35
|
+
### Patch changes
|
|
36
|
+
|
|
37
|
+
- Updated dependencies: channel@0.31.0, core@0.31.0, messaging@0.31.0, provider@0.31.0, template@0.31.0, k-msg@0.31.0
|
|
38
|
+
|
|
3
39
|
## 0.9.13 — 2026-07-21
|
|
4
40
|
|
|
5
41
|
### Patch changes
|
package/README.md
CHANGED
|
@@ -165,11 +165,11 @@ Required values by provider/channel:
|
|
|
165
165
|
| Provider | Channel | Required config keys | Required send-time values | Notes |
|
|
166
166
|
| --- | --- | --- | --- | --- |
|
|
167
167
|
| `aligo` | `SMS/LMS/MMS` | `apiKey`, `userId` | `to`, `text`, sender (`--from` or `aligo.config.sender`) | MMS also needs image input |
|
|
168
|
-
| `aligo` | `ALIMTALK` | `apiKey`, `userId` | `to`, `template-id`, `vars`, senderKey (`--sender-key`/`--channel` alias/`aligo.config.senderKey`), sender (`--from` or `aligo.config.sender`) | `preflight` validates channel/template access |
|
|
169
|
-
| `iwinv` | `SMS/LMS/MMS` | `
|
|
170
|
-
| `iwinv` | `ALIMTALK` | `apiKey` | `to`, `template-id`, `vars` | If failover/reSend is enabled, sender callback is required (`--from` or sender number in config) |
|
|
168
|
+
| `aligo` | `ALIMTALK` | `apiKey`, `userId` | `to`, `template-id`, `vars`, senderKey (`--sender-key`/`--channel` alias/`aligo.config.senderKey`), sender (`--from` or `aligo.config.sender`) | `preflight` validates channel/template access; the message is the template body with `vars` filled in by name |
|
|
169
|
+
| `iwinv` | `SMS/LMS/MMS` | `smsApiKey`, `smsAuthKey` | `to`, `text`, sender (`--from` or `iwinv.config.smsSenderNumber`/`senderNumber`) | MMS requires image binary input; `apiKey` is only needed for AlimTalk (`config provider add` fills it in by default, so remove it and the `ALIMTALK` route for SMS-only use) |
|
|
170
|
+
| `iwinv` | `ALIMTALK` | `apiKey` | `to`, `template-id`, `vars` | `vars` are matched to the template's `#{name}` placeholders by name. If failover/reSend is enabled, sender callback is required (`--from` or sender number in config) |
|
|
171
171
|
| `solapi` | `SMS/LMS/MMS` | `apiKey`, `apiSecret` | `to`, `text`, sender (`--from` or `solapi.config.defaultFrom`) | MMS also needs image input |
|
|
172
|
-
| `solapi` | `ALIMTALK` | `apiKey`, `apiSecret` | `to`, `template-id`, `vars`, profileId/pfId (`--sender-key`/channel alias or `solapi.config.kakaoPfId`) |
|
|
172
|
+
| `solapi` | `ALIMTALK` | `apiKey`, `apiSecret` | `to`, `template-id`, `vars`, profileId/pfId (`--sender-key`/channel alias or `solapi.config.kakaoPfId`) | SOLAPI identifies the channel by pfId; no `plusId` is needed |
|
|
173
173
|
| `mock` | all | none | minimal message fields (`to`, `text` or `template-id`/`vars`) | Local test provider |
|
|
174
174
|
|
|
175
175
|
### Provider onboarding expectations
|
|
@@ -180,7 +180,7 @@ CLI readiness checks describe the vendor prerequisite path. They do **not** crea
|
|
|
180
180
|
| --- | --- | --- | --- |
|
|
181
181
|
| `iwinv` | Manual console approval | config keys, manual evidence record, template probe, sender fallback config | `k-msg providers doctor` -> `k-msg alimtalk preflight` |
|
|
182
182
|
| `aligo` | API-backed Kakao channel path | config keys, channel/template capabilities, Kakao list probe, plusId inference guidance | `k-msg providers doctor` -> `k-msg alimtalk preflight` |
|
|
183
|
-
| `solapi` | External vendor metadata + explicit binding | config keys,
|
|
183
|
+
| `solapi` | External vendor metadata + explicit binding | config keys, pfId/profileId binding, template probe result when available | `k-msg providers doctor` -> `k-msg alimtalk preflight` |
|
|
184
184
|
| `mock` | Local fixture only | basic capability checks and seed template path | `k-msg providers doctor` -> `k-msg alimtalk preflight` |
|
|
185
185
|
|
|
186
186
|
## Commands
|
|
@@ -225,6 +225,15 @@ k-msg db schema generate \
|
|
|
225
225
|
--format sql \
|
|
226
226
|
--out-dir ./db \
|
|
227
227
|
--sql-file tracking.sql
|
|
228
|
+
|
|
229
|
+
# The tracking table of a store created with
|
|
230
|
+
# { tableName: "otp_tracking", typeStrategy: { timestamp: "date" } }
|
|
231
|
+
k-msg db schema print \
|
|
232
|
+
--dialect postgres \
|
|
233
|
+
--target tracking \
|
|
234
|
+
--format sql \
|
|
235
|
+
--tracking-table otp_tracking \
|
|
236
|
+
--timestamp-type date
|
|
228
237
|
```
|
|
229
238
|
|
|
230
239
|
Flags:
|
|
@@ -232,6 +241,13 @@ Flags:
|
|
|
232
241
|
- `--dialect <postgres|mysql|sqlite>`: required
|
|
233
242
|
- `--target <tracking|queue|both>`: default `both`
|
|
234
243
|
- `--format <drizzle|sql|both>`: default `both`
|
|
244
|
+
- Pass the options your store or queue uses, so the schema matches it:
|
|
245
|
+
- `--message-id-type <text|uuid|varchar>`, `--id-type <text|varchar>`, `--short-text-type <text|varchar>`, `--timestamp-type <bigint|integer|date>`, `--json-type <auto|text>`: the tracking store's `typeStrategy` (defaults `text`, `text`, `varchar`, `bigint`, `auto`). On MySQL, the primary key and the indexed columns are `VARCHAR` whatever these say, since MySQL cannot index `TEXT`
|
|
246
|
+
- `--tracking-table <name>` (default `kmsg_delivery_tracking`) and `--queue-table <name>` (default `kmsg_jobs`)
|
|
247
|
+
- `--store-raw`: adds the tracking `raw` column, as `storeRaw: true` does (default `false`)
|
|
248
|
+
- Not covered by the flags:
|
|
249
|
+
- `columnMap`, `indexNames` and field-crypto (`fieldCryptoSchema`) schemas. For those, build the schema in code with `buildCloudflareSqlSchemaSql()` or `renderDrizzleSchemaSource()` from `@k-msg/messaging/adapters/cloudflare`, passing the store's own options.
|
|
250
|
+
- Index names stay the defaults (`idx_kmsg_delivery_*`, `idx_kmsg_jobs_*`) when a table is renamed. A second table in the same database (or Postgres schema) then skips its `CREATE INDEX IF NOT EXISTS` and gets no indexes, so give it its own `indexNames` in code.
|
|
235
251
|
- `generate` only:
|
|
236
252
|
- `--out-dir <path>` default current directory
|
|
237
253
|
- `--drizzle-file <name>` default `kmsg.schema.ts`
|
|
@@ -252,7 +268,8 @@ k-msg db tracking migrate retry --sqlite-file ./local.db
|
|
|
252
268
|
Operational notes:
|
|
253
269
|
|
|
254
270
|
- state is persisted in DB meta tables plus local snapshots under `.kmsg/migrations`
|
|
255
|
-
- `retry` only replays failed chunks
|
|
271
|
+
- `retry` only replays failed chunks; resume a run that stopped on a read error with `apply`
|
|
272
|
+
- `apply` and `retry` encrypt with the tracking store's keys from `KMSG_FIELD_CRYPTO_KEYS` and `KMSG_ACTIVE_KID` (see `docs/security/migration-cli-runbook.md`)
|
|
256
273
|
- use `status` before changing rollout flags (`compatPlainColumns`)
|
|
257
274
|
|
|
258
275
|
## Recommended AlimTalk flow
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k-msg/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "k-msg CLI (prebuilt binaries via GitHub Releases)",
|
|
6
6
|
"type": "module",
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@gunshi/plugin-completion": "0.35.1",
|
|
38
|
-
"@k-msg/channel": "0.
|
|
39
|
-
"@k-msg/core": "0.
|
|
40
|
-
"@k-msg/messaging": "0.
|
|
41
|
-
"@k-msg/provider": "0.
|
|
42
|
-
"@k-msg/template": "0.
|
|
38
|
+
"@k-msg/channel": "0.32.0",
|
|
39
|
+
"@k-msg/core": "0.32.0",
|
|
40
|
+
"@k-msg/messaging": "0.32.0",
|
|
41
|
+
"@k-msg/provider": "0.32.0",
|
|
42
|
+
"@k-msg/template": "0.32.0",
|
|
43
43
|
"@types/bun": "^1.3.14",
|
|
44
44
|
"@types/node": "^26.0.1",
|
|
45
45
|
"gunshi": "0.35.1",
|
|
46
|
-
"k-msg": "0.
|
|
46
|
+
"k-msg": "0.32.0",
|
|
47
47
|
"solapi": "^6.0.1",
|
|
48
|
-
"ttsc": "^0.
|
|
48
|
+
"ttsc": "^0.30.4",
|
|
49
49
|
"typescript": "^7.0.2",
|
|
50
50
|
"zod": "^4.4.3"
|
|
51
51
|
},
|