@technomoron/mail-magic-client 1.0.34 → 2.0.0-beta1
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/CHANGES +29 -0
- package/README.md +3 -4
- package/dist/cjs/mail-magic-client.d.ts +4 -0
- package/dist/cjs/mail-magic-client.js +20 -23
- package/dist/esm/mail-magic-client.js +20 -23
- package/package.json +48 -46
package/CHANGES
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
CHANGES
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
+
Unreleased (2026-03-07)
|
|
5
|
+
|
|
6
|
+
- fix(release): switch the GitHub client publish job to npm trusted publishing by removing the forced `NODE_AUTH_TOKEN`, so npm can authorize `release-mail-magic-client.yml` through the configured OIDC publisher instead of the repository token.
|
|
7
|
+
- fix(release): move the GitHub client workflow npm auth token to job scope so the publish step inherits the same registry credentials used earlier in the run instead of overriding them with an empty step-local value.
|
|
8
|
+
- fix(release): allow the GitHub client workflow to publish and create the GitHub release when manually dispatched on an existing client tag, so a failed tagged release can be retried without minting a new version.
|
|
9
|
+
- chore(release): add package-local `release:preflight` support so a single package can run cleanbuild, tests, and local release checks from its own directory.
|
|
10
|
+
- chore(release): stop using `setup-node` pnpm caching in the GitHub client release workflow because this repo does not ship a `pnpm-lock.yaml`.
|
|
11
|
+
- chore(release): install workspace dependencies with `pnpm install --no-frozen-lockfile --link-workspace-packages` in the GitHub client release workflow because this repo does not ship a `pnpm-lock.yaml` and the CLI depends on the local prerelease client package.
|
|
12
|
+
- chore(release): add a repo-level pnpm build-script allowlist for `sqlite3` and `esbuild`, while explicitly blocking `@scarf/scarf`, so clean GitHub installs can run the shared test/build pipeline before publishing the client.
|
|
13
|
+
- (Changes generated/assisted by Codex (profile: openai-gpt-5-codex/medium).)
|
|
14
|
+
|
|
15
|
+
Version 2.0.0-beta1 (2026-03-07)
|
|
16
|
+
|
|
17
|
+
- chore(release): stage the `2.0.0-beta1` prerelease and align package metadata with it.
|
|
18
|
+
- chore(release): add shared local/CI release verification flow and update the GitHub client release workflow to use it on Node 24.
|
|
19
|
+
- chore(release): publish tagged GitHub client releases to npm via a shared `npm publish` flow and add a local publish dry-run path for pre-tag testing.
|
|
20
|
+
- (Changes generated/assisted by Codex (profile: openai-gpt-5-codex/medium).)
|
|
21
|
+
|
|
22
|
+
Version 1.0.36 (2026-03-06)
|
|
23
|
+
|
|
24
|
+
- feat(client): add `triggerReload()` method to trigger a server-side force-reload via `POST /api/v1/reload`.
|
|
25
|
+
- docs(readme): remove references to server-side `ASSET_ROUTE` config and describe the fixed `/asset` and compatibility `/api/asset` routes.
|
|
26
|
+
- (Changes generated/assisted by Codex (profile: openai-gpt-5-codex/medium).)
|
|
27
|
+
|
|
28
|
+
Version 1.0.35 (2026-03-05)
|
|
29
|
+
|
|
30
|
+
- fix(client): check response `content-type` header in `postFormData` before calling `response.json()`; extract shared `parseJsonResponse` helper used by both `request()` and `postFormData()`.
|
|
31
|
+
- (Changes generated/assisted by Claude Code (profile: anthropic-claude-opus-4-6/high).)
|
|
32
|
+
|
|
4
33
|
Version 1.0.34 (2026-03-04)
|
|
5
34
|
|
|
6
35
|
- chore(dist): remove generated `dist/mail-magic-client.js` artifact from package tree.
|
package/README.md
CHANGED
|
@@ -104,7 +104,6 @@ The CLI is now a separate package: `@technomoron/mail-magic-cli`.
|
|
|
104
104
|
- `await client.fetchPublicAsset('example.test', 'images/logo.png')` -> `/asset/{domain}/{path}`
|
|
105
105
|
- `await client.fetchPublicAsset('example.test', 'images/logo.png', true)` -> `/api/asset/{domain}/{path}`
|
|
106
106
|
|
|
107
|
-
The third argument `viaApiBase` (default `false`) switches the route prefix. Use `false` (default)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
forwards requests under a single path prefix.
|
|
107
|
+
The third argument `viaApiBase` (default `false`) switches the route prefix. Use `false` (default) for the normal
|
|
108
|
+
public asset route (`/asset`). Use `true` when you need the compatibility API route (`/api/asset`) — useful when a
|
|
109
|
+
reverse proxy only forwards requests under the API prefix.
|
|
@@ -77,6 +77,7 @@ declare class TemplateClient {
|
|
|
77
77
|
private baseURL;
|
|
78
78
|
private apiKey;
|
|
79
79
|
constructor(baseURL: string, apiKey: string);
|
|
80
|
+
private parseJsonResponse;
|
|
80
81
|
request<T>(method: 'GET' | 'POST' | 'PUT' | 'DELETE', command: string, body?: RequestBody): Promise<T>;
|
|
81
82
|
get<T>(command: string): Promise<T>;
|
|
82
83
|
post<T>(command: string, body: RequestBody): Promise<T>;
|
|
@@ -99,6 +100,9 @@ declare class TemplateClient {
|
|
|
99
100
|
storeFormRecipient(data: StoreFormRecipientInput): Promise<ApiResponse>;
|
|
100
101
|
sendFormMessage(data: SendFormMessageInput): Promise<ApiResponse>;
|
|
101
102
|
uploadAssets(data: UploadAssetsInput): Promise<ApiResponse>;
|
|
103
|
+
triggerReload(): Promise<ApiResponse<{
|
|
104
|
+
reload: string;
|
|
105
|
+
}>>;
|
|
102
106
|
getSwaggerSpec(): Promise<ApiResponse>;
|
|
103
107
|
fetchPublicAsset(domain: string, assetPath: string, viaApiBase?: boolean): Promise<ArrayBuffer>;
|
|
104
108
|
}
|
|
@@ -15,6 +15,21 @@ class TemplateClient {
|
|
|
15
15
|
throw new Error('Apikey/api-url required');
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
async parseJsonResponse(response) {
|
|
19
|
+
const contentType = response.headers.get('content-type') || '';
|
|
20
|
+
if (!contentType.includes('application/json')) {
|
|
21
|
+
const text = await response.text();
|
|
22
|
+
throw new Error(`FETCH FAILED: ${response.status} unexpected content-type "${contentType}" - ${text.slice(0, 200)}`);
|
|
23
|
+
}
|
|
24
|
+
const j = await response.json();
|
|
25
|
+
if (response.ok) {
|
|
26
|
+
return j;
|
|
27
|
+
}
|
|
28
|
+
if (j && j.message) {
|
|
29
|
+
throw new Error(`FETCH FAILED: ${response.status} ${j.message}`);
|
|
30
|
+
}
|
|
31
|
+
throw new Error(`FETCH FAILED: ${response.status} ${response.statusText}`);
|
|
32
|
+
}
|
|
18
33
|
async request(method, command, body) {
|
|
19
34
|
const url = `${this.baseURL}${command}`;
|
|
20
35
|
const headers = {
|
|
@@ -31,21 +46,7 @@ class TemplateClient {
|
|
|
31
46
|
options.body = JSON.stringify(body);
|
|
32
47
|
}
|
|
33
48
|
const response = await fetch(url, options);
|
|
34
|
-
|
|
35
|
-
if (!contentType.includes('application/json')) {
|
|
36
|
-
const text = await response.text();
|
|
37
|
-
throw new Error(`FETCH FAILED: ${response.status} unexpected content-type "${contentType}" - ${text.slice(0, 200)}`);
|
|
38
|
-
}
|
|
39
|
-
const j = await response.json();
|
|
40
|
-
if (response.ok) {
|
|
41
|
-
return j;
|
|
42
|
-
}
|
|
43
|
-
if (j && j.message) {
|
|
44
|
-
throw new Error(`FETCH FAILED: ${response.status} ${j.message}`);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
throw new Error(`FETCH FAILED: ${response.status} ${response.statusText}`);
|
|
48
|
-
}
|
|
49
|
+
return this.parseJsonResponse(response);
|
|
49
50
|
}
|
|
50
51
|
async get(command) {
|
|
51
52
|
return this.request('GET', command);
|
|
@@ -144,14 +145,7 @@ class TemplateClient {
|
|
|
144
145
|
},
|
|
145
146
|
body: formData
|
|
146
147
|
});
|
|
147
|
-
|
|
148
|
-
if (response.ok) {
|
|
149
|
-
return j;
|
|
150
|
-
}
|
|
151
|
-
if (j && j.message) {
|
|
152
|
-
throw new Error(`FETCH FAILED: ${response.status} ${j.message}`);
|
|
153
|
-
}
|
|
154
|
-
throw new Error(`FETCH FAILED: ${response.status} ${response.statusText}`);
|
|
148
|
+
return this.parseJsonResponse(response);
|
|
155
149
|
}
|
|
156
150
|
async storeTemplate(td) {
|
|
157
151
|
// Backward-compatible alias for transactional template storage.
|
|
@@ -299,6 +293,9 @@ class TemplateClient {
|
|
|
299
293
|
});
|
|
300
294
|
return this.postFormData('/api/v1/assets', formData);
|
|
301
295
|
}
|
|
296
|
+
async triggerReload() {
|
|
297
|
+
return this.post('/api/v1/reload', {});
|
|
298
|
+
}
|
|
302
299
|
async getSwaggerSpec() {
|
|
303
300
|
return this.get('/api/swagger');
|
|
304
301
|
}
|
|
@@ -10,6 +10,21 @@ class TemplateClient {
|
|
|
10
10
|
throw new Error('Apikey/api-url required');
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
+
async parseJsonResponse(response) {
|
|
14
|
+
const contentType = response.headers.get('content-type') || '';
|
|
15
|
+
if (!contentType.includes('application/json')) {
|
|
16
|
+
const text = await response.text();
|
|
17
|
+
throw new Error(`FETCH FAILED: ${response.status} unexpected content-type "${contentType}" - ${text.slice(0, 200)}`);
|
|
18
|
+
}
|
|
19
|
+
const j = await response.json();
|
|
20
|
+
if (response.ok) {
|
|
21
|
+
return j;
|
|
22
|
+
}
|
|
23
|
+
if (j && j.message) {
|
|
24
|
+
throw new Error(`FETCH FAILED: ${response.status} ${j.message}`);
|
|
25
|
+
}
|
|
26
|
+
throw new Error(`FETCH FAILED: ${response.status} ${response.statusText}`);
|
|
27
|
+
}
|
|
13
28
|
async request(method, command, body) {
|
|
14
29
|
const url = `${this.baseURL}${command}`;
|
|
15
30
|
const headers = {
|
|
@@ -26,21 +41,7 @@ class TemplateClient {
|
|
|
26
41
|
options.body = JSON.stringify(body);
|
|
27
42
|
}
|
|
28
43
|
const response = await fetch(url, options);
|
|
29
|
-
|
|
30
|
-
if (!contentType.includes('application/json')) {
|
|
31
|
-
const text = await response.text();
|
|
32
|
-
throw new Error(`FETCH FAILED: ${response.status} unexpected content-type "${contentType}" - ${text.slice(0, 200)}`);
|
|
33
|
-
}
|
|
34
|
-
const j = await response.json();
|
|
35
|
-
if (response.ok) {
|
|
36
|
-
return j;
|
|
37
|
-
}
|
|
38
|
-
if (j && j.message) {
|
|
39
|
-
throw new Error(`FETCH FAILED: ${response.status} ${j.message}`);
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
throw new Error(`FETCH FAILED: ${response.status} ${response.statusText}`);
|
|
43
|
-
}
|
|
44
|
+
return this.parseJsonResponse(response);
|
|
44
45
|
}
|
|
45
46
|
async get(command) {
|
|
46
47
|
return this.request('GET', command);
|
|
@@ -139,14 +140,7 @@ class TemplateClient {
|
|
|
139
140
|
},
|
|
140
141
|
body: formData
|
|
141
142
|
});
|
|
142
|
-
|
|
143
|
-
if (response.ok) {
|
|
144
|
-
return j;
|
|
145
|
-
}
|
|
146
|
-
if (j && j.message) {
|
|
147
|
-
throw new Error(`FETCH FAILED: ${response.status} ${j.message}`);
|
|
148
|
-
}
|
|
149
|
-
throw new Error(`FETCH FAILED: ${response.status} ${response.statusText}`);
|
|
143
|
+
return this.parseJsonResponse(response);
|
|
150
144
|
}
|
|
151
145
|
async storeTemplate(td) {
|
|
152
146
|
// Backward-compatible alias for transactional template storage.
|
|
@@ -294,6 +288,9 @@ class TemplateClient {
|
|
|
294
288
|
});
|
|
295
289
|
return this.postFormData('/api/v1/assets', formData);
|
|
296
290
|
}
|
|
291
|
+
async triggerReload() {
|
|
292
|
+
return this.post('/api/v1/reload', {});
|
|
293
|
+
}
|
|
297
294
|
async getSwaggerSpec() {
|
|
298
295
|
return this.get('/api/swagger');
|
|
299
296
|
}
|
package/package.json
CHANGED
|
@@ -1,47 +1,49 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
2
|
+
"name": "@technomoron/mail-magic-client",
|
|
3
|
+
"version": "2.0.0-beta1",
|
|
4
|
+
"description": "Client library for mail-magic",
|
|
5
|
+
"main": "dist/cjs/mail-magic-client.js",
|
|
6
|
+
"types": "dist/cjs/mail-magic-client.d.ts",
|
|
7
|
+
"module": "dist/esm/mail-magic-client.js",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"prepare": "run-s build",
|
|
10
|
+
"scrub": "rimraf node_modules pnpm-lock.yaml package-lock.json yarn.lock lib/ dist/",
|
|
11
|
+
"build:cjs": "tsc --project tsconfig/tsconfig.cjs.json",
|
|
12
|
+
"build:esm": "tsc --project tsconfig/tsconfig.esm.json",
|
|
13
|
+
"build": "run-s build:cjs build:esm",
|
|
14
|
+
"test": "vitest run --silent --reporter=dot",
|
|
15
|
+
"test:watch": "vitest",
|
|
16
|
+
"lint": "node ../../node_modules/eslint/bin/eslint.js --config ../../eslint.config.mjs --no-error-on-unmatched-pattern ./src",
|
|
17
|
+
"lintfix": "node ../../node_modules/eslint/bin/eslint.js --config ../../eslint.config.mjs --fix --no-error-on-unmatched-pattern ./src",
|
|
18
|
+
"format": "run-s lintfix pretty",
|
|
19
|
+
"pretty": "node ../../node_modules/prettier/bin/prettier.cjs --config ../../.prettierrc --write \"**/*.{js,ts,vue,json,css,scss,md}\"",
|
|
20
|
+
"cleanbuild": "run-s clean:dist format build",
|
|
21
|
+
"clean:dist": "rimraf ./dist/",
|
|
22
|
+
"release": "bash ../../scripts/release-package.sh .",
|
|
23
|
+
"release:check": "bash ../../scripts/release-package-check.sh .",
|
|
24
|
+
"release:preflight": "bash ../../scripts/release-package-preflight.sh ."
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/technomoron/mail-magic.git",
|
|
29
|
+
"directory": "packages/client"
|
|
30
|
+
},
|
|
31
|
+
"author": "Bjørn Erik Jacobsen",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist/**/*.js",
|
|
35
|
+
"dist/**/*.d.ts",
|
|
36
|
+
"package.json",
|
|
37
|
+
"CHANGES"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"email-addresses": "^5.0.0",
|
|
41
|
+
"nunjucks": "^3.2.4"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.19.11",
|
|
45
|
+
"@types/nunjucks": "^3.2.6",
|
|
46
|
+
"typescript": "^5.9.2",
|
|
47
|
+
"vitest": "^4.0.16"
|
|
48
|
+
}
|
|
49
|
+
}
|