@johnhenry/packfile 0.0.0 → 0.0.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.md +10 -1
- package/blob-preview.d.ts +86 -0
- package/browser.d.ts +86 -0
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -197,7 +197,7 @@ Uses SHA-256 hashing (same as file ETags) for consistent cache keys.
|
|
|
197
197
|
import { fromArchive, toArchive, createRouter } from '@johnhenry/packfile/browser';
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
-
The browser bundle provides `fromArchive`, `toArchive`, and `createRouter`, using the `wbn` package directly (no Node APIs required) and Web Crypto for hashing -- same wire format as the Node entrypoint, so an archive built by one is directly readable by the other.
|
|
200
|
+
The browser bundle provides `fromArchive`, `toArchive`, and `createRouter`, using the `wbn` package directly (no Node APIs required) and Web Crypto for hashing -- same wire format as the Node entrypoint, so an archive built by one is directly readable by the other. **`toArchive()` here returns an `ArrayBuffer`, not the `Buffer` the Node `.` entry's `toArchive()` returns** (or a `Uint8Array` when called with `{ compressed: false }`) -- there is no `Buffer` in a browser. Types for this subpath are declared in `browser.d.ts` (see `./browser`'s `types` condition in `package.json`).
|
|
201
201
|
|
|
202
202
|
```js
|
|
203
203
|
const archive = await fetch('/app.wbn').then(r => r.arrayBuffer());
|
|
@@ -405,6 +405,15 @@ import { compressObject, deCompressObject } from '@johnhenry/packfile/compressio
|
|
|
405
405
|
| `./blob-preview` | `lib/blob-preview.mjs` | `createBlobPreview` — host a `FilesMap` client-side via `blob:` URLs, no server |
|
|
406
406
|
| `./web-bundle` | `lib/web-bundle.mjs` | Lower-level Web Bundle primitives: `toWebBundle`, `fromWebBundle`, `createWebBundleRouter` — the engine `toArchive`/`fromArchive` are built on, with a real `baseURL`/headers/IWA-signing exposed |
|
|
407
407
|
|
|
408
|
+
TypeScript types: `.`, `./browser`, and `./blob-preview` each have a `types`
|
|
409
|
+
condition and a real `.d.ts` file (`types.d.ts`, `browser.d.ts`,
|
|
410
|
+
`blob-preview.d.ts`). The remaining subpaths (`./compat`, `./cache`,
|
|
411
|
+
`./hash`, `./compression`, `./web-bundle`) do not yet -- importing from one
|
|
412
|
+
of those in TypeScript will type-check as `any`, not a compile error, but
|
|
413
|
+
also not real type safety. (`./browser` and `./blob-preview` were fixed in
|
|
414
|
+
[#5](https://github.com/johnhenry/packfile/issues/5); the others are open,
|
|
415
|
+
unfixed instances of the same gap.)
|
|
416
|
+
|
|
408
417
|
## Security model
|
|
409
418
|
|
|
410
419
|
**What packfile guarantees:**
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { FilesMap } from "./types";
|
|
2
|
+
|
|
3
|
+
export { FilesMap };
|
|
4
|
+
|
|
5
|
+
// Note: `blob-preview.d.ts` describes the `./blob-preview` entry point
|
|
6
|
+
// (`lib/blob-preview.mjs`), whose only export is `createBlobPreview`.
|
|
7
|
+
|
|
8
|
+
/** Why a reference was left unrewritten (see README "What this does and
|
|
9
|
+
* does not solve"): either the target path doesn't exist in the given
|
|
10
|
+
* `FilesMap` ("missing"), or resolving it would require a file that's
|
|
11
|
+
* still mid-finalization -- a genuine reference cycle ("cycle"). */
|
|
12
|
+
export type UnresolvedReferenceReason = "missing" | "cycle";
|
|
13
|
+
|
|
14
|
+
export type UnresolvedReferenceInfo = {
|
|
15
|
+
reason: UnresolvedReferenceReason;
|
|
16
|
+
targetPath: string;
|
|
17
|
+
fromPath: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type CreateBlobPreviewOptions = {
|
|
21
|
+
/** The entry-point path, must exist in `files`. Default `"index.html"`. */
|
|
22
|
+
rootPath?: string;
|
|
23
|
+
/** Throw instead of warning when a relative reference can't be resolved
|
|
24
|
+
* (missing file, or a reference-cycle closing edge). Default `false`. */
|
|
25
|
+
strict?: boolean;
|
|
26
|
+
/** Called instead of the default `console.warn` for every reference this
|
|
27
|
+
* module leaves unrewritten because it couldn't (or, for cycles,
|
|
28
|
+
* shouldn't) be resolved. Ignored when `strict` is set (which throws
|
|
29
|
+
* instead). */
|
|
30
|
+
onUnresolvedReference?: (info: UnresolvedReferenceInfo) => void;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A registry of in-memory JS files, each backed by its own `blob:` URL.
|
|
35
|
+
*
|
|
36
|
+
* This is a duplicate of `@johnhenry/andbox`'s own `VirtualModuleRegistry`
|
|
37
|
+
* interface (from `createVirtualModuleRegistry()`, which `createBlobPreview`
|
|
38
|
+
* uses internally for JS specifier resolution), not an import of it: as of
|
|
39
|
+
* this writing `@johnhenry/andbox`'s `package.json` has no `types`
|
|
40
|
+
* condition of its own (the same class of bug this file's sibling
|
|
41
|
+
* `browser.d.ts` fixes for this package -- see packfile issue #5), so
|
|
42
|
+
* `import("@johnhenry/andbox").VirtualModuleRegistry` does not resolve for
|
|
43
|
+
* a consumer of *this* package under `moduleResolution: "nodenext"`/
|
|
44
|
+
* `"bundler"`. Duplicated here deliberately so this package's own types
|
|
45
|
+
* stay resolvable regardless of that separate, upstream issue; keep this
|
|
46
|
+
* in sync with `@johnhenry/andbox`'s `src/index.d.ts` if it changes.
|
|
47
|
+
*/
|
|
48
|
+
export interface VirtualModuleRegistry {
|
|
49
|
+
/** Get the `blob:` URL registered for a path, or `null` if unknown. */
|
|
50
|
+
resolve(path: string): string | null;
|
|
51
|
+
/** Resolve a module specifier the way `import` would, from the point of
|
|
52
|
+
* view of a given importing file: import-map resolution first, then a
|
|
53
|
+
* relative-path fallback, then `null` if neither matched. */
|
|
54
|
+
resolveSpecifier(specifier: string, parentPath?: string): string | null;
|
|
55
|
+
/** Register (or replace) a file at runtime. Returns the new blob URL. */
|
|
56
|
+
define(path: string, source: string): string;
|
|
57
|
+
/** Whether a path is registered. */
|
|
58
|
+
has(path: string): boolean;
|
|
59
|
+
/** All registered paths. */
|
|
60
|
+
paths(): string[];
|
|
61
|
+
/** Revoke every blob URL this registry has ever minted. */
|
|
62
|
+
dispose(): void;
|
|
63
|
+
/** Whether `dispose()` has been called. */
|
|
64
|
+
isDisposed(): boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type BlobPreview = {
|
|
68
|
+
/** `blob:` URL for `rootPath`. */
|
|
69
|
+
entryUrl: string;
|
|
70
|
+
/** Look up the `blob:` URL minted for a given packaged path. */
|
|
71
|
+
resolve(path: string): string | null;
|
|
72
|
+
/** Revokes every `blob:` URL this call minted. */
|
|
73
|
+
dispose(): void;
|
|
74
|
+
/** The underlying andbox registry, for advanced JS-specifier resolution. */
|
|
75
|
+
registry: VirtualModuleRegistry;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Turn a packfile `FilesMap` into a set of `blob:` URLs suitable for hosting
|
|
80
|
+
* inside a browser tab/iframe with no server. For trusted/your-own content
|
|
81
|
+
* only -- see README's "What this does and does not solve".
|
|
82
|
+
*/
|
|
83
|
+
export function createBlobPreview(
|
|
84
|
+
files: FilesMap,
|
|
85
|
+
options?: CreateBlobPreviewOptions
|
|
86
|
+
): Promise<BlobPreview>;
|
package/browser.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { FileEntry, FilesMap, RouterOptions, RouteHandler } from "./types";
|
|
2
|
+
|
|
3
|
+
export { FileEntry, FilesMap, RouterOptions, RouteHandler };
|
|
4
|
+
|
|
5
|
+
// Note: `browser.d.ts` describes the `./browser` entry point (`browser.mjs`),
|
|
6
|
+
// not the main `.` entry (see `types.d.ts` for that). `createRouter` is the
|
|
7
|
+
// exact same implementation as the `.` entry's (both import
|
|
8
|
+
// `./lib/create-router.mjs`), so its types are reused unchanged. `toArchive`
|
|
9
|
+
// and `fromArchive`, however, are a *separate* implementation from the Node
|
|
10
|
+
// entry's (`lib/to-archive.mjs`/`lib/from-archive.mjs`) -- same wire format,
|
|
11
|
+
// but different runtime types, because there is no `Buffer` in a browser:
|
|
12
|
+
//
|
|
13
|
+
// - `toArchive()`'s options key is `compressed` here, not `compress` (the
|
|
14
|
+
// Node entry's key) -- a real, pre-existing naming inconsistency between
|
|
15
|
+
// the two entrypoints, not a typo introduced by this file. There is also
|
|
16
|
+
// no `compressionLevel` option here (browser.mjs's own comment notes
|
|
17
|
+
// `CompressionStream` has no level parameter to plumb one through to).
|
|
18
|
+
// - `toArchive()` returns a `Uint8Array` when called with
|
|
19
|
+
// `{ compressed: false }` (the raw, uncompressed Web Bundle from
|
|
20
|
+
// `wbn`'s `BundleBuilder.createBundle()`), and an `ArrayBuffer` when
|
|
21
|
+
// compression runs (the default): `compressObject()`
|
|
22
|
+
// (`lib/compression.browser.mjs`) pipes through `CompressionStream` and
|
|
23
|
+
// resolves via `Response#arrayBuffer()`. The Node entry's `toArchive()`,
|
|
24
|
+
// by contrast, always returns a `Buffer`. Don't assume this matches the
|
|
25
|
+
// Node types -- confirmed by reading both implementations, not guessed.
|
|
26
|
+
// - `fromArchive()`'s `buffer` parameter is `ArrayBuffer | Uint8Array`, not
|
|
27
|
+
// `Buffer | ArrayBuffer | Uint8Array` like the Node entry -- there is no
|
|
28
|
+
// `Buffer` global to accept in a browser build.
|
|
29
|
+
|
|
30
|
+
export type BrowserToArchiveOptions = {
|
|
31
|
+
/** Default `true`. When `false`, skips compression and returns the raw
|
|
32
|
+
* Web Bundle bytes as a `Uint8Array` instead of an `ArrayBuffer`. */
|
|
33
|
+
compressed?: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type BrowserFromArchiveOptions = {
|
|
37
|
+
/** Default `true`. Set `false` if `buffer` is an uncompressed Web Bundle. */
|
|
38
|
+
compressed?: boolean;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Serializes a file Map to a (by default gzip-compressed) Web Bundle.
|
|
43
|
+
* Returns an `ArrayBuffer` when compressed (the default); returns the raw
|
|
44
|
+
* `Uint8Array` bundle directly when called with `{ compressed: false }`.
|
|
45
|
+
* Same wire format as the Node `.` entry's `toArchive()`, which always
|
|
46
|
+
* returns a `Buffer` -- the two are readable by each other regardless.
|
|
47
|
+
*
|
|
48
|
+
* Declared as overloads (rather than a single `Promise<ArrayBuffer |
|
|
49
|
+
* Uint8Array>` signature) so a literal `{ compressed: false }` narrows the
|
|
50
|
+
* return type precisely instead of forcing every caller to deal with the
|
|
51
|
+
* union.
|
|
52
|
+
*/
|
|
53
|
+
export function toArchive(
|
|
54
|
+
map: Map<string, FileEntry>,
|
|
55
|
+
options?: { compressed?: true }
|
|
56
|
+
): Promise<ArrayBuffer>;
|
|
57
|
+
export function toArchive(
|
|
58
|
+
map: Map<string, FileEntry>,
|
|
59
|
+
options: { compressed: false }
|
|
60
|
+
): Promise<Uint8Array>;
|
|
61
|
+
export function toArchive(
|
|
62
|
+
map: Map<string, FileEntry>,
|
|
63
|
+
options?: BrowserToArchiveOptions
|
|
64
|
+
): Promise<ArrayBuffer | Uint8Array>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Deserializes a (by default gzip-compressed) Web Bundle back into a
|
|
68
|
+
* `Map<string, FileEntry>`. Accepts an `ArrayBuffer` or `Uint8Array` --
|
|
69
|
+
* there is no `Buffer` global in a browser build.
|
|
70
|
+
*/
|
|
71
|
+
export function fromArchive(
|
|
72
|
+
buffer: ArrayBuffer | Uint8Array,
|
|
73
|
+
options?: BrowserFromArchiveOptions
|
|
74
|
+
): Promise<Map<string, FileEntry>>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns a `(input, ctx?) => Promise<Response>` handler that serves files
|
|
78
|
+
* from a `Map`/`LazyFileMap`. `input` may be a path string or a `Request`.
|
|
79
|
+
* The returned function also has itself assigned to `.fetch`. Identical
|
|
80
|
+
* implementation to the `.` entry's `createRouter` (both import
|
|
81
|
+
* `./lib/create-router.mjs`).
|
|
82
|
+
*/
|
|
83
|
+
export function createRouter(
|
|
84
|
+
files: FilesMap,
|
|
85
|
+
options?: RouterOptions
|
|
86
|
+
): RouteHandler;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnhenry/packfile",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"types": "./types.d.ts",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"test": "node --test test.mjs",
|
|
27
|
+
"typecheck": "tsc --project test/types-fixture/tsconfig.json",
|
|
27
28
|
"demo:compile": "node demo/compile.mjs",
|
|
28
29
|
"demo:server": "node demo/server.mjs",
|
|
29
30
|
"demo:browser": "npx serve ."
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"theres-waldo": "^0.0.0",
|
|
42
|
+
"typescript": "^7.0.2",
|
|
41
43
|
"wbn-sign": "^0.3.1"
|
|
42
44
|
},
|
|
43
45
|
"exports": {
|
|
@@ -45,21 +47,29 @@
|
|
|
45
47
|
"types": "./types.d.ts",
|
|
46
48
|
"default": "./index.mjs"
|
|
47
49
|
},
|
|
48
|
-
"./browser":
|
|
50
|
+
"./browser": {
|
|
51
|
+
"types": "./browser.d.ts",
|
|
52
|
+
"default": "./browser.mjs"
|
|
53
|
+
},
|
|
49
54
|
"./compat": "./compat.mjs",
|
|
50
55
|
"./cache": "./cache.mjs",
|
|
51
56
|
"./hash": "./lib/hash.mjs",
|
|
52
57
|
"./compression": "./lib/compression.mjs",
|
|
53
|
-
"./blob-preview":
|
|
58
|
+
"./blob-preview": {
|
|
59
|
+
"types": "./blob-preview.d.ts",
|
|
60
|
+
"default": "./lib/blob-preview.mjs"
|
|
61
|
+
},
|
|
54
62
|
"./web-bundle": "./lib/web-bundle.mjs"
|
|
55
63
|
},
|
|
56
64
|
"files": [
|
|
57
65
|
"index.mjs",
|
|
58
66
|
"browser.mjs",
|
|
67
|
+
"browser.d.ts",
|
|
59
68
|
"compat.mjs",
|
|
60
69
|
"cache.mjs",
|
|
61
70
|
"packfile.mjs",
|
|
62
71
|
"lib/",
|
|
72
|
+
"blob-preview.d.ts",
|
|
63
73
|
"types.d.ts",
|
|
64
74
|
"types.ts",
|
|
65
75
|
"README.md",
|