@ossy/cli 1.16.11 → 1.17.4

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.
@@ -1,75 +0,0 @@
1
- import { logInfo } from '../log.js'
2
- import { readPublishFieldsFromWebsiteConfig } from './load-website-config.js'
3
- import {
4
- postResourceTemplates,
5
- requireCmsAuthentication,
6
- resolveApiBaseUrlForUpload,
7
- } from '../cms/upload-resource-templates.js'
8
-
9
- /**
10
- * After a successful deployment, sync `resourceTemplates` from app config to the workspace API.
11
- */
12
- export async function maybeUploadResourceTemplatesAfterPublish ({
13
- configPath,
14
- cmsToken,
15
- apiUrlFlag,
16
- }) {
17
- const config = readPublishFieldsFromWebsiteConfig(configPath)
18
- const workspaceId = config.workspaceId
19
- const resourceTemplates = config.resourceTemplates
20
-
21
- if (!workspaceId) {
22
- logInfo({
23
- message:
24
- '[@ossy/cli] publish: skipping resource template upload (no workspaceId in config)',
25
- })
26
- return
27
- }
28
- if (!Array.isArray(resourceTemplates) || resourceTemplates.length === 0) {
29
- logInfo({
30
- message:
31
- '[@ossy/cli] publish: skipping resource template upload (resourceTemplates missing or empty)',
32
- })
33
- return
34
- }
35
-
36
- const apiBaseUrl = resolveApiBaseUrlForUpload({
37
- flag: apiUrlFlag,
38
- envVar: process.env.OSSY_API_URL,
39
- configApiUrl: config?.apiUrl,
40
- })
41
- const uploadUrl = `${apiBaseUrl.replace(/\/$/, '')}/resource-templates`
42
- const authToken = requireCmsAuthentication(
43
- cmsToken,
44
- 'Resource template upload'
45
- )
46
-
47
- logInfo({
48
- message: `[@ossy/cli] publish: uploading resource templates → POST ${uploadUrl}`,
49
- })
50
-
51
- const response = await postResourceTemplates({
52
- apiBaseUrl,
53
- token: authToken,
54
- workspaceId,
55
- resourceTemplates,
56
- })
57
-
58
- if (!response.ok) {
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 --authentication (or OSSY_API_KEY in CI), not a non-API deploy token.'
67
- : ''
68
- throw new Error(
69
- `Resource template upload failed: HTTP ${response.status}${hint404}${hint401}${
70
- text ? ` — ${text.slice(0, 200)}` : ''
71
- }`
72
- )
73
- }
74
- logInfo({ message: '[@ossy/cli] publish: resource templates uploaded' })
75
- }
@@ -1,183 +0,0 @@
1
- import { readdir, stat, readFile } from 'fs/promises'
2
- import { existsSync } from 'fs'
3
- import path from 'path'
4
- import { logInfo } from '../log.js'
5
- import { readPublishFieldsFromWebsiteConfig } from './load-website-config.js'
6
- import {
7
- normalizeAuthorizationToken,
8
- requireCmsAuthentication,
9
- resolveApiBaseUrlForUpload,
10
- } from '../cms/upload-resource-templates.js'
11
- import { guessContentType } from '../file.js'
12
-
13
- const MAX_FILES = 200
14
-
15
- export { guessContentType }
16
-
17
- /**
18
- * @param {string} buildDir absolute path to `build/` output
19
- * @returns {Promise<{ absPath: string, relativePath: string, size: number }[]>}
20
- */
21
- export async function collectBuildFiles (buildDir) {
22
- const out = []
23
-
24
- async function walk (dir, rel = '') {
25
- const entries = await readdir(dir, { withFileTypes: true })
26
- for (const e of entries) {
27
- const abs = path.join(dir, e.name)
28
- const relPath = rel ? `${rel}/${e.name}` : e.name
29
- if (e.isDirectory()) {
30
- await walk(abs, relPath)
31
- } else {
32
- const st = await stat(abs)
33
- out.push({
34
- absPath: abs,
35
- relativePath: relPath.split(path.sep).join('/'),
36
- size: st.size,
37
- })
38
- }
39
- }
40
- }
41
-
42
- await walk(buildDir)
43
- return out
44
- }
45
-
46
- function workspaceHeaders (token, workspaceId) {
47
- return {
48
- Authorization: normalizeAuthorizationToken(token),
49
- 'Content-Type': 'application/json',
50
- workspaceId,
51
- }
52
- }
53
-
54
- /**
55
- * After deploy: upload `build/` to S3 via presigned URLs and commit a CMS resource (`@ossy/platform/site-artifact-batch`).
56
- */
57
- export async function maybeUploadSiteArtifactsAfterPublish ({
58
- configPath,
59
- cmsToken,
60
- apiUrlFlag,
61
- buildDir: buildDirOpt,
62
- }) {
63
- const config = readPublishFieldsFromWebsiteConfig(configPath)
64
- const workspaceId = config.workspaceId
65
-
66
- if (!workspaceId) {
67
- logInfo({
68
- message:
69
- '[@ossy/cli] publish: skipping site artifacts (no workspaceId in config)',
70
- })
71
- return
72
- }
73
-
74
- const packageRoot = path.join(path.dirname(configPath), '..')
75
- const buildDir = buildDirOpt
76
- ? path.resolve(buildDirOpt)
77
- : path.join(packageRoot, 'build')
78
-
79
- if (!existsSync(buildDir)) {
80
- logInfo({
81
- message: `[@ossy/cli] publish: skipping site artifacts (no build at ${buildDir}; run npm run build first)`,
82
- })
83
- return
84
- }
85
-
86
- const apiBaseUrl = resolveApiBaseUrlForUpload({
87
- flag: apiUrlFlag,
88
- envVar: process.env.OSSY_API_URL,
89
- configApiUrl: config.apiUrl,
90
- })
91
-
92
- const files = await collectBuildFiles(buildDir)
93
- if (files.length === 0) {
94
- logInfo({ message: '[@ossy/cli] publish: skipping site artifacts (build directory is empty)' })
95
- return
96
- }
97
- if (files.length > MAX_FILES) {
98
- throw new Error(
99
- `[@ossy/cli] publish: site artifact upload supports at most ${MAX_FILES} files; build has ${files.length}`
100
- )
101
- }
102
-
103
- const authToken = requireCmsAuthentication(
104
- cmsToken,
105
- 'Site artifact upload'
106
- )
107
-
108
- logInfo({ message: `[@ossy/cli] publish: uploading ${files.length} site artifact file(s) to CMS…` })
109
-
110
- const presignRes = await fetch(`${apiBaseUrl}/site-artifacts/presign-batch`, {
111
- method: 'POST',
112
- headers: workspaceHeaders(authToken, workspaceId),
113
- body: JSON.stringify({
114
- files: files.map((f) => ({
115
- path: f.relativePath,
116
- contentType: guessContentType(f.relativePath),
117
- contentLength: f.size,
118
- })),
119
- }),
120
- })
121
-
122
- if (!presignRes.ok) {
123
- const text = await presignRes.text().catch(() => '')
124
- throw new Error(
125
- `Site artifact presign failed: HTTP ${presignRes.status}${text ? ` — ${text.slice(0, 300)}` : ''}`
126
- )
127
- }
128
-
129
- /** @type {{ batchId: string, files: { path: string, key: string, uploadUrl: string, contentType: string, contentLength: number }[] }} */
130
- const presignJson = await presignRes.json()
131
- const { batchId, files: uploadSlots } = presignJson
132
-
133
- if (!batchId || !Array.isArray(uploadSlots) || uploadSlots.length !== files.length) {
134
- throw new Error('[@ossy/cli] publish: invalid presign-batch response')
135
- }
136
-
137
- const byPath = new Map(uploadSlots.map((s) => [s.path, s]))
138
-
139
- for (const local of files) {
140
- const slot = byPath.get(local.relativePath)
141
- if (!slot?.uploadUrl) {
142
- throw new Error(`[@ossy/cli] publish: presign response missing entry for ${local.relativePath}`)
143
- }
144
- const body = await readFile(local.absPath)
145
- if (body.length !== local.size) {
146
- throw new Error(`[@ossy/cli] publish: file size mismatch for ${local.relativePath}`)
147
- }
148
- const putRes = await fetch(slot.uploadUrl, {
149
- method: 'PUT',
150
- headers: {
151
- 'Content-Type': slot.contentType,
152
- 'Content-Length': String(slot.contentLength),
153
- },
154
- body,
155
- })
156
- if (!putRes.ok) {
157
- const t = await putRes.text().catch(() => '')
158
- throw new Error(
159
- `S3 PUT failed for ${local.relativePath}: HTTP ${putRes.status}${t ? ` — ${t.slice(0, 200)}` : ''}`
160
- )
161
- }
162
- }
163
-
164
-
165
- const commitRes = await fetch(`${apiBaseUrl}/site-artifacts/commit-batch`, {
166
- method: 'POST',
167
- headers: workspaceHeaders(authToken, workspaceId),
168
- body: JSON.stringify({
169
- batchId,
170
- paths: files.map((f) => f.relativePath),
171
- name: batchId,
172
- }),
173
- })
174
-
175
- if (!commitRes.ok) {
176
- const text = await commitRes.text().catch(() => '')
177
- throw new Error(
178
- `Site artifact commit failed: HTTP ${commitRes.status}${text ? ` — ${text.slice(0, 300)}` : ''}`
179
- )
180
- }
181
-
182
- logInfo({ message: '[@ossy/cli] publish: site artifacts uploaded and CMS resource created' })
183
- }