@ossy/cli 0.16.10 → 0.16.12
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/README.md
CHANGED
|
@@ -49,18 +49,26 @@ Details:
|
|
|
49
49
|
cd packages/my-website
|
|
50
50
|
npx @ossy/cli publish \
|
|
51
51
|
--username <github-username> \
|
|
52
|
-
--authentication <token> \
|
|
52
|
+
--authentication <github-or-deploy-token> \
|
|
53
|
+
--cms-authentication <ossy-api-jwt> \
|
|
53
54
|
--platforms-path ../infrastructure/platforms.json \
|
|
54
55
|
--deployments-path ../infrastructure/deployments.json
|
|
55
56
|
```
|
|
56
57
|
|
|
58
|
+
- **`--cms-authentication`** — Ossy **API JWT** (from the app’s API tokens) for `POST /resource-templates` and site-artifacts. If omitted, **`--authentication`** is used for CMS calls too (only works when that value is already a valid Ossy JWT). In GitHub Actions, set repo secret **`OSSY_API_KEY`** and pass **`--cms-authentication`** explicitly; the deploy token is usually **not** valid for the API.
|
|
59
|
+
|
|
60
|
+
### Unifying deploy and CMS authentication (future)
|
|
61
|
+
|
|
62
|
+
**`--authentication`** and **`--cms-authentication`** exist because **`deployment deploy`** (via **`@ossy/deployment-tools`**) and the **Ossy HTTP API** currently expect **different** credentials (e.g. GitHub / queue token vs Ossy-signed JWT). They could be merged into **one** flag (or a single env secret in CI) if either: (1) deploy is **no longer** invoked from the CLI and **`publish`** is only CMS/API work, or (2) the deploy path is changed to accept the **same** Ossy-issued token the API uses. That lines up with [**Future direction**](#future-direction-planned) (platform-driven rollouts instead of queue + dual tokens).
|
|
63
|
+
|
|
64
|
+
API and worker packages can use the same pattern: a minimal **`src/config.js`** with string-literal **`domain`** (and optional **`platform`**) matching **`deployments.json`**, then run **`publish`** from **`packages/api`** or **`packages/worker`** with **`--skip-resource-templates`** and **`--skip-site-artifacts`** (no website `workspaceId` / `build/` flow).
|
|
65
|
+
|
|
57
66
|
- **`--domain` / `--platform`** — Optional if `src/config.js` contains string literals `domain: '…'` and `platform: '…'` (or `targetDeploymentPlatform`).
|
|
58
67
|
- **`--config`** — Path to another `config.js` if not `./src/config.js`.
|
|
59
68
|
- If `platform` is omitted but `domain` is set (from flags or config), it is inferred from `deployments.json` when that domain appears under exactly one `targetDeploymentPlatform`.
|
|
60
69
|
- **`--all`** — Runs `deployment deploy-all` for the platform; requires `--platform` or `platform` in config.
|
|
61
70
|
- **Resource templates** — After a successful deploy, the CLI reads **`workspaceId`** / **`resourceTemplates`** from `./src/config.js` (or `--config`) using the **static extraction** described above (not `import()`). If **`workspaceId`** is set and **`resourceTemplates`** is a non-empty array, they are **POST**ed to **`{api}/resource-templates`** with the **`workspaceId`** header (same as the CMS). Skipped when **`--skip-resource-templates`** is set, or when `workspaceId` / `resourceTemplates` are missing or not extractable.
|
|
62
71
|
- **Site artifacts** — Uses the same **static `workspaceId` / `apiUrl` extraction** as resource templates. If **`workspaceId`** is set and **`build/`** exists next to `src/` (i.e. run **`npm run build`** first), the CLI calls **`/site-artifacts/presign-batch`**, **PUT**s each file to S3, then **`/site-artifacts/commit-batch`** so a **`@ossy/platform/site-artifact-batch`** resource is created in the CMS. Skipped with **`--skip-site-artifacts`**, when there is no **`build/`**, or when **`workspaceId`** is missing. Override the build output directory with **`--site-artifacts-build-dir`** (absolute or cwd-relative).
|
|
63
|
-
- **`--cms-authentication`** — Optional token used only for CMS/API steps (templates + site artifacts); defaults to **`--authentication`** (deployment token).
|
|
64
72
|
- **`--api-url`** — Optional API base for CMS calls (e.g. `https://api.ossy.se/api/v0`). Otherwise **`OSSY_API_URL`**, else an **absolute** `apiUrl` from config, else `https://api.ossy.se/api/v0`. Relative app `apiUrl` values (e.g. `/@ossy`) are ignored unless you pass **`--api-url`** or set **`OSSY_API_URL`**.
|
|
65
73
|
|
|
66
74
|
Requires network access so `npx` can run `@ossy/deployment-tools`.
|
|
@@ -102,7 +110,7 @@ jobs:
|
|
|
102
110
|
- name: Upload
|
|
103
111
|
run: |
|
|
104
112
|
npx --yes @ossy/cli cms upload \
|
|
105
|
-
--authentication ${{ secrets.
|
|
113
|
+
--authentication ${{ secrets.OSSY_API_KEY }} \
|
|
106
114
|
--config src/config.js
|
|
107
115
|
```
|
|
108
116
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/cli",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.12",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/ossy-se/packages.git"
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"bin": "./src/index.js",
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@babel/parser": "^7.28.6",
|
|
21
|
-
"@ossy/app": "^0.15.
|
|
21
|
+
"@ossy/app": "^0.15.12",
|
|
22
22
|
"arg": "^5.0.2",
|
|
23
23
|
"glob": "^10.3.10"
|
|
24
24
|
},
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"/src",
|
|
31
31
|
"README.md"
|
|
32
32
|
],
|
|
33
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "1da35d94f324f917d5ea790f838ce8e50214730e"
|
|
34
34
|
}
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strips optional `Bearer ` prefix. The Ossy API expects the raw JWT in `Authorization`.
|
|
3
|
+
* @param {string | undefined} token
|
|
4
|
+
* @returns {string}
|
|
5
|
+
*/
|
|
6
|
+
export function normalizeAuthorizationToken (token) {
|
|
7
|
+
const t = String(token ?? '').trim()
|
|
8
|
+
if (!t) return ''
|
|
9
|
+
return t.replace(/^Bearer\s+/i, '').trim()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {string | undefined} token
|
|
14
|
+
* @param {string} label e.g. "Resource template upload"
|
|
15
|
+
* @returns {string} normalized JWT
|
|
16
|
+
*/
|
|
17
|
+
export function requireCmsAuthentication (token, label) {
|
|
18
|
+
const normalized = normalizeAuthorizationToken(token)
|
|
19
|
+
if (!normalized) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`[@ossy/cli] publish: ${label} needs a non-empty Ossy API JWT. ` +
|
|
22
|
+
'Pass --cms-authentication with a token from the Ossy app (API tokens), or set the OSSY_API_KEY secret in CI. ' +
|
|
23
|
+
'The GitHub token used for --authentication (container deploy) is not accepted by the API.'
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
return normalized
|
|
27
|
+
}
|
|
28
|
+
|
|
1
29
|
/**
|
|
2
30
|
* POST workspace-imported resource templates to the Ossy API.
|
|
3
31
|
* @param {{ apiBaseUrl: string, token: string, workspaceId: string, resourceTemplates: unknown[] }} opts
|
|
@@ -11,10 +39,11 @@ export function postResourceTemplates ({
|
|
|
11
39
|
}) {
|
|
12
40
|
const base = apiBaseUrl.replace(/\/$/, '')
|
|
13
41
|
const url = `${base}/resource-templates`
|
|
42
|
+
const auth = normalizeAuthorizationToken(token)
|
|
14
43
|
return fetch(url, {
|
|
15
44
|
method: 'POST',
|
|
16
45
|
headers: {
|
|
17
|
-
Authorization:
|
|
46
|
+
Authorization: auth,
|
|
18
47
|
'Content-Type': 'application/json',
|
|
19
48
|
workspaceId,
|
|
20
49
|
},
|
|
@@ -2,6 +2,7 @@ import { logInfo } from '../log.js'
|
|
|
2
2
|
import { readPublishFieldsFromWebsiteConfig } from './load-website-config.js'
|
|
3
3
|
import {
|
|
4
4
|
postResourceTemplates,
|
|
5
|
+
requireCmsAuthentication,
|
|
5
6
|
resolveApiBaseUrlForUpload,
|
|
6
7
|
} from '../cms/upload-resource-templates.js'
|
|
7
8
|
|
|
@@ -37,20 +38,35 @@ export async function maybeUploadResourceTemplatesAfterPublish ({
|
|
|
37
38
|
envVar: process.env.OSSY_API_URL,
|
|
38
39
|
configApiUrl: config?.apiUrl,
|
|
39
40
|
})
|
|
41
|
+
const uploadUrl = `${apiBaseUrl.replace(/\/$/, '')}/resource-templates`
|
|
42
|
+
const authToken = requireCmsAuthentication(
|
|
43
|
+
cmsToken,
|
|
44
|
+
'Resource template upload'
|
|
45
|
+
)
|
|
40
46
|
|
|
41
|
-
logInfo({
|
|
47
|
+
logInfo({
|
|
48
|
+
message: `[@ossy/cli] publish: uploading resource templates → POST ${uploadUrl}`,
|
|
49
|
+
})
|
|
42
50
|
|
|
43
51
|
const response = await postResourceTemplates({
|
|
44
52
|
apiBaseUrl,
|
|
45
|
-
token:
|
|
53
|
+
token: authToken,
|
|
46
54
|
workspaceId,
|
|
47
55
|
resourceTemplates,
|
|
48
56
|
})
|
|
49
57
|
|
|
50
58
|
if (!response.ok) {
|
|
51
59
|
const text = await response.text().catch(() => '')
|
|
60
|
+
const hint404 =
|
|
61
|
+
response.status === 404
|
|
62
|
+
? ` Wrong host or path: requested ${uploadUrl}. Confirm OSSY_API_URL / --api-url points at the Ossy API base including /api/v0.`
|
|
63
|
+
: ''
|
|
64
|
+
const hint401 =
|
|
65
|
+
response.status === 401
|
|
66
|
+
? ' Use an Ossy API JWT with --cms-authentication (repo secret OSSY_API_KEY in CI), not the GitHub deploy token.'
|
|
67
|
+
: ''
|
|
52
68
|
throw new Error(
|
|
53
|
-
`Resource template upload failed: HTTP ${response.status}${
|
|
69
|
+
`Resource template upload failed: HTTP ${response.status}${hint404}${hint401}${
|
|
54
70
|
text ? ` — ${text.slice(0, 200)}` : ''
|
|
55
71
|
}`
|
|
56
72
|
)
|
|
@@ -3,7 +3,11 @@ import { existsSync } from 'fs'
|
|
|
3
3
|
import path from 'path'
|
|
4
4
|
import { logInfo } from '../log.js'
|
|
5
5
|
import { readPublishFieldsFromWebsiteConfig } from './load-website-config.js'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
normalizeAuthorizationToken,
|
|
8
|
+
requireCmsAuthentication,
|
|
9
|
+
resolveApiBaseUrlForUpload,
|
|
10
|
+
} from '../cms/upload-resource-templates.js'
|
|
7
11
|
|
|
8
12
|
const MAX_FILES = 200
|
|
9
13
|
|
|
@@ -68,7 +72,7 @@ export async function collectBuildFiles (buildDir) {
|
|
|
68
72
|
|
|
69
73
|
function workspaceHeaders (token, workspaceId) {
|
|
70
74
|
return {
|
|
71
|
-
Authorization: token,
|
|
75
|
+
Authorization: normalizeAuthorizationToken(token),
|
|
72
76
|
'Content-Type': 'application/json',
|
|
73
77
|
workspaceId,
|
|
74
78
|
}
|
|
@@ -123,11 +127,16 @@ export async function maybeUploadSiteArtifactsAfterPublish ({
|
|
|
123
127
|
)
|
|
124
128
|
}
|
|
125
129
|
|
|
130
|
+
const authToken = requireCmsAuthentication(
|
|
131
|
+
cmsToken,
|
|
132
|
+
'Site artifact upload'
|
|
133
|
+
)
|
|
134
|
+
|
|
126
135
|
logInfo({ message: `[@ossy/cli] publish: uploading ${files.length} site artifact file(s) to CMS…` })
|
|
127
136
|
|
|
128
137
|
const presignRes = await fetch(`${apiBaseUrl}/site-artifacts/presign-batch`, {
|
|
129
138
|
method: 'POST',
|
|
130
|
-
headers: workspaceHeaders(
|
|
139
|
+
headers: workspaceHeaders(authToken, workspaceId),
|
|
131
140
|
body: JSON.stringify({
|
|
132
141
|
files: files.map((f) => ({
|
|
133
142
|
path: f.relativePath,
|
|
@@ -182,7 +191,7 @@ export async function maybeUploadSiteArtifactsAfterPublish ({
|
|
|
182
191
|
|
|
183
192
|
const commitRes = await fetch(`${apiBaseUrl}/site-artifacts/commit-batch`, {
|
|
184
193
|
method: 'POST',
|
|
185
|
-
headers: workspaceHeaders(
|
|
194
|
+
headers: workspaceHeaders(authToken, workspaceId),
|
|
186
195
|
body: JSON.stringify({
|
|
187
196
|
batchId,
|
|
188
197
|
paths: files.map((f) => f.relativePath),
|