@forumulate/cli 0.3.5 → 0.4.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/README.md +100 -21
- package/dist/api-base.d.ts +26 -7
- package/dist/api-base.d.ts.map +1 -1
- package/dist/api-base.js +38 -8
- package/dist/api-base.js.map +1 -1
- package/dist/cli.js +25 -1
- package/dist/cli.js.map +1 -1
- package/dist/credentials.d.ts +1 -1
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +113 -44
- package/dist/doctor.js.map +1 -1
- package/dist/publish/api.d.ts +95 -0
- package/dist/publish/api.d.ts.map +1 -0
- package/dist/publish/api.js +265 -0
- package/dist/publish/api.js.map +1 -0
- package/dist/publish/command.d.ts +44 -0
- package/dist/publish/command.d.ts.map +1 -0
- package/dist/publish/command.js +246 -0
- package/dist/publish/command.js.map +1 -0
- package/dist/publish/compare.d.ts +45 -0
- package/dist/publish/compare.d.ts.map +1 -0
- package/dist/publish/compare.js +124 -0
- package/dist/publish/compare.js.map +1 -0
- package/dist/publish/context.d.ts +46 -0
- package/dist/publish/context.d.ts.map +1 -0
- package/dist/publish/context.js +54 -0
- package/dist/publish/context.js.map +1 -0
- package/dist/publish/docs-apply.d.ts +39 -0
- package/dist/publish/docs-apply.d.ts.map +1 -0
- package/dist/publish/docs-apply.js +178 -0
- package/dist/publish/docs-apply.js.map +1 -0
- package/dist/publish/docs-plan.d.ts +40 -0
- package/dist/publish/docs-plan.d.ts.map +1 -0
- package/dist/publish/docs-plan.js +211 -0
- package/dist/publish/docs-plan.js.map +1 -0
- package/dist/publish/docs-reconcile.d.ts +26 -0
- package/dist/publish/docs-reconcile.d.ts.map +1 -0
- package/dist/publish/docs-reconcile.js +162 -0
- package/dist/publish/docs-reconcile.js.map +1 -0
- package/dist/publish/extras.d.ts +25 -0
- package/dist/publish/extras.d.ts.map +1 -0
- package/dist/publish/extras.js +218 -0
- package/dist/publish/extras.js.map +1 -0
- package/dist/publish/frontmatter.d.ts +45 -0
- package/dist/publish/frontmatter.d.ts.map +1 -0
- package/dist/publish/frontmatter.js +265 -0
- package/dist/publish/frontmatter.js.map +1 -0
- package/dist/publish/manifest.d.ts +5 -0
- package/dist/publish/manifest.d.ts.map +1 -0
- package/dist/publish/manifest.js +144 -0
- package/dist/publish/manifest.js.map +1 -0
- package/dist/publish/posts.d.ts +39 -0
- package/dist/publish/posts.d.ts.map +1 -0
- package/dist/publish/posts.js +350 -0
- package/dist/publish/posts.js.map +1 -0
- package/dist/publish/rewrite.d.ts +20 -0
- package/dist/publish/rewrite.d.ts.map +1 -0
- package/dist/publish/rewrite.js +82 -0
- package/dist/publish/rewrite.js.map +1 -0
- package/dist/publish/scan.d.ts +25 -0
- package/dist/publish/scan.d.ts.map +1 -0
- package/dist/publish/scan.js +351 -0
- package/dist/publish/scan.js.map +1 -0
- package/dist/publish/types.d.ts +155 -0
- package/dist/publish/types.d.ts.map +1 -0
- package/dist/publish/types.js +13 -0
- package/dist/publish/types.js.map +1 -0
- package/dist/run.d.ts +10 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +71 -51
- package/dist/run.js.map +1 -1
- package/package.json +4 -3
- package/dist/publish-dir.d.ts +0 -54
- package/dist/publish-dir.d.ts.map +0 -1
- package/dist/publish-dir.js +0 -119
- package/dist/publish-dir.js.map +0 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ForumulateClient } from '@forumulate/sdk';
|
|
2
|
+
import type { LiveCollection, LivePage, LivePost } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Every call the publisher makes, through `@forumulate/sdk`.
|
|
5
|
+
*
|
|
6
|
+
* Two things every customer publisher re-learned are built in here once:
|
|
7
|
+
*
|
|
8
|
+
* - A 429 is a pause, not a failure. Reading 38 pages as fast as the event
|
|
9
|
+
* loop allows is indistinguishable from a scraper (an earlier publisher met
|
|
10
|
+
* this after its import had already landed, and reported a crash on work
|
|
11
|
+
* that succeeded). Retries honour `Retry-After`, then back off.
|
|
12
|
+
* - Writes are paced. Per-page reorder is one request per page, and
|
|
13
|
+
* a publisher that fires 400 of them at once spends the rest of the run in
|
|
14
|
+
* 429s.
|
|
15
|
+
*
|
|
16
|
+
* And one that is ours: a dry run CANNOT write. Every mutating method checks
|
|
17
|
+
* `readOnly` and throws, so a planning bug fails loudly instead of quietly
|
|
18
|
+
* publishing.
|
|
19
|
+
*/
|
|
20
|
+
export interface ApiOptions {
|
|
21
|
+
client: ForumulateClient;
|
|
22
|
+
/** Whether a token is present — decides authenticated vs public reads. */
|
|
23
|
+
authed: boolean;
|
|
24
|
+
readOnly: boolean;
|
|
25
|
+
/** Minimum gap between writes, ms. */
|
|
26
|
+
paceMs: number;
|
|
27
|
+
/** Multipart upload is the one call the SDK's JSON `request` cannot make. */
|
|
28
|
+
upload?: (path: string, form: FormData) => Promise<unknown>;
|
|
29
|
+
sleep?: (ms: number) => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
type Q = Record<string, string | number | boolean | undefined>;
|
|
32
|
+
export declare const isUuid: (s: string) => boolean;
|
|
33
|
+
export declare class PublishApi {
|
|
34
|
+
readonly opts: ApiOptions;
|
|
35
|
+
private lastWrite;
|
|
36
|
+
/** Writes this run made, for the summary — and for a test to assert none happened. */
|
|
37
|
+
writes: number;
|
|
38
|
+
constructor(opts: ApiOptions);
|
|
39
|
+
private call;
|
|
40
|
+
get<T>(path: string, query?: Q): Promise<T>;
|
|
41
|
+
post<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
42
|
+
patch<T>(path: string, body: unknown): Promise<T>;
|
|
43
|
+
put<T>(path: string, body: unknown): Promise<T>;
|
|
44
|
+
del<T>(path: string): Promise<T>;
|
|
45
|
+
/** Walk a cursor-paged list to the end. */
|
|
46
|
+
all<T>(path: string, key: string, query?: Q): Promise<T[]>;
|
|
47
|
+
orgId(ref: string): Promise<string>;
|
|
48
|
+
/** The space by id or slug, or null when it does not exist. */
|
|
49
|
+
space(org: string, ref: string): Promise<{
|
|
50
|
+
id: string;
|
|
51
|
+
slug: string;
|
|
52
|
+
type: string;
|
|
53
|
+
orgId: string;
|
|
54
|
+
} | null>;
|
|
55
|
+
/**
|
|
56
|
+
* Collections and pages as they are now. Anonymous reads see only what is
|
|
57
|
+
* published — the plan says so rather than presenting a partial view as whole.
|
|
58
|
+
*/
|
|
59
|
+
docs(org: string, space: string): Promise<{
|
|
60
|
+
collections: LiveCollection[];
|
|
61
|
+
pages: LivePage[];
|
|
62
|
+
fieldKeys: string[];
|
|
63
|
+
publicRows: Map<string, Record<string, unknown>>;
|
|
64
|
+
}>;
|
|
65
|
+
/** Every page's markdown, in one paged walk when authenticated. */
|
|
66
|
+
markdownById(org: string, space: string): Promise<Map<string, string>>;
|
|
67
|
+
/** One published page's markdown, the way a reader (or an agent) gets it. */
|
|
68
|
+
publicMarkdown(org: string, space: string, pageId: string): Promise<string | null>;
|
|
69
|
+
pageMeta(org: string, space: string, pageId: string): Promise<Record<string, unknown>>;
|
|
70
|
+
posts(org: string, space: string, type: string): Promise<LivePost[] | null>;
|
|
71
|
+
shape(org: string, space: string): Promise<{
|
|
72
|
+
sections: {
|
|
73
|
+
key: string;
|
|
74
|
+
required?: boolean;
|
|
75
|
+
role?: string;
|
|
76
|
+
schemaProperty?: string;
|
|
77
|
+
}[];
|
|
78
|
+
params: {
|
|
79
|
+
key: string;
|
|
80
|
+
}[];
|
|
81
|
+
}>;
|
|
82
|
+
assets(org: string, space: string): Promise<Map<string, string>>;
|
|
83
|
+
/**
|
|
84
|
+
* Upload once, by content. The stored name carries a hash of the bytes, so a
|
|
85
|
+
* re-run finds the asset it uploaded last time instead of storing a copy per
|
|
86
|
+
* run — and a changed image gets a new name, so no cache serves the old one.
|
|
87
|
+
*/
|
|
88
|
+
upload(org: string, space: string, abs: string, existing: Map<string, string>): Promise<string>;
|
|
89
|
+
}
|
|
90
|
+
/** `<12 hex of sha256>-<file name>` — the stored name an asset is found by. */
|
|
91
|
+
export declare function assetName(abs: string): string;
|
|
92
|
+
/** A short, stable key for `Idempotency-Key`: the same write retried is one write. */
|
|
93
|
+
export declare function idemKey(...parts: string[]): string;
|
|
94
|
+
export {};
|
|
95
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/publish/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PublishApi = exports.isUuid = void 0;
|
|
4
|
+
exports.assetName = assetName;
|
|
5
|
+
exports.idemKey = idemKey;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
const sleeper = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
10
|
+
const isUuid = (s) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s);
|
|
11
|
+
exports.isUuid = isUuid;
|
|
12
|
+
class PublishApi {
|
|
13
|
+
opts;
|
|
14
|
+
lastWrite = 0;
|
|
15
|
+
/** Writes this run made, for the summary — and for a test to assert none happened. */
|
|
16
|
+
writes = 0;
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
this.opts = opts;
|
|
19
|
+
}
|
|
20
|
+
async call(method, path, body, query, headers) {
|
|
21
|
+
const sleep = this.opts.sleep ?? sleeper;
|
|
22
|
+
const write = method !== 'GET';
|
|
23
|
+
if (write && this.opts.readOnly)
|
|
24
|
+
throw new Error(`dry run tried to write: ${method} ${path}`);
|
|
25
|
+
for (let attempt = 0;; attempt++) {
|
|
26
|
+
if (write) {
|
|
27
|
+
const wait = this.lastWrite + this.opts.paceMs - Date.now();
|
|
28
|
+
if (wait > 0)
|
|
29
|
+
await sleep(wait);
|
|
30
|
+
this.lastWrite = Date.now();
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const res = await this.opts.client.request(method, path, { body, query, headers });
|
|
34
|
+
if (write)
|
|
35
|
+
this.writes++;
|
|
36
|
+
return res;
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
const status = e.status;
|
|
40
|
+
// 429 and the transient 5xx a deploy produces; never a 4xx that means "no".
|
|
41
|
+
if ((status === 429 || status === 502 || status === 503) && attempt < 5) {
|
|
42
|
+
await sleep(2000 * (attempt + 1));
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
get(path, query) {
|
|
50
|
+
return this.call('GET', path, undefined, query);
|
|
51
|
+
}
|
|
52
|
+
post(path, body = {}, headers) {
|
|
53
|
+
return this.call('POST', path, body, undefined, headers);
|
|
54
|
+
}
|
|
55
|
+
patch(path, body) {
|
|
56
|
+
return this.call('PATCH', path, body);
|
|
57
|
+
}
|
|
58
|
+
put(path, body) {
|
|
59
|
+
return this.call('PUT', path, body);
|
|
60
|
+
}
|
|
61
|
+
del(path) {
|
|
62
|
+
return this.call('DELETE', path);
|
|
63
|
+
}
|
|
64
|
+
/** Walk a cursor-paged list to the end. */
|
|
65
|
+
async all(path, key, query = {}) {
|
|
66
|
+
const out = [];
|
|
67
|
+
let cursor;
|
|
68
|
+
for (let i = 0; i < 1000; i++) {
|
|
69
|
+
const res = await this.get(path, {
|
|
70
|
+
...query,
|
|
71
|
+
...(cursor ? { cursor } : {}),
|
|
72
|
+
});
|
|
73
|
+
out.push(...(res[key] ?? []));
|
|
74
|
+
const page = res.page;
|
|
75
|
+
cursor = page?.nextCursor ?? undefined;
|
|
76
|
+
if (!(page?.hasMore ?? page?.has_more) || !cursor)
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
// ── Resolution ─────────────────────────────────────────────────────────────
|
|
82
|
+
async orgId(ref) {
|
|
83
|
+
if ((0, exports.isUuid)(ref) || !this.opts.authed)
|
|
84
|
+
return ref;
|
|
85
|
+
const { orgs } = await this.get('/orgs');
|
|
86
|
+
const hit = orgs.find((o) => o.slug === ref || o.id === ref);
|
|
87
|
+
if (!hit)
|
|
88
|
+
throw new Error(`No organization "${ref}" for this token (it sees: ${orgs.map((o) => o.slug).join(', ') || 'none'})`);
|
|
89
|
+
return hit.id;
|
|
90
|
+
}
|
|
91
|
+
/** The space by id or slug, or null when it does not exist. */
|
|
92
|
+
async space(org, ref) {
|
|
93
|
+
if (!this.opts.authed) {
|
|
94
|
+
try {
|
|
95
|
+
const r = await this.get(`/public/orgs/${org}/spaces/${ref}`);
|
|
96
|
+
return { ...r.space, orgId: r.organization.id };
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
if (e.status === 404)
|
|
100
|
+
return null;
|
|
101
|
+
throw e;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const spaces = await this.all(`/orgs/${org}/spaces`, 'spaces', { limit: 500 });
|
|
105
|
+
const hit = spaces.find((s) => s.id === ref || s.slug === ref);
|
|
106
|
+
return hit ? { ...hit, orgId: org } : null;
|
|
107
|
+
}
|
|
108
|
+
// ── Docs state ─────────────────────────────────────────────────────────────
|
|
109
|
+
/**
|
|
110
|
+
* Collections and pages as they are now. Anonymous reads see only what is
|
|
111
|
+
* published — the plan says so rather than presenting a partial view as whole.
|
|
112
|
+
*/
|
|
113
|
+
async docs(org, space) {
|
|
114
|
+
const publicRows = new Map();
|
|
115
|
+
if (!this.opts.authed) {
|
|
116
|
+
const r = await this.get(`/public/orgs/${org}/spaces/${space}`);
|
|
117
|
+
const pages = [];
|
|
118
|
+
const flatten = (rows, collectionId) => {
|
|
119
|
+
for (const p of rows) {
|
|
120
|
+
publicRows.set(String(p.id), p);
|
|
121
|
+
pages.push({
|
|
122
|
+
id: String(p.id),
|
|
123
|
+
slug: String(p.slug),
|
|
124
|
+
title: String(p.title),
|
|
125
|
+
collectionId,
|
|
126
|
+
parentId: p.parentId ?? null,
|
|
127
|
+
sortKey: String(p.sortKey ?? ''),
|
|
128
|
+
published: p.hasLive !== false,
|
|
129
|
+
});
|
|
130
|
+
if (Array.isArray(p.children))
|
|
131
|
+
flatten(p.children, collectionId);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
for (const c of r.collections ?? [])
|
|
135
|
+
flatten((c.pages ?? []), c.id);
|
|
136
|
+
const collections = (r.collections ?? []).map((c, i) => ({
|
|
137
|
+
id: c.id,
|
|
138
|
+
slug: c.slug,
|
|
139
|
+
name: c.name,
|
|
140
|
+
isDefault: Boolean(c.isDefault),
|
|
141
|
+
sortKey: String(i).padStart(6, '0'),
|
|
142
|
+
nav: c.nav,
|
|
143
|
+
}));
|
|
144
|
+
return {
|
|
145
|
+
collections,
|
|
146
|
+
pages,
|
|
147
|
+
fieldKeys: (r.shape?.params ?? []).map((p) => p.key),
|
|
148
|
+
publicRows,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const [collections, rows, shape] = await Promise.all([
|
|
152
|
+
this.all(`/orgs/${org}/spaces/${space}/collections`, 'collections', {
|
|
153
|
+
limit: 500,
|
|
154
|
+
}),
|
|
155
|
+
this.all(`/orgs/${org}/spaces/${space}/pages`, 'pages', { limit: 1000 }),
|
|
156
|
+
this.get(`/orgs/${org}/spaces/${space}/shape`).catch(() => ({ shape: undefined })),
|
|
157
|
+
]);
|
|
158
|
+
// Versions and translations are clones carrying the same slug; the
|
|
159
|
+
// publisher writes the primary, so it reads the primary.
|
|
160
|
+
const pages = rows
|
|
161
|
+
.filter((p) => (p.versionKey ?? 'default') === 'default' && (p.locale ?? 'default') === 'default')
|
|
162
|
+
.map((p) => ({
|
|
163
|
+
...p,
|
|
164
|
+
published: p.status ? p.status === 'published' : p.published !== false,
|
|
165
|
+
}));
|
|
166
|
+
return {
|
|
167
|
+
collections,
|
|
168
|
+
pages,
|
|
169
|
+
fieldKeys: (shape.shape?.params ?? []).map((p) => p.key),
|
|
170
|
+
publicRows,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/** Every page's markdown, in one paged walk when authenticated. */
|
|
174
|
+
async markdownById(org, space) {
|
|
175
|
+
const out = new Map();
|
|
176
|
+
if (!this.opts.authed)
|
|
177
|
+
return out;
|
|
178
|
+
const items = await this.all(`/orgs/${org}/spaces/${space}/items`, 'items', { limit: 50, include: 'body' });
|
|
179
|
+
for (const i of items)
|
|
180
|
+
if (typeof i.markdown === 'string')
|
|
181
|
+
out.set(i.id, i.markdown);
|
|
182
|
+
return out;
|
|
183
|
+
}
|
|
184
|
+
/** One published page's markdown, the way a reader (or an agent) gets it. */
|
|
185
|
+
async publicMarkdown(org, space, pageId) {
|
|
186
|
+
try {
|
|
187
|
+
const res = await this.opts.client.request('GET', `/public/orgs/${org}/spaces/${space}/pages/${pageId}.md`, { raw: true });
|
|
188
|
+
return await res.text();
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
const status = e.status;
|
|
192
|
+
if (status === 404)
|
|
193
|
+
return null;
|
|
194
|
+
if (status === 429) {
|
|
195
|
+
await (this.opts.sleep ?? sleeper)(3000);
|
|
196
|
+
return this.publicMarkdown(org, space, pageId);
|
|
197
|
+
}
|
|
198
|
+
throw e;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async pageMeta(org, space, pageId) {
|
|
202
|
+
const r = await this.get(`/orgs/${org}/spaces/${space}/pages/${pageId}/metadata`);
|
|
203
|
+
return r.metadata ?? {};
|
|
204
|
+
}
|
|
205
|
+
// ── Posts state ────────────────────────────────────────────────────────────
|
|
206
|
+
async posts(org, space, type) {
|
|
207
|
+
if (this.opts.authed) {
|
|
208
|
+
const items = await this.all(`/orgs/${org}/spaces/${space}/items`, 'items', { limit: 50, include: 'sections,body' });
|
|
209
|
+
return items.filter((i) => i.slug);
|
|
210
|
+
}
|
|
211
|
+
if (type !== 'BLOG')
|
|
212
|
+
return null;
|
|
213
|
+
const rows = await this.all(`/public/orgs/${org}/spaces/${space}/blog`, 'articles', { limit: 100 });
|
|
214
|
+
return rows.map((r) => ({ ...r, published: true }));
|
|
215
|
+
}
|
|
216
|
+
async shape(org, space) {
|
|
217
|
+
if (!this.opts.authed) {
|
|
218
|
+
const r = await this.get(`/public/orgs/${org}/spaces/${space}`).catch(() => ({ shape: undefined }));
|
|
219
|
+
return { sections: r.shape?.sections ?? [], params: r.shape?.params ?? [] };
|
|
220
|
+
}
|
|
221
|
+
const r = await this.get(`/orgs/${org}/spaces/${space}/shape`);
|
|
222
|
+
return { sections: r.shape?.sections ?? [], params: r.shape?.params ?? [] };
|
|
223
|
+
}
|
|
224
|
+
// ── Assets ─────────────────────────────────────────────────────────────────
|
|
225
|
+
async assets(org, space) {
|
|
226
|
+
if (!this.opts.authed)
|
|
227
|
+
return new Map();
|
|
228
|
+
const rows = await this.all(`/orgs/${org}/spaces/${space}/assets`, 'assets', { limit: 500 });
|
|
229
|
+
return new Map(rows.map((a) => [a.filename, a.url]));
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Upload once, by content. The stored name carries a hash of the bytes, so a
|
|
233
|
+
* re-run finds the asset it uploaded last time instead of storing a copy per
|
|
234
|
+
* run — and a changed image gets a new name, so no cache serves the old one.
|
|
235
|
+
*/
|
|
236
|
+
async upload(org, space, abs, existing) {
|
|
237
|
+
const name = assetName(abs);
|
|
238
|
+
const known = existing.get(name);
|
|
239
|
+
if (known)
|
|
240
|
+
return known;
|
|
241
|
+
if (this.opts.readOnly)
|
|
242
|
+
throw new Error(`dry run tried to upload ${abs}`);
|
|
243
|
+
if (!this.opts.upload)
|
|
244
|
+
throw new Error('asset upload is not available in this environment');
|
|
245
|
+
const form = new FormData();
|
|
246
|
+
form.set('file', new Blob([(0, node_fs_1.readFileSync)(abs)]), name);
|
|
247
|
+
const res = (await this.opts.upload(`/orgs/${org}/spaces/${space}/assets`, form));
|
|
248
|
+
if (!res.asset?.url)
|
|
249
|
+
throw new Error(`upload of ${abs} answered without an asset url`);
|
|
250
|
+
this.writes++;
|
|
251
|
+
existing.set(name, res.asset.url);
|
|
252
|
+
return res.asset.url;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
exports.PublishApi = PublishApi;
|
|
256
|
+
/** `<12 hex of sha256>-<file name>` — the stored name an asset is found by. */
|
|
257
|
+
function assetName(abs) {
|
|
258
|
+
const hash = (0, node_crypto_1.createHash)('sha256').update((0, node_fs_1.readFileSync)(abs)).digest('hex').slice(0, 12);
|
|
259
|
+
return `${hash}-${(0, node_path_1.basename)(abs).replace(/[^\w.-]+/g, '-')}`;
|
|
260
|
+
}
|
|
261
|
+
/** A short, stable key for `Idempotency-Key`: the same write retried is one write. */
|
|
262
|
+
function idemKey(...parts) {
|
|
263
|
+
return (0, node_crypto_1.createHash)('sha256').update(parts.join('\u0000')).digest('hex').slice(0, 40);
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/publish/api.ts"],"names":[],"mappings":";;;AAuWA,8BAGC;AAGD,0BAEC;AA/WD,qCAAuC;AACvC,yCAAqC;AACrC,6CAAyC;AAiCzC,MAAM,OAAO,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAErE,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAClC,iEAAiE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAD/D,QAAA,MAAM,UACyD;AAE5E,MAAa,UAAU;IAIA;IAHb,SAAS,GAAG,CAAC,CAAC;IACtB,sFAAsF;IACtF,MAAM,GAAG,CAAC,CAAC;IACX,YAAqB,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjC,KAAK,CAAC,IAAI,CAChB,MAAc,EACd,IAAY,EACZ,IAAc,EACd,KAAS,EACT,OAAgC;QAEhC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC;QACzC,MAAM,KAAK,GAAG,MAAM,KAAK,KAAK,CAAC;QAC/B,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QAC9F,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;YAClC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC5D,IAAI,IAAI,GAAG,CAAC;oBAAE,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;gBAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC9B,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;gBACtF,IAAI,KAAK;oBAAE,IAAI,CAAC,MAAM,EAAE,CAAC;gBACzB,OAAO,GAAG,CAAC;YACb,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,MAAM,GAAI,CAAyB,CAAC,MAAM,CAAC;gBACjD,4EAA4E;gBAC5E,IAAI,CAAC,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;oBACxE,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;oBAClC,SAAS;gBACX,CAAC;gBACD,MAAM,CAAC,CAAC;YACV,CAAC;QACH,CAAC;IACH,CAAC;IACD,GAAG,CAAI,IAAY,EAAE,KAAS;QAC5B,OAAO,IAAI,CAAC,IAAI,CAAI,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,CAAI,IAAY,EAAE,OAAgB,EAAE,EAAE,OAAgC;QACxE,OAAO,IAAI,CAAC,IAAI,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;IACD,KAAK,CAAI,IAAY,EAAE,IAAa;QAClC,OAAO,IAAI,CAAC,IAAI,CAAI,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IACD,GAAG,CAAI,IAAY,EAAE,IAAa;QAChC,OAAO,IAAI,CAAC,IAAI,CAAI,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,GAAG,CAAI,IAAY;QACjB,OAAO,IAAI,CAAC,IAAI,CAAI,QAAQ,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,2CAA2C;IAC3C,KAAK,CAAC,GAAG,CAAI,IAAY,EAAE,GAAW,EAAE,QAAW,EAAE;QACnD,MAAM,GAAG,GAAQ,EAAE,CAAC;QACpB,IAAI,MAA0B,CAAC;QAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAA0B,IAAI,EAAE;gBACxD,GAAG,KAAK;gBACR,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9B,CAAC,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,GAAG,CAAE,GAAG,CAAC,GAAG,CAAS,IAAI,EAAE,CAAC,CAAC,CAAC;YACvC,MAAM,IAAI,GAAG,GAAG,CAAC,IACkE,CAAC;YACpF,MAAM,GAAG,IAAI,EAAE,UAAU,IAAI,SAAS,CAAC;YACvC,IAAI,CAAC,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM;gBAAE,MAAM;QAC3D,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,KAAK,CAAC,GAAW;QACrB,IAAI,IAAA,cAAM,EAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,GAAG,CAAC;QACjD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,CAA2C,OAAO,CAAC,CAAC;QACnF,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,GAAG;YACN,MAAM,IAAI,KAAK,CACb,oBAAoB,GAAG,8BAA8B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,GAAG,CACrG,CAAC;QACJ,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAED,+DAA+D;IAC/D,KAAK,CAAC,KAAK,CACT,GAAW,EACX,GAAW;QAEX,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACtB,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAGrB,gBAAgB,GAAG,WAAW,GAAG,EAAE,CAAC,CAAC;gBACxC,OAAO,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC;YAClD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAK,CAAyB,CAAC,MAAM,KAAK,GAAG;oBAAE,OAAO,IAAI,CAAC;gBAC3D,MAAM,CAAC,CAAC;YACV,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAC3B,SAAS,GAAG,SAAS,EACrB,QAAQ,EACR,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;QAC/D,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7C,CAAC;IAED,8EAA8E;IAE9E;;;OAGG;IACH,KAAK,CAAC,IAAI,CACR,GAAW,EACX,KAAa;QAOb,MAAM,UAAU,GAAG,IAAI,GAAG,EAAmC,CAAC;QAC9D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAKrB,gBAAgB,GAAG,WAAW,KAAK,EAAE,CAAC,CAAC;YAC1C,MAAM,KAAK,GAAe,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,CACd,IAA4D,EAC5D,YAAoB,EACpB,EAAE;gBACF,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;oBACrB,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;oBAChC,KAAK,CAAC,IAAI,CAAC;wBACT,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;wBAChB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;wBACpB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;wBACtB,YAAY;wBACZ,QAAQ,EAAG,CAAC,CAAC,QAA0B,IAAI,IAAI;wBAC/C,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;wBAChC,SAAS,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK;qBAC/B,CAAC,CAAC;oBACH,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;wBAAE,OAAO,CAAC,CAAC,CAAC,QAAiB,EAAE,YAAY,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC,CAAC;YACF,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,IAAI,EAAE;gBAAE,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC7E,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;gBACvD,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC/B,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;gBACnC,GAAG,EAAE,CAAC,CAAC,GAAG;aACX,CAAC,CAAC,CAAC;YACJ,OAAO;gBACL,WAAW;gBACX,KAAK;gBACL,SAAS,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;gBACpD,UAAU;aACX,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACnD,IAAI,CAAC,GAAG,CAAiB,SAAS,GAAG,WAAW,KAAK,cAAc,EAAE,aAAa,EAAE;gBAClF,KAAK,EAAE,GAAG;aACX,CAAC;YACF,IAAI,CAAC,GAAG,CACN,SAAS,GAAG,WAAW,KAAK,QAAQ,EACpC,OAAO,EACP,EAAE,KAAK,EAAE,IAAI,EAAE,CAChB;YACD,IAAI,CAAC,GAAG,CACN,SAAS,GAAG,WAAW,KAAK,QAAQ,CACrC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;SACtC,CAAC,CAAC;QACH,mEAAmE;QACnE,yDAAyD;QACzD,MAAM,KAAK,GAAG,IAAI;aACf,MAAM,CACL,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,SAAS,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC,KAAK,SAAS,CAC1F;aACA,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACX,GAAG,CAAC;YACJ,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK;SACvE,CAAC,CAAC,CAAC;QACN,OAAO;YACL,WAAW;YACX,KAAK;YACL,SAAS,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YACxD,UAAU;SACX,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,KAAK,CAAC,YAAY,CAAC,GAAW,EAAE,KAAa;QAC3C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,GAAG,CAAC;QAClC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAC1B,SAAS,GAAG,WAAW,KAAK,QAAQ,EACpC,OAAO,EACP,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAC/B,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;gBAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;QACrF,OAAO,GAAG,CAAC;IACb,CAAC;IAED,6EAA6E;IAC7E,KAAK,CAAC,cAAc,CAAC,GAAW,EAAE,KAAa,EAAE,MAAc;QAC7D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CACxC,KAAK,EACL,gBAAgB,GAAG,WAAW,KAAK,UAAU,MAAM,KAAK,EACxD,EAAE,GAAG,EAAE,IAAI,EAAE,CACd,CAAC;YACF,OAAO,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,MAAM,GAAI,CAAyB,CAAC,MAAM,CAAC;YACjD,IAAI,MAAM,KAAK,GAAG;gBAAE,OAAO,IAAI,CAAC;YAChC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;gBACzC,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YACjD,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAW,EAAE,KAAa,EAAE,MAAc;QACvD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CACtB,SAAS,GAAG,WAAW,KAAK,UAAU,MAAM,WAAW,CACxD,CAAC;QACF,OAAO,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC1B,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,KAAa,EAAE,IAAY;QAClD,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAC1B,SAAS,GAAG,WAAW,KAAK,QAAQ,EACpC,OAAO,EACP,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,CACxC,CAAC;YACF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QACD,IAAI,IAAI,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CACzB,gBAAgB,GAAG,WAAW,KAAK,OAAO,EAC1C,UAAU,EACV,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;QACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,KAAK,CACT,GAAW,EACX,KAAa;QAKb,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACtB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CACtB,gBAAgB,GAAG,WAAW,KAAK,EAAE,CACtC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YACtC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;QAC9E,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CACtB,SAAS,GAAG,WAAW,KAAK,QAAQ,CACrC,CAAC;QACF,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;IAC9E,CAAC;IAED,8EAA8E;IAE9E,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,KAAa;QACrC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CACzB,SAAS,GAAG,WAAW,KAAK,SAAS,EACrC,QAAQ,EACR,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;QACF,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CACV,GAAW,EACX,KAAa,EACb,GAAW,EACX,QAA6B;QAE7B,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QAC5F,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC,IAAA,sBAAY,EAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACtD,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,WAAW,KAAK,SAAS,EAAE,IAAI,CAAC,CAE/E,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,GAAG,gCAAgC,CAAC,CAAC;QACvF,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;IACvB,CAAC;CACF;AA5TD,gCA4TC;AAED,+EAA+E;AAC/E,SAAgB,SAAS,CAAC,GAAW;IACnC,MAAM,IAAI,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAA,sBAAY,EAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvF,OAAO,GAAG,IAAI,IAAI,IAAA,oBAAQ,EAAC,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,sFAAsF;AACtF,SAAgB,OAAO,CAAC,GAAG,KAAe;IACxC,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ForumulateClient } from '@forumulate/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* `forumulate publish <folder>` — a folder of Markdown, and optionally a
|
|
4
|
+
* manifest, made into a live presence; and the same command run again changes
|
|
5
|
+
* only what changed.
|
|
6
|
+
*
|
|
7
|
+
* Four customers wrote this themselves before we did (a Python script, two
|
|
8
|
+
* converter-plus-publisher pairs, ~400 lines of TypeScript), and every one of
|
|
9
|
+
* them did the same seven things: front matter to collections and pages,
|
|
10
|
+
* idempotent re-runs, prune, reorder, read back, dry run, the OpenAPI
|
|
11
|
+
* reference. That is the spec of this command.
|
|
12
|
+
*
|
|
13
|
+
* Three modes over ONE planner: `--dry-run` plans against the live space and
|
|
14
|
+
* writes nothing (a token is optional — without one it reads the public
|
|
15
|
+
* space); a real run applies the plan; and then the planner runs once more
|
|
16
|
+
* against what is now live, and anything it would still change is reported as
|
|
17
|
+
* a failure. That last pass is the read-back: a publish that answered 200 and
|
|
18
|
+
* changed nothing is the failure every one of those scripts was eventually
|
|
19
|
+
* written to catch.
|
|
20
|
+
*/
|
|
21
|
+
export interface PublishOptions {
|
|
22
|
+
folder: string;
|
|
23
|
+
org?: string;
|
|
24
|
+
space?: string;
|
|
25
|
+
manifest?: string;
|
|
26
|
+
dryRun: boolean;
|
|
27
|
+
prune: boolean;
|
|
28
|
+
force: boolean;
|
|
29
|
+
verify: boolean;
|
|
30
|
+
only?: string[];
|
|
31
|
+
paceMs: number;
|
|
32
|
+
json: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface PublishDeps {
|
|
35
|
+
client: ForumulateClient;
|
|
36
|
+
authed: boolean;
|
|
37
|
+
out: (line: string) => void;
|
|
38
|
+
err: (line: string) => void;
|
|
39
|
+
upload?: (path: string, form: FormData) => Promise<unknown>;
|
|
40
|
+
env?: NodeJS.ProcessEnv;
|
|
41
|
+
sleep?: (ms: number) => Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
export declare function runPublish(opts: PublishOptions, deps: PublishDeps): Promise<number>;
|
|
44
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/publish/command.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAYxD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAKD,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA+IzF"}
|