uniweb 0.69.2 → 0.69.3
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/package.json +6 -6
- package/src/backend/site-sync.js +143 -77
- package/src/commands/publish.js +4 -11
- package/src/commands/push.js +7 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.69.
|
|
3
|
+
"version": "0.69.3",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,16 +41,16 @@
|
|
|
41
41
|
"js-yaml": "^4.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/content-writer": "^0.3.4",
|
|
45
44
|
"@uniweb/core": "^0.29.8",
|
|
46
|
-
"@uniweb/kit": "^0.19.4",
|
|
47
45
|
"@uniweb/runtime": "^0.27.4",
|
|
48
|
-
"@uniweb/
|
|
49
|
-
"@uniweb/schemas": "^0.7.0"
|
|
46
|
+
"@uniweb/content-writer": "^0.3.4",
|
|
47
|
+
"@uniweb/schemas": "^0.7.0",
|
|
48
|
+
"@uniweb/kit": "^0.19.4",
|
|
49
|
+
"@uniweb/semantic-parser": "^1.4.1"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@uniweb/build": "^0.63.2",
|
|
53
52
|
"@uniweb/content-reader": "^1.2.5",
|
|
53
|
+
"@uniweb/build": "^0.63.2",
|
|
54
54
|
"@uniweb/semantic-parser": "^1.4.1"
|
|
55
55
|
},
|
|
56
56
|
"peerDependenciesMeta": {
|
package/src/backend/site-sync.js
CHANGED
|
@@ -1196,37 +1196,94 @@ export function refuseUnsendableRecords(refusals, { error, note }) {
|
|
|
1196
1196
|
* left alone. (The map sat in the gitignored cache until 2026-09-20, so a fresh
|
|
1197
1197
|
* `git clone` or a deleted `.uniweb/` was what emptied it; it is committed now.)
|
|
1198
1198
|
*
|
|
1199
|
+
* ⚠️ A PARTIAL map is not this function's: it runs before the package is built, when
|
|
1200
|
+
* nothing yet says which items went without identity. `recoverUnbankedIdentity` runs
|
|
1201
|
+
* after, and fills in what is missing.
|
|
1202
|
+
*
|
|
1199
1203
|
* @returns {Promise<Object<string,string>>} the map (possibly empty)
|
|
1200
1204
|
*/
|
|
1201
1205
|
export async function ensureItemUuids({ client, siteDir, note }) {
|
|
1202
1206
|
const cached = readItemUuids(siteDir, client.origin)
|
|
1203
1207
|
if (Object.keys(cached).length) return cached
|
|
1204
|
-
|
|
1205
|
-
|
|
1208
|
+
const harvested = await storedItemUuids({ client, siteDir })
|
|
1209
|
+
if (!harvested || !Object.keys(harvested).length) return cached
|
|
1210
|
+
writeItemUuids(siteDir, client.origin, harvested)
|
|
1211
|
+
note?.(`Recovered identity for ${Object.keys(harvested).length} item(s) from the backend.`)
|
|
1212
|
+
return harvested
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Each page and section `$uuid` the backend holds for the site this copy is bound to, by
|
|
1217
|
+
* the path it projects to — one read of its own document. Null when the copy is bound to
|
|
1218
|
+
* no site there (a site never pushed has no identity to recover, and nothing to lose,
|
|
1219
|
+
* since every item is genuinely new) or the read fails.
|
|
1220
|
+
*
|
|
1221
|
+
* Best-effort: a failure leaves the push identity-blind, which the backend refuses rather
|
|
1222
|
+
* than silently applying. Better to hit that than to guess.
|
|
1223
|
+
*
|
|
1224
|
+
* @returns {Promise<Object<string,string>|null>}
|
|
1225
|
+
*/
|
|
1226
|
+
async function storedItemUuids({ client, siteDir }) {
|
|
1206
1227
|
// The site to recover identity against — this backend's, from sync.json. It read
|
|
1207
1228
|
// `site.yml::$uuid`, so after step 4 it found nothing and never recovered.
|
|
1208
1229
|
const siteContentUuid = readBackendState(siteDir, client.origin).site?.uuid || null
|
|
1209
|
-
if (!siteContentUuid) return
|
|
1230
|
+
if (!siteContentUuid) return null
|
|
1210
1231
|
try {
|
|
1211
1232
|
const res = await client.pullSiteContent(siteContentUuid)
|
|
1212
|
-
if (!res?.ok) return
|
|
1233
|
+
if (!res?.ok) return null
|
|
1213
1234
|
const doc = entityDocFromUwx(Buffer.from(await res.arrayBuffer()))
|
|
1214
|
-
|
|
1215
|
-
const harvested = collectUnitUuids(doc)
|
|
1216
|
-
if (Object.keys(harvested).length) {
|
|
1217
|
-
writeItemUuids(siteDir, client.origin, harvested)
|
|
1218
|
-
note?.(
|
|
1219
|
-
`Recovered identity for ${Object.keys(harvested).length} item(s) from the backend.`
|
|
1220
|
-
)
|
|
1221
|
-
}
|
|
1222
|
-
return harvested
|
|
1235
|
+
return doc ? collectUnitUuids(doc) : null
|
|
1223
1236
|
} catch {
|
|
1224
|
-
|
|
1225
|
-
// refuses rather than silently applying. Better to hit that than to guess.
|
|
1226
|
-
return cached
|
|
1237
|
+
return null
|
|
1227
1238
|
}
|
|
1228
1239
|
}
|
|
1229
1240
|
|
|
1241
|
+
/**
|
|
1242
|
+
* Fill in the page and section identity this copy LACKS for the site it is bound to, from
|
|
1243
|
+
* the backend's own document. What the copy already holds is kept.
|
|
1244
|
+
*
|
|
1245
|
+
* ⛔ `ensureItemUuids` recovers only an EMPTY map, and a map can be partial: until
|
|
1246
|
+
* 2026-09-25 a push whose records were refused after its pages landed saved the pages'
|
|
1247
|
+
* identity nowhere (`pushSyncPackages`), leaving the map with `site.yml` alone. Every push
|
|
1248
|
+
* after that sent the pages with no `$uuid` while the backend held them, and was refused —
|
|
1249
|
+
* "one section carries no item identity (section pages)" — with nothing ever recovering it.
|
|
1250
|
+
*
|
|
1251
|
+
* @returns {Promise<number>} how many pages and sections were recovered
|
|
1252
|
+
*/
|
|
1253
|
+
export async function recoverItemUuids({ client, siteDir, note }) {
|
|
1254
|
+
const cached = readItemUuids(siteDir, client.origin)
|
|
1255
|
+
const harvested = await storedItemUuids({ client, siteDir })
|
|
1256
|
+
if (!harvested) return 0
|
|
1257
|
+
const missing = Object.keys(harvested).filter((path) => !cached[path])
|
|
1258
|
+
if (!missing.length) return 0
|
|
1259
|
+
writeItemUuids(siteDir, client.origin, { ...harvested, ...cached })
|
|
1260
|
+
note?.(`Recovered identity for ${missing.length} item(s) from the backend.`)
|
|
1261
|
+
return missing.length
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* Recover the identity a package just built went out without, when the backend may hold it —
|
|
1266
|
+
* a page or section (`itemIdentity.unknown`), or a record's list items
|
|
1267
|
+
* (`recordItemIdentity.unbanked`) — and say what to build the package again with.
|
|
1268
|
+
*
|
|
1269
|
+
* A page added since the last push is also without identity, and costs one read that finds
|
|
1270
|
+
* nothing. That is the price of never sending as new an item the backend already holds.
|
|
1271
|
+
*
|
|
1272
|
+
* @returns {Promise<object|null>} emit options to build the package again with, or null
|
|
1273
|
+
* when nothing was recovered
|
|
1274
|
+
*/
|
|
1275
|
+
export async function recoverUnbankedIdentity({ client, siteDir, pkg, note }) {
|
|
1276
|
+
let again = null
|
|
1277
|
+
if (pkg?.itemIdentity?.unknown > 0 && (await recoverItemUuids({ client, siteDir, note }))) {
|
|
1278
|
+
again = { ...again, itemUuids: readItemUuids(siteDir, client.origin) }
|
|
1279
|
+
}
|
|
1280
|
+
const unbanked = pkg?.recordItemIdentity?.unbanked
|
|
1281
|
+
if (unbanked?.length && (await recoverRecordItemUuids({ client, siteDir, uuids: unbanked, note }))) {
|
|
1282
|
+
again = { ...again, recordItemUuids: readRecordItemUuids(siteDir, client.origin) }
|
|
1283
|
+
}
|
|
1284
|
+
return again
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1230
1287
|
export function readUnitBases(siteDir, backend) {
|
|
1231
1288
|
const v = readMap(siteDir, backend, 'unitBases')
|
|
1232
1289
|
return { local: v.local || {}, remote: v.remote || {} }
|
|
@@ -1791,6 +1848,73 @@ export async function pushSyncPackages({
|
|
|
1791
1848
|
// The backend's post-write copy of the site-content document, kept for the
|
|
1792
1849
|
// remote-side unit base (see writeUnitBases).
|
|
1793
1850
|
let siteFinalizedDoc = null
|
|
1851
|
+
// ⭐ WHAT THE SITE-CONTENT LANE LANDED IS SETTLED THE MOMENT IT LANDS — its query and item
|
|
1852
|
+
// identity, its unit bases and the files it now holds as synced — on either path to it.
|
|
1853
|
+
// ⛔ Until 2026-09-25 the item identity and the bases were settled at the END, after the
|
|
1854
|
+
// records lane, so a records lane that was refused returned before them: the pages were
|
|
1855
|
+
// stored, their identity was saved nowhere, and every later push sent them without it and
|
|
1856
|
+
// was refused — "one section carries no item identity (section pages)" — while the
|
|
1857
|
+
// queries, banked at once, were kept. And the queries were banked on the update path
|
|
1858
|
+
// only, so a site created with no media never saved theirs.
|
|
1859
|
+
const settleSiteContent = () => {
|
|
1860
|
+
// ⭐ BANK COLLECTION-DECLARATION IDENTITY, the sibling of the folder's placements
|
|
1861
|
+
// below. These items have no file to back-fill into — they all come from one
|
|
1862
|
+
// `collections/collections.yml` — so the only place their `$uuid` can live is
|
|
1863
|
+
// `sync.json` (this backend's `queries` map), keyed by the name the backend enforces
|
|
1864
|
+
// unique. Without it every push after the first re-sends the whole `collections`
|
|
1865
|
+
// section uuid-less and is refused.
|
|
1866
|
+
if (siteFinalizedDoc) {
|
|
1867
|
+
const recordIds = collectQueryUuids(siteFinalizedDoc)
|
|
1868
|
+
if (Object.keys(recordIds).length) writeQueryUuids(siteDir, client.origin, recordIds)
|
|
1869
|
+
}
|
|
1870
|
+
// Re-base the page attribution: our emitted document and the backend's post-write
|
|
1871
|
+
// copy of it are the two sides' new agreed state.
|
|
1872
|
+
const patch = {}
|
|
1873
|
+
const ours = sentSiteDoc
|
|
1874
|
+
if (ours) patch.local = computeUnitHashes(ours)
|
|
1875
|
+
// `finalized[].document` is the backend's own representation, read back from
|
|
1876
|
+
// the stored row — the only remote-side base a push can produce.
|
|
1877
|
+
const theirs = siteFinalizedDoc?.pages ? siteFinalizedDoc : null
|
|
1878
|
+
if (theirs) {
|
|
1879
|
+
patch.remote = computeUnitHashes(theirs)
|
|
1880
|
+
// A unit the backend kept for someone else is not agreed state: its remote base
|
|
1881
|
+
// stays where it was, so a refusal names it as changed upstream.
|
|
1882
|
+
const before = readUnitBases(siteDir, client.origin).remote
|
|
1883
|
+
for (const path of notHeld.kept) {
|
|
1884
|
+
if (before[path]) patch.remote[path] = before[path]
|
|
1885
|
+
else delete patch.remote[path]
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
if (Object.keys(patch).length) writeUnitBases(siteDir, client.origin, patch)
|
|
1889
|
+
// The backend's post-write document carries `$uuid` per item at every nesting
|
|
1890
|
+
// level, so the push that just landed also re-arms identity for the next one.
|
|
1891
|
+
// Replaced wholesale: an item that no longer exists must not keep a uuid that
|
|
1892
|
+
// would re-target something else.
|
|
1893
|
+
if (theirs) writeItemUuids(siteDir, client.origin, collectUnitUuids(theirs))
|
|
1894
|
+
else {
|
|
1895
|
+
// ⛔ BANKING IS BEST-EFFORT AND ITS FAILURE USED TO BE SILENT — say it here,
|
|
1896
|
+
// because the cost lands two commands away and names something else.
|
|
1897
|
+
//
|
|
1898
|
+
// Without `finalized[0].document` (carrying `pages`) this push banks NO item
|
|
1899
|
+
// identity. The push still reports success. The next `push`/`publish` then
|
|
1900
|
+
// emits with no `$uuid` per item, and the backend refuses — correctly, since
|
|
1901
|
+
// silently re-identifying every stored row is far worse. But that refusal
|
|
1902
|
+
// reads as a stale-token or a producer bug, with nothing pointing back at the
|
|
1903
|
+
// push that failed to bank.
|
|
1904
|
+
//
|
|
1905
|
+
// ⚠️ We cannot tell WHY it is absent from here — a response shape that
|
|
1906
|
+
// changed, a lane that shipped nothing, a backend that does not echo the
|
|
1907
|
+
// document. Report the observable fact and let the operator carry it.
|
|
1908
|
+
note(
|
|
1909
|
+
'identity not banked: this push returned no post-write document, so no per-item ' +
|
|
1910
|
+
'$uuid was stored. The next push or publish will be identity-blind and the backend ' +
|
|
1911
|
+
'may refuse it. `uniweb pull` re-arms identity if that happens.'
|
|
1912
|
+
)
|
|
1913
|
+
}
|
|
1914
|
+
// The files of the units the backend now holds as ours are the synced version — the
|
|
1915
|
+
// ancestor the next `pull --merge` merges from.
|
|
1916
|
+
if (heldUnits.length) recordPushedUnits(siteDir, heldUnits)
|
|
1917
|
+
}
|
|
1794
1918
|
if (siteContent) {
|
|
1795
1919
|
if (siteContentUuid) {
|
|
1796
1920
|
const finalized = await pushLane(
|
|
@@ -1812,18 +1936,8 @@ export async function pushSyncPackages({
|
|
|
1812
1936
|
}
|
|
1813
1937
|
harvestSiteContent(finalized)
|
|
1814
1938
|
siteFinalizedDoc = finalized[0]?.document || null
|
|
1815
|
-
// ⭐ BANK COLLECTION-DECLARATION IDENTITY, the sibling of the folder's
|
|
1816
|
-
// placements below. These items have no file to back-fill into — they all
|
|
1817
|
-
// come from one `collections/collections.yml` — so the only place their
|
|
1818
|
-
// `$uuid` can live is `sync.json` (this backend's `queries` map), keyed by the
|
|
1819
|
-
// name the backend enforces unique. Without it every push after the first re-sends the whole
|
|
1820
|
-
// `collections` section uuid-less and is refused.
|
|
1821
|
-
if (siteFinalizedDoc) {
|
|
1822
|
-
const recordIds = collectQueryUuids(siteFinalizedDoc)
|
|
1823
|
-
if (Object.keys(recordIds).length)
|
|
1824
|
-
writeQueryUuids(siteDir, client.origin, recordIds)
|
|
1825
|
-
}
|
|
1826
1939
|
finalizedTotal += finalized.length
|
|
1940
|
+
settleSiteContent()
|
|
1827
1941
|
} else {
|
|
1828
1942
|
const payload = await postLane(
|
|
1829
1943
|
'site-content',
|
|
@@ -1857,6 +1971,7 @@ export async function pushSyncPackages({
|
|
|
1857
1971
|
harvestSiteContent(createdFinalized)
|
|
1858
1972
|
siteFinalizedDoc = createdFinalized?.[0]?.document || null
|
|
1859
1973
|
finalizedTotal += createdFinalized?.length ?? 1
|
|
1974
|
+
settleSiteContent()
|
|
1860
1975
|
}
|
|
1861
1976
|
}
|
|
1862
1977
|
|
|
@@ -1940,56 +2055,7 @@ export async function pushSyncPackages({
|
|
|
1940
2055
|
}
|
|
1941
2056
|
}
|
|
1942
2057
|
mergeHarvested()
|
|
1943
|
-
//
|
|
1944
|
-
// copy of it are the two sides' new agreed state. Only when the site-content lane
|
|
1945
|
-
// actually shipped — a push that skipped it left that state where it was.
|
|
1946
|
-
if (siteContent) {
|
|
1947
|
-
const patch = {}
|
|
1948
|
-
const ours = sentSiteDoc
|
|
1949
|
-
if (ours) patch.local = computeUnitHashes(ours)
|
|
1950
|
-
// `finalized[].document` is the backend's own representation, read back from
|
|
1951
|
-
// the stored row — the only remote-side base a push can produce.
|
|
1952
|
-
const theirs = siteFinalizedDoc?.pages ? siteFinalizedDoc : null
|
|
1953
|
-
if (theirs) {
|
|
1954
|
-
patch.remote = computeUnitHashes(theirs)
|
|
1955
|
-
// A unit the backend kept for someone else is not agreed state: its remote base
|
|
1956
|
-
// stays where it was, so a refusal names it as changed upstream.
|
|
1957
|
-
const before = readUnitBases(siteDir, client.origin).remote
|
|
1958
|
-
for (const path of notHeld.kept) {
|
|
1959
|
-
if (before[path]) patch.remote[path] = before[path]
|
|
1960
|
-
else delete patch.remote[path]
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
if (Object.keys(patch).length) writeUnitBases(siteDir, client.origin, patch)
|
|
1964
|
-
// The backend's post-write document carries `$uuid` per item at every nesting
|
|
1965
|
-
// level, so the push that just landed also re-arms identity for the next one.
|
|
1966
|
-
// Replaced wholesale: an item that no longer exists must not keep a uuid that
|
|
1967
|
-
// would re-target something else.
|
|
1968
|
-
if (theirs) writeItemUuids(siteDir, client.origin, collectUnitUuids(theirs))
|
|
1969
|
-
else {
|
|
1970
|
-
// ⛔ BANKING IS BEST-EFFORT AND ITS FAILURE USED TO BE SILENT — say it here,
|
|
1971
|
-
// because the cost lands two commands away and names something else.
|
|
1972
|
-
//
|
|
1973
|
-
// Without `finalized[0].document` (carrying `pages`) this push banks NO item
|
|
1974
|
-
// identity. The push still reports success. The next `push`/`publish` then
|
|
1975
|
-
// emits with no `$uuid` per item, and the backend refuses — correctly, since
|
|
1976
|
-
// silently re-identifying every stored row is far worse. But that refusal
|
|
1977
|
-
// reads as a stale-token or a producer bug, with nothing pointing back at the
|
|
1978
|
-
// push that failed to bank.
|
|
1979
|
-
//
|
|
1980
|
-
// ⚠️ We cannot tell WHY it is absent from here — a response shape that
|
|
1981
|
-
// changed, a lane that shipped nothing, a backend that does not echo the
|
|
1982
|
-
// document. Report the observable fact and let the operator carry it.
|
|
1983
|
-
note(
|
|
1984
|
-
'identity not banked: this push returned no post-write document, so no per-item ' +
|
|
1985
|
-
'$uuid was stored. The next push or publish will be identity-blind and the backend ' +
|
|
1986
|
-
'may refuse it. `uniweb pull` re-arms identity if that happens.'
|
|
1987
|
-
)
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1990
|
-
// The files of the units the backend now holds as ours are the synced version — the
|
|
1991
|
-
// ancestor the next `pull --merge` merges from.
|
|
1992
|
-
if (heldUnits.length) recordPushedUnits(siteDir, heldUnits)
|
|
2058
|
+
// (The site-content lane's own state was settled when it landed — `settleSiteContent`.)
|
|
1993
2059
|
// What the backend holds that this copy doesn't. None of it was overwritten, and no
|
|
1994
2060
|
// later push will overwrite it — but the files are behind until a pull.
|
|
1995
2061
|
if (notHeld.kept.length || notHeld.foreign.length) {
|
package/src/commands/publish.js
CHANGED
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
ensureItemUuids,
|
|
88
88
|
readFolderItemUuids,
|
|
89
89
|
readRecordItemUuids,
|
|
90
|
-
|
|
90
|
+
recoverUnbankedIdentity,
|
|
91
91
|
ensureSiteExists,
|
|
92
92
|
refuseUnsendableRecords,
|
|
93
93
|
clearRemoteSyncStateIfUnbound,
|
|
@@ -973,16 +973,9 @@ export async function publish(args = []) {
|
|
|
973
973
|
let pkg
|
|
974
974
|
try {
|
|
975
975
|
pkg = await emitSyncPackages(siteDir, emitOptions)
|
|
976
|
-
//
|
|
977
|
-
const
|
|
978
|
-
if (
|
|
979
|
-
if (await recoverRecordItemUuids({ client, siteDir, uuids: unbanked, note: (m) => say.dim(m) })) {
|
|
980
|
-
pkg = await emitSyncPackages(siteDir, {
|
|
981
|
-
...emitOptions,
|
|
982
|
-
recordItemUuids: readRecordItemUuids(siteDir, client.origin)
|
|
983
|
-
})
|
|
984
|
-
}
|
|
985
|
-
}
|
|
976
|
+
// Identity the backend holds and this copy lacks — see `uniweb push`.
|
|
977
|
+
const again = await recoverUnbankedIdentity({ client, siteDir, pkg, note: (m) => say.dim(m) })
|
|
978
|
+
if (again) pkg = await emitSyncPackages(siteDir, { ...emitOptions, ...again })
|
|
986
979
|
} catch (err) {
|
|
987
980
|
say.err(`Could not build the sync package: ${err.message}`)
|
|
988
981
|
return { exitCode: 1 }
|
package/src/commands/push.js
CHANGED
|
@@ -83,7 +83,7 @@ import {
|
|
|
83
83
|
readFolderItemUuids,
|
|
84
84
|
readQueryUuids,
|
|
85
85
|
readRecordItemUuids,
|
|
86
|
-
|
|
86
|
+
recoverUnbankedIdentity,
|
|
87
87
|
ensureItemUuids,
|
|
88
88
|
refuseUnsendableRecords,
|
|
89
89
|
ensureSiteExists,
|
|
@@ -535,18 +535,12 @@ export async function push(args = [], deps = {}) {
|
|
|
535
535
|
let pkg
|
|
536
536
|
try {
|
|
537
537
|
pkg = await emitSyncPackages(siteDir, emitOptions)
|
|
538
|
-
// A record the backend holds
|
|
539
|
-
//
|
|
540
|
-
// build the package again with
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
pkg = await emitSyncPackages(siteDir, {
|
|
545
|
-
...emitOptions,
|
|
546
|
-
recordItemUuids: readRecordItemUuids(siteDir, client.origin)
|
|
547
|
-
})
|
|
548
|
-
}
|
|
549
|
-
}
|
|
538
|
+
// A page, section or record list item the backend holds and this copy has no identity
|
|
539
|
+
// for — a map left partial, or a record pushed before its items were banked — is refused
|
|
540
|
+
// if sent without it. Recover it from the backend, and build the package again with it.
|
|
541
|
+
const again =
|
|
542
|
+
output || dryRun ? null : await recoverUnbankedIdentity({ client, siteDir, pkg, note })
|
|
543
|
+
if (again) pkg = await emitSyncPackages(siteDir, { ...emitOptions, ...again })
|
|
550
544
|
} catch (err) {
|
|
551
545
|
error(`Could not build the sync package: ${err.message}`)
|
|
552
546
|
return { exitCode: 2 }
|