@kubohiroya/turbowarp-extension-loader 0.5.0 → 0.5.1

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.ja.md CHANGED
@@ -218,7 +218,8 @@ Manifest は `uri` を持てます。その作品をダウンロードできる
218
218
  {"schemaVersion": 1, "uri": "https://example.test/editor/turbowarp-plus-projects/66/66aa/0193f0a1-2b3c-7d4e-8f01-2233445566aa.sb3", "extensions": []}
219
219
  ```
220
220
 
221
- 1つの作品に1つの URI。何度編集しても変わりません。だから指紋ではなく住所なのです。指紋は保存
221
+ 1つの作品に1つの URI。何度編集しても変わりません。拡張を足したり形式を変えたりすると Manifest は
222
+ 組み直されますが、住所はその向こう側で保たれます。だから指紋ではなく住所なのです。指紋は保存
222
223
  するたびに変わるので、ブラウザーのキャッシュも開く人の選択の記録も、触るたびに同じ作品を別名で
223
224
  綴じてしまいます。住所は中身が変わっても変わりません。
224
225
 
package/README.md CHANGED
@@ -220,7 +220,8 @@ identifies it.
220
220
  {"schemaVersion": 1, "uri": "https://example.test/editor/turbowarp-plus-projects/66/66aa/0193f0a1-2b3c-7d4e-8f01-2233445566aa.sb3", "extensions": []}
221
221
  ```
222
222
 
223
- One work, one URI, across every edit. That is why it is an address and not a fingerprint: a
223
+ One work, one URI, across every edit — including the edits that change its extensions, which
224
+ rebuild the manifest around it. That is why it is an address and not a fingerprint: a
224
225
  fingerprint changes on every save, so a browser cache and a record of what the opener chose would
225
226
  file one work under a new name each time it was touched. An address does not change when the bytes
226
227
  do.
package/dist/packager.js CHANGED
@@ -81,7 +81,10 @@ export async function convertProjectSources(input, ports, { zip: Zip, targets =
81
81
  for (const id of Object.keys(targets))
82
82
  if (!records.some(record => record.id === id))
83
83
  fail('UNKNOWN_EXTENSION', `Unknown conversion target ${id}`);
84
- const manifest = validateManifest({ schemaVersion: 1, extensions });
84
+ // The project keeps its address through a conversion: it is the same work, served from the
85
+ // same place, however its extensions are now held.
86
+ const manifest = validateManifest({ schemaVersion: 1,
87
+ ...(prepared.manifest.uri === undefined ? {} : { uri: prepared.manifest.uri }), extensions });
85
88
  const lock = Object.freeze({ schemaVersion: 1, previousLock: project.turboWarpPlusLock ?? null, extensions: Object.freeze(lockEntries) });
86
89
  project.turboWarpPlus = manifest;
87
90
  project.turboWarpPlusLock = lock;
@@ -94,10 +94,13 @@ export async function prepareExtensionAddition(input, request, ports, { zip: Zip
94
94
  if (project.extensionURLs !== undefined && !plainObject(project.extensionURLs))
95
95
  fail('INVALID_PROJECT', 'Project extensionURLs must be an object');
96
96
  const previous = prepared.manifest?.extensions || [];
97
+ // Carried through every rebuild below: an address that changed when an extension was
98
+ // added would not be an address.
99
+ const carried = prepared.manifest?.uri === undefined ? {} : { uri: prepared.manifest.uri };
97
100
  if (previous.some(spec => spec.id === draft.id) || (project.extensions || []).includes(draft.id) ||
98
101
  Object.hasOwn(project.extensionURLs || {}, draft.id))
99
102
  fail('DUPLICATE_EXTENSION', 'This extension ID already belongs to the project', draft.id);
100
- validateManifest({ schemaVersion: 1, extensions: [...previous, draft] }, loaderOptions);
103
+ validateManifest({ schemaVersion: 1, ...carried, extensions: [...previous, draft] }, loaderOptions);
101
104
  if (draft.source.type === 'embedded-file' && Object.hasOwn(files, draft.source.path)) {
102
105
  fail('SOURCE_PATH_COLLISION', 'The embedded path already exists in this project', draft.id);
103
106
  }
@@ -128,7 +131,7 @@ export async function prepareExtensionAddition(input, request, ports, { zip: Zip
128
131
  }
129
132
  const verified = new Uint8Array(bytes);
130
133
  const sha256 = await wait(() => digest(verified));
131
- const manifest = validateManifest({ schemaVersion: 1, extensions: [...previous, { ...draft, sha256 }] }, loaderOptions);
134
+ const manifest = validateManifest({ schemaVersion: 1, ...carried, extensions: [...previous, { ...draft, sha256 }] }, loaderOptions);
132
135
  const spec = manifest.extensions.find(item => item.id === draft.id);
133
136
  project.turboWarpPlus = manifest;
134
137
  project.extensions = [...(project.extensions || []), spec.id];
@@ -173,7 +173,11 @@ export async function prepareCatalogExtensionChanges(input, requests, ports, { z
173
173
  ...(old?.publisher ? { publisher: old.publisher } : {}),
174
174
  capabilities: old?.capabilities || [], dependencies: choice.dependencies });
175
175
  }
176
- const manifest = validateManifest({ schemaVersion: 1, extensions: [...extensions.values()] }, loaderOptions);
176
+ // The project's own address survives a change to its extensions. Rebuilding the manifest
177
+ // without it would file the same work under a new name the next time it was saved, which
178
+ // is the one thing an address is for.
179
+ const manifest = validateManifest({ schemaVersion: 1, ...(prepared.manifest?.uri === undefined ?
180
+ {} : { uri: prepared.manifest.uri }), extensions: [...extensions.values()] }, loaderOptions);
177
181
  for (const spec of manifest.extensions)
178
182
  if (spec.source.type === 'embedded-file')
179
183
  replacedPaths.delete(spec.source.path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubohiroya/turbowarp-extension-loader",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Host-independent verified TurboWarp Plus extension loading core",
5
5
  "keywords": [
6
6
  "turbowarp",