@inkandswitch/patchwork 0.0.1 → 0.1.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/CHANGELOG.md +20 -0
- package/dist/client.d.ts +0 -2
- package/dist/index.js +1 -1
- package/dist/repo.d.ts +1 -3
- package/dist/repo.js +6 -4
- package/dist/site-kit/index.d.ts +1 -1
- package/dist/site-kit/options.d.ts +20 -16
- package/dist/site-kit/options.js +0 -8
- package/dist/site-kit/sync-servers.d.ts +12 -5
- package/dist/site-kit/sync-servers.js +27 -14
- package/dist/types.d.ts +0 -5
- package/dist/vite/config-plugin.d.ts +1 -1
- package/dist/vite/config-plugin.js +8 -3
- package/dist/vite/patchwork-plugin.d.ts +1 -1
- package/package.json +6 -6
- package/src/client.d.ts +0 -2
- package/src/index.ts +0 -1
- package/src/repo.ts +11 -8
- package/src/site-kit/index.ts +1 -0
- package/src/site-kit/options.ts +19 -17
- package/src/site-kit/sync-servers.ts +31 -13
- package/src/types.ts +0 -6
- package/src/vite/config-plugin.ts +12 -5
- package/src/vite/patchwork-plugin.ts +1 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# @inkandswitch/patchwork
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0aa315d: Configure Subduction or Keyhive with exclusive `syncServers` configuration. `syncServers.keyhive` replaces the `keyhive` and `keyhiveSyncServer` site options and the runtime `setup({ keyhive })` option. Selecting a named ARK relay or providing a custom relay identity and URL enables Keyhive, and configured server URLs now control worker connections as well as connection hints.
|
|
8
|
+
- bd63259: New package: one import for a Patchwork site. It owns the boot sequence (`repo`, `router`, `loading`), the vite plugin (config, html, importmap, manifest, netlify, icons, service worker), the site-kit config helpers, and the ambient client types — all previously spread across the bootloader and each site's own `index.html`, `vite.config.ts`, and `public/` directory.
|
|
9
|
+
|
|
10
|
+
A site is now a `package.json` dependency, a `vite.config.ts` with `patchwork({...})`, and a `main.ts` that imports `@inkandswitch/patchwork`.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [0aa315d]
|
|
15
|
+
- Updated dependencies [bd63259]
|
|
16
|
+
- Updated dependencies [bd63259]
|
|
17
|
+
- Updated dependencies [bd63259]
|
|
18
|
+
- @inkandswitch/patchwork-bootloader@0.5.0
|
|
19
|
+
- @inkandswitch/patchwork-elements@4.0.2
|
|
20
|
+
- @inkandswitch/patchwork-filesystem@0.2.3
|
package/dist/client.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -84,7 +84,7 @@ async function doSetup(options) {
|
|
|
84
84
|
}
|
|
85
85
|
});
|
|
86
86
|
let workerAdapter = new MessageChannelNetworkAdapter(workerPort);
|
|
87
|
-
({ repo, hive, signerIdentity } = await createRepo(
|
|
87
|
+
({ repo, hive, signerIdentity } = await createRepo(siteName, workerAdapter));
|
|
88
88
|
// The worker was recreated with cold state: wire the repo onto the fresh
|
|
89
89
|
// port and drop the adapter stranded on the dead one.
|
|
90
90
|
const bootHive = hive;
|
package/dist/repo.d.ts
CHANGED
|
@@ -3,9 +3,7 @@ import { type AutomergeRepoKeyhive } from "@automerge/automerge-repo-keyhive";
|
|
|
3
3
|
import setupServiceWorker from "@inkandswitch/patchwork-bootloader";
|
|
4
4
|
import type { SignerIdentity } from "./types.js";
|
|
5
5
|
export declare function initWasm(): Promise<void>;
|
|
6
|
-
export declare function createRepo(
|
|
7
|
-
keyhive?: boolean;
|
|
8
|
-
}, siteName: string, workerAdapter: MessageChannelNetworkAdapter): Promise<{
|
|
6
|
+
export declare function createRepo(siteName: string, workerAdapter: MessageChannelNetworkAdapter): Promise<{
|
|
9
7
|
repo: Repo;
|
|
10
8
|
hive?: AutomergeRepoKeyhive;
|
|
11
9
|
signerIdentity?: SignerIdentity;
|
package/dist/repo.js
CHANGED
|
@@ -7,7 +7,9 @@ import { initSync as initSubductionSync } from "@automerge/automerge-subduction/
|
|
|
7
7
|
import { MemorySigner } from "@automerge/automerge-subduction/slim";
|
|
8
8
|
import debug from "debug";
|
|
9
9
|
const log = debug("patchwork:setup:repo");
|
|
10
|
-
const
|
|
10
|
+
const syncServer = typeof __SYNC_SERVER__ !== "undefined"
|
|
11
|
+
? __SYNC_SERVER__
|
|
12
|
+
: { url: "wss://subduction.sync.inkandswitch.com" };
|
|
11
13
|
// Fetch and initialize automerge + subduction wasm. Memoized: the fetches start
|
|
12
14
|
// on the first call and every later caller awaits the same init. Skipped
|
|
13
15
|
// entirely when the site brings its own Repo (it did this itself).
|
|
@@ -25,8 +27,8 @@ export function initWasm() {
|
|
|
25
27
|
}
|
|
26
28
|
return wasmReady;
|
|
27
29
|
}
|
|
28
|
-
export async function createRepo(
|
|
29
|
-
if (
|
|
30
|
+
export async function createRepo(siteName, workerAdapter) {
|
|
31
|
+
if (syncServer.keyhive) {
|
|
30
32
|
log("setting up keyhive");
|
|
31
33
|
initKeyhiveWasm();
|
|
32
34
|
const { hive, repo } = await initializeAutomergeRepoKeyhiveWithRepo({
|
|
@@ -38,7 +40,7 @@ export async function createRepo(config, siteName, workerAdapter) {
|
|
|
38
40
|
cachingMode: "periodic",
|
|
39
41
|
onlyShareWithHardcodedServerPeerId: false,
|
|
40
42
|
// ARK selects the relay via `syncServer`, defaulting to "subduction".
|
|
41
|
-
|
|
43
|
+
syncServer: syncServer.keyhive,
|
|
42
44
|
repo: {
|
|
43
45
|
storage: new IndexedDBWorkerStorageAdapter(),
|
|
44
46
|
enableRemoteHeadsGossiping: true,
|
package/dist/site-kit/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* wires these into vite's plugin hooks (dev middleware, emitFile, virtual
|
|
8
8
|
* modules, config()).
|
|
9
9
|
*/
|
|
10
|
-
export type { PatchworkSiteOptions, PatchworkIconsOptions, PatchworkHtmlOptions, PatchworkNetlifyOptions, PatchworkSyncServersOptions, } from "./options.js";
|
|
10
|
+
export type { PatchworkSiteOptions, PatchworkIconsOptions, PatchworkHtmlOptions, PatchworkNetlifyOptions, PatchworkKeyhiveSyncServer, PatchworkSyncServersOptions, } from "./options.js";
|
|
11
11
|
export { resolveSyncServers, PRELOAD_WASM_ASSETS } from "./sync-servers.js";
|
|
12
12
|
export { getIcons, ICON_SPECS, type IconSpec } from "./icons.js";
|
|
13
13
|
export { buildHtml, escapeHtml } from "./html.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SyncServerIdentity } from "@automerge/automerge-repo-keyhive";
|
|
1
2
|
/**
|
|
2
3
|
* The bundler-agnostic option shape for a Patchwork site's generated
|
|
3
4
|
* static assets (icons, index.html, manifest.webmanifest, Netlify config).
|
|
@@ -22,14 +23,20 @@ export interface PatchworkNetlifyOptions {
|
|
|
22
23
|
/** Cache-Control: immutable on /assets/*. Default true. */
|
|
23
24
|
immutableAssets?: boolean;
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
+
type PatchworkPrimarySyncServerOptions = {
|
|
27
|
+
subduction?: string;
|
|
28
|
+
keyhive?: never;
|
|
29
|
+
} | {
|
|
30
|
+
subduction?: never;
|
|
31
|
+
keyhive: PatchworkKeyhiveSyncServer;
|
|
32
|
+
};
|
|
33
|
+
export type PatchworkKeyhiveSyncServer = "keyhive" | "subduction" | ({
|
|
34
|
+
url: string;
|
|
35
|
+
} & SyncServerIdentity);
|
|
36
|
+
export type PatchworkSyncServersOptions = {
|
|
26
37
|
/** wss:// URL for the legacy automerge-repo sync-server channel (connected on demand via connectClassicSync). Default: wss://sync3.automerge.org. Pass false to skip its preconnect hint. */
|
|
27
38
|
classic?: string | false;
|
|
28
|
-
|
|
29
|
-
subduction?: string;
|
|
30
|
-
/** wss:// URL for keyhive sync — live when keyhiveSyncServer is true. Default: wss://keyhive.sync.automerge.org */
|
|
31
|
-
keyhive?: string;
|
|
32
|
-
}
|
|
39
|
+
} & PatchworkPrimarySyncServerOptions;
|
|
33
40
|
export interface PatchworkSiteOptions {
|
|
34
41
|
/** -> __SITE_NAME__ define */
|
|
35
42
|
siteName?: string;
|
|
@@ -41,10 +48,6 @@ export interface PatchworkSiteOptions {
|
|
|
41
48
|
description?: string;
|
|
42
49
|
/** default "/src/main.ts" — must be root-absolute, since the generated index.html doesn't live at the project root */
|
|
43
50
|
entry?: string;
|
|
44
|
-
/** -> __KEYHIVE__ define */
|
|
45
|
-
keyhive?: boolean;
|
|
46
|
-
/** -> __KEYHIVE_SYNC_SERVER__ define */
|
|
47
|
-
keyhiveSyncServer?: boolean;
|
|
48
51
|
themeColor?: string | {
|
|
49
52
|
light: string;
|
|
50
53
|
dark: string;
|
|
@@ -52,12 +55,12 @@ export interface PatchworkSiteOptions {
|
|
|
52
55
|
/** manifest background_color */
|
|
53
56
|
backgroundColor?: string;
|
|
54
57
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
58
|
+
* Sync-server configuration for this build. Providing `keyhive` enables
|
|
59
|
+
* keyhive and selects the relay identity ARK grants access to. Custom
|
|
60
|
+
* identities also require their WebSocket URL. `subduction` and `keyhive`
|
|
61
|
+
* are mutually exclusive. The live server and `classic` are also emitted as
|
|
62
|
+
* connection hints. Pass `false` to keep the default servers but skip those
|
|
63
|
+
* hints.
|
|
61
64
|
*/
|
|
62
65
|
syncServers?: false | PatchworkSyncServersOptions;
|
|
63
66
|
icons?: false | PatchworkIconsOptions;
|
|
@@ -65,3 +68,4 @@ export interface PatchworkSiteOptions {
|
|
|
65
68
|
manifest?: false | Record<string, unknown>;
|
|
66
69
|
netlify?: false | PatchworkNetlifyOptions;
|
|
67
70
|
}
|
|
71
|
+
export {};
|
package/dist/site-kit/options.js
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The bundler-agnostic option shape for a Patchwork site's generated
|
|
3
|
-
* static assets (icons, index.html, manifest.webmanifest, Netlify config).
|
|
4
|
-
* `../vite/patchwork-plugin.ts` extends this with vite-only config
|
|
5
|
-
* (importmap, server/preview/worker/build) — a different bundler adapter
|
|
6
|
-
* can reuse this same shape and the pure builders in this directory without
|
|
7
|
-
* pulling in anything vite-specific.
|
|
8
|
-
*/
|
|
9
1
|
export {};
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { PatchworkSiteOptions } from "./options.js";
|
|
2
|
+
import type { SyncServerSelection } from "@automerge/automerge-repo-keyhive";
|
|
3
|
+
export declare const DEFAULT_SYNC_SERVERS: {
|
|
4
|
+
classic: string;
|
|
5
|
+
subduction: string;
|
|
6
|
+
keyhive: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function resolvePrimarySyncServer(options: PatchworkSiteOptions): {
|
|
9
|
+
url: string;
|
|
10
|
+
keyhive?: SyncServerSelection;
|
|
11
|
+
};
|
|
2
12
|
/**
|
|
3
13
|
* Resolves which sync-server origins are actually live for this build: the
|
|
4
|
-
* channel that's live is subduction xor keyhive (
|
|
5
|
-
*
|
|
6
|
-
* classic (on-demand, but still worth a preconnect hint) unless disabled.
|
|
7
|
-
* A flat list would drift from `keyhiveSyncServer` — e.g. always hinting
|
|
8
|
-
* subduction even on a build that actually connects to keyhive.
|
|
14
|
+
* channel that's live is subduction xor keyhive plus classic (on-demand,
|
|
15
|
+
* but still worth a preconnect hint) unless disabled.
|
|
9
16
|
*/
|
|
10
17
|
export declare function resolveSyncServers(options: PatchworkSiteOptions): string[];
|
|
11
18
|
export declare const PRELOAD_WASM_ASSETS: string[];
|
|
@@ -2,33 +2,46 @@
|
|
|
2
2
|
// and automerge-worker.ts's SUBDUCTION_SYNC_URL selection — kept here as
|
|
3
3
|
// plain constants (rather than importing those runtime modules) since this
|
|
4
4
|
// only needs the hostnames, not the browser-only logic that reads them.
|
|
5
|
-
const DEFAULT_SYNC_SERVERS = {
|
|
5
|
+
export const DEFAULT_SYNC_SERVERS = {
|
|
6
6
|
classic: "wss://sync3.automerge.org",
|
|
7
7
|
subduction: "wss://subduction.sync.inkandswitch.com",
|
|
8
8
|
keyhive: "wss://keyhive.sync.automerge.org",
|
|
9
9
|
};
|
|
10
|
+
export function resolvePrimarySyncServer(options) {
|
|
11
|
+
const servers = options.syncServers || undefined;
|
|
12
|
+
if (servers?.keyhive) {
|
|
13
|
+
if (typeof servers.keyhive === "string") {
|
|
14
|
+
return {
|
|
15
|
+
keyhive: servers.keyhive,
|
|
16
|
+
url: DEFAULT_SYNC_SERVERS[servers.keyhive],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const { url, ...identity } = servers.keyhive;
|
|
20
|
+
return {
|
|
21
|
+
keyhive: identity,
|
|
22
|
+
url,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
url: servers?.subduction ?? DEFAULT_SYNC_SERVERS.subduction,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
10
29
|
function wsToHttpOrigin(wsUrl) {
|
|
11
30
|
return wsUrl.replace(/^ws/, "http");
|
|
12
31
|
}
|
|
13
32
|
/**
|
|
14
33
|
* Resolves which sync-server origins are actually live for this build: the
|
|
15
|
-
* channel that's live is subduction xor keyhive (
|
|
16
|
-
*
|
|
17
|
-
* classic (on-demand, but still worth a preconnect hint) unless disabled.
|
|
18
|
-
* A flat list would drift from `keyhiveSyncServer` — e.g. always hinting
|
|
19
|
-
* subduction even on a build that actually connects to keyhive.
|
|
34
|
+
* channel that's live is subduction xor keyhive plus classic (on-demand,
|
|
35
|
+
* but still worth a preconnect hint) unless disabled.
|
|
20
36
|
*/
|
|
21
37
|
export function resolveSyncServers(options) {
|
|
22
38
|
if (options.syncServers === false)
|
|
23
39
|
return [];
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
origins.push(primary);
|
|
30
|
-
if (servers.classic)
|
|
31
|
-
origins.push(servers.classic);
|
|
40
|
+
const primary = resolvePrimarySyncServer(options);
|
|
41
|
+
const classic = options.syncServers?.classic ?? DEFAULT_SYNC_SERVERS.classic;
|
|
42
|
+
const origins = [primary.url];
|
|
43
|
+
if (classic)
|
|
44
|
+
origins.push(classic);
|
|
32
45
|
return origins.map(wsToHttpOrigin);
|
|
33
46
|
}
|
|
34
47
|
// Emitted by importmap-plugin.ts. keyhive_wasm.wasm is loaded lazily (only
|
package/dist/types.d.ts
CHANGED
|
@@ -57,11 +57,6 @@ export interface PatchworkOptions {
|
|
|
57
57
|
name?: string;
|
|
58
58
|
/** DOM id of the `<patchwork-view>` hosting the root tool. Defaults to "root". */
|
|
59
59
|
rootElementId?: string;
|
|
60
|
-
/**
|
|
61
|
-
* Initialize keyhive for access control. The Repo then uses keyhive's network
|
|
62
|
-
* adapter, peerId and idFactory instead of a sharePolicy.
|
|
63
|
-
*/
|
|
64
|
-
keyhive?: boolean;
|
|
65
60
|
/**
|
|
66
61
|
* Bring your own Repo. When provided, setup skips wasm initialization and
|
|
67
62
|
* repo creation entirely — you are responsible for having initialized
|
|
@@ -2,7 +2,7 @@ import type { Plugin } from "vite";
|
|
|
2
2
|
import wasm from "vite-plugin-wasm";
|
|
3
3
|
import type { PatchworkVitePluginOptions } from "./patchwork-plugin.js";
|
|
4
4
|
/**
|
|
5
|
-
* Owns envPrefix, define (__SITE_NAME__/
|
|
5
|
+
* Owns envPrefix, define (__SITE_NAME__/sync-server configuration),
|
|
6
6
|
* server/preview CORS defaults, worker format + the wasm plugin, and build
|
|
7
7
|
* defaults (firefox150 target, unminified, sourcemapped) — everything a site
|
|
8
8
|
* used to hand-write in its own vite.config.ts. Each is switched off
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import wasm from "vite-plugin-wasm";
|
|
2
|
+
import { DEFAULT_SYNC_SERVERS, resolvePrimarySyncServer, } from "../site-kit/sync-servers.js";
|
|
2
3
|
const CORS_HEADERS = { "Access-Control-Allow-Origin": "*" };
|
|
3
4
|
/**
|
|
4
|
-
* Owns envPrefix, define (__SITE_NAME__/
|
|
5
|
+
* Owns envPrefix, define (__SITE_NAME__/sync-server configuration),
|
|
5
6
|
* server/preview CORS defaults, worker format + the wasm plugin, and build
|
|
6
7
|
* defaults (firefox150 target, unminified, sourcemapped) — everything a site
|
|
7
8
|
* used to hand-write in its own vite.config.ts. Each is switched off
|
|
@@ -11,9 +12,13 @@ export function configPlugin(options = {}) {
|
|
|
11
12
|
return {
|
|
12
13
|
name: "@patchwork/config",
|
|
13
14
|
config() {
|
|
15
|
+
const primarySyncServer = resolvePrimarySyncServer(options);
|
|
16
|
+
const classicSyncServer = options.syncServers && typeof options.syncServers.classic === "string"
|
|
17
|
+
? options.syncServers.classic
|
|
18
|
+
: DEFAULT_SYNC_SERVERS.classic;
|
|
14
19
|
const define = {
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
__SYNC_SERVER__: JSON.stringify(primarySyncServer),
|
|
21
|
+
__CLASSIC_SYNC_SERVER__: JSON.stringify(classicSyncServer),
|
|
17
22
|
};
|
|
18
23
|
if (options.siteName) {
|
|
19
24
|
define.__SITE_NAME__ = JSON.stringify(options.siteName);
|
|
@@ -31,7 +31,7 @@ export type ImportMap = {
|
|
|
31
31
|
[scope: string]: Imports;
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
|
-
export type { PatchworkSiteOptions, PatchworkIconsOptions, PatchworkHtmlOptions, PatchworkNetlifyOptions, PatchworkSyncServersOptions, } from "../site-kit/options.js";
|
|
34
|
+
export type { PatchworkSiteOptions, PatchworkIconsOptions, PatchworkHtmlOptions, PatchworkNetlifyOptions, PatchworkKeyhiveSyncServer, PatchworkSyncServersOptions, } from "../site-kit/options.js";
|
|
35
35
|
export interface PatchworkVitePluginOptions extends PatchworkSiteOptions {
|
|
36
36
|
importmap?: ImportMap;
|
|
37
37
|
server?: false | ServerOptions;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkandswitch/patchwork",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"author": "Ink & Switch",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"debug": "^4.4.3",
|
|
38
38
|
"sharp": "^0.35.3",
|
|
39
39
|
"vite-plugin-wasm": "^3.6.0",
|
|
40
|
-
"@inkandswitch/patchwork-bootloader": "^0.
|
|
41
|
-
"@inkandswitch/patchwork-
|
|
42
|
-
"@inkandswitch/patchwork-
|
|
43
|
-
"@inkandswitch/patchwork-
|
|
44
|
-
"@inkandswitch/patchwork-
|
|
40
|
+
"@inkandswitch/patchwork-bootloader": "^0.5.0",
|
|
41
|
+
"@inkandswitch/patchwork-elements": "^4.0.2",
|
|
42
|
+
"@inkandswitch/patchwork-filesystem": "^0.2.3",
|
|
43
|
+
"@inkandswitch/patchwork-plugins": "^1.0.1",
|
|
44
|
+
"@inkandswitch/patchwork-providers": "^0.4.2"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"esbuild": "^0.23.1",
|
package/src/client.d.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -152,7 +152,6 @@ async function doSetup(options: PatchworkOptions): Promise<Patchwork> {
|
|
|
152
152
|
|
|
153
153
|
let workerAdapter = new MessageChannelNetworkAdapter(workerPort);
|
|
154
154
|
({ repo, hive, signerIdentity } = await createRepo(
|
|
155
|
-
options,
|
|
156
155
|
siteName,
|
|
157
156
|
workerAdapter
|
|
158
157
|
));
|
package/src/repo.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
initKeyhiveWasm,
|
|
11
11
|
initializeAutomergeRepoKeyhiveWithRepo,
|
|
12
12
|
type AutomergeRepoKeyhive,
|
|
13
|
+
type SyncServerSelection,
|
|
13
14
|
} from "@automerge/automerge-repo-keyhive";
|
|
14
15
|
// eslint-disable-next-line
|
|
15
16
|
// @ts-ignore — initSync is a wasm-bindgen runtime helper not in the .d.ts
|
|
@@ -21,11 +22,14 @@ import debug from "debug";
|
|
|
21
22
|
|
|
22
23
|
const log = debug("patchwork:setup:repo");
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
declare const __SYNC_SERVER__: {
|
|
26
|
+
url: string;
|
|
27
|
+
keyhive?: SyncServerSelection;
|
|
28
|
+
};
|
|
29
|
+
const syncServer =
|
|
30
|
+
typeof __SYNC_SERVER__ !== "undefined"
|
|
31
|
+
? __SYNC_SERVER__
|
|
32
|
+
: { url: "wss://subduction.sync.inkandswitch.com" };
|
|
29
33
|
|
|
30
34
|
// Fetch and initialize automerge + subduction wasm. Memoized: the fetches start
|
|
31
35
|
// on the first call and every later caller awaits the same init. Skipped
|
|
@@ -46,7 +50,6 @@ export function initWasm(): Promise<void> {
|
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
export async function createRepo(
|
|
49
|
-
config: { keyhive?: boolean },
|
|
50
53
|
siteName: string,
|
|
51
54
|
workerAdapter: MessageChannelNetworkAdapter
|
|
52
55
|
): Promise<{
|
|
@@ -54,7 +57,7 @@ export async function createRepo(
|
|
|
54
57
|
hive?: AutomergeRepoKeyhive;
|
|
55
58
|
signerIdentity?: SignerIdentity;
|
|
56
59
|
}> {
|
|
57
|
-
if (
|
|
60
|
+
if (syncServer.keyhive) {
|
|
58
61
|
log("setting up keyhive");
|
|
59
62
|
initKeyhiveWasm();
|
|
60
63
|
const { hive, repo } = await initializeAutomergeRepoKeyhiveWithRepo({
|
|
@@ -66,7 +69,7 @@ export async function createRepo(
|
|
|
66
69
|
cachingMode: "periodic",
|
|
67
70
|
onlyShareWithHardcodedServerPeerId: false,
|
|
68
71
|
// ARK selects the relay via `syncServer`, defaulting to "subduction".
|
|
69
|
-
|
|
72
|
+
syncServer: syncServer.keyhive,
|
|
70
73
|
repo: {
|
|
71
74
|
storage: new IndexedDBWorkerStorageAdapter(),
|
|
72
75
|
enableRemoteHeadsGossiping: true,
|
package/src/site-kit/index.ts
CHANGED
package/src/site-kit/options.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { SyncServerIdentity } from "@automerge/automerge-repo-keyhive";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* The bundler-agnostic option shape for a Patchwork site's generated
|
|
3
5
|
* static assets (icons, index.html, manifest.webmanifest, Netlify config).
|
|
@@ -26,14 +28,19 @@ export interface PatchworkNetlifyOptions {
|
|
|
26
28
|
immutableAssets?: boolean;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
type PatchworkPrimarySyncServerOptions =
|
|
32
|
+
| { subduction?: string; keyhive?: never }
|
|
33
|
+
| { subduction?: never; keyhive: PatchworkKeyhiveSyncServer };
|
|
34
|
+
|
|
35
|
+
export type PatchworkKeyhiveSyncServer =
|
|
36
|
+
| "keyhive"
|
|
37
|
+
| "subduction"
|
|
38
|
+
| ({ url: string } & SyncServerIdentity);
|
|
39
|
+
|
|
40
|
+
export type PatchworkSyncServersOptions = {
|
|
30
41
|
/** wss:// URL for the legacy automerge-repo sync-server channel (connected on demand via connectClassicSync). Default: wss://sync3.automerge.org. Pass false to skip its preconnect hint. */
|
|
31
42
|
classic?: string | false;
|
|
32
|
-
|
|
33
|
-
subduction?: string;
|
|
34
|
-
/** wss:// URL for keyhive sync — live when keyhiveSyncServer is true. Default: wss://keyhive.sync.automerge.org */
|
|
35
|
-
keyhive?: string;
|
|
36
|
-
}
|
|
43
|
+
} & PatchworkPrimarySyncServerOptions;
|
|
37
44
|
|
|
38
45
|
export interface PatchworkSiteOptions {
|
|
39
46
|
/** -> __SITE_NAME__ define */
|
|
@@ -47,22 +54,17 @@ export interface PatchworkSiteOptions {
|
|
|
47
54
|
/** default "/src/main.ts" — must be root-absolute, since the generated index.html doesn't live at the project root */
|
|
48
55
|
entry?: string;
|
|
49
56
|
|
|
50
|
-
/** -> __KEYHIVE__ define */
|
|
51
|
-
keyhive?: boolean;
|
|
52
|
-
/** -> __KEYHIVE_SYNC_SERVER__ define */
|
|
53
|
-
keyhiveSyncServer?: boolean;
|
|
54
|
-
|
|
55
57
|
themeColor?: string | { light: string; dark: string };
|
|
56
58
|
/** manifest background_color */
|
|
57
59
|
backgroundColor?: string;
|
|
58
60
|
|
|
59
61
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
62
|
+
* Sync-server configuration for this build. Providing `keyhive` enables
|
|
63
|
+
* keyhive and selects the relay identity ARK grants access to. Custom
|
|
64
|
+
* identities also require their WebSocket URL. `subduction` and `keyhive`
|
|
65
|
+
* are mutually exclusive. The live server and `classic` are also emitted as
|
|
66
|
+
* connection hints. Pass `false` to keep the default servers but skip those
|
|
67
|
+
* hints.
|
|
66
68
|
*/
|
|
67
69
|
syncServers?: false | PatchworkSyncServersOptions;
|
|
68
70
|
|
|
@@ -1,36 +1,54 @@
|
|
|
1
1
|
import type { PatchworkSiteOptions } from "./options.js";
|
|
2
|
+
import type { SyncServerSelection } from "@automerge/automerge-repo-keyhive";
|
|
2
3
|
|
|
3
4
|
// Mirrors core/bootloader/src/sync-config.ts's DEFAULT_CLASSIC_SYNC_SERVER
|
|
4
5
|
// and automerge-worker.ts's SUBDUCTION_SYNC_URL selection — kept here as
|
|
5
6
|
// plain constants (rather than importing those runtime modules) since this
|
|
6
7
|
// only needs the hostnames, not the browser-only logic that reads them.
|
|
7
|
-
const DEFAULT_SYNC_SERVERS = {
|
|
8
|
+
export const DEFAULT_SYNC_SERVERS = {
|
|
8
9
|
classic: "wss://sync3.automerge.org",
|
|
9
10
|
subduction: "wss://subduction.sync.inkandswitch.com",
|
|
10
11
|
keyhive: "wss://keyhive.sync.automerge.org",
|
|
11
12
|
};
|
|
12
13
|
|
|
14
|
+
export function resolvePrimarySyncServer(options: PatchworkSiteOptions): {
|
|
15
|
+
url: string;
|
|
16
|
+
keyhive?: SyncServerSelection;
|
|
17
|
+
} {
|
|
18
|
+
const servers = options.syncServers || undefined;
|
|
19
|
+
if (servers?.keyhive) {
|
|
20
|
+
if (typeof servers.keyhive === "string") {
|
|
21
|
+
return {
|
|
22
|
+
keyhive: servers.keyhive,
|
|
23
|
+
url: DEFAULT_SYNC_SERVERS[servers.keyhive],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const { url, ...identity } = servers.keyhive;
|
|
27
|
+
return {
|
|
28
|
+
keyhive: identity,
|
|
29
|
+
url,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
url: servers?.subduction ?? DEFAULT_SYNC_SERVERS.subduction,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
13
37
|
function wsToHttpOrigin(wsUrl: string): string {
|
|
14
38
|
return wsUrl.replace(/^ws/, "http");
|
|
15
39
|
}
|
|
16
40
|
|
|
17
41
|
/**
|
|
18
42
|
* Resolves which sync-server origins are actually live for this build: the
|
|
19
|
-
* channel that's live is subduction xor keyhive (
|
|
20
|
-
*
|
|
21
|
-
* classic (on-demand, but still worth a preconnect hint) unless disabled.
|
|
22
|
-
* A flat list would drift from `keyhiveSyncServer` — e.g. always hinting
|
|
23
|
-
* subduction even on a build that actually connects to keyhive.
|
|
43
|
+
* channel that's live is subduction xor keyhive plus classic (on-demand,
|
|
44
|
+
* but still worth a preconnect hint) unless disabled.
|
|
24
45
|
*/
|
|
25
46
|
export function resolveSyncServers(options: PatchworkSiteOptions): string[] {
|
|
26
47
|
if (options.syncServers === false) return [];
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
: servers.subduction;
|
|
32
|
-
origins.push(primary);
|
|
33
|
-
if (servers.classic) origins.push(servers.classic);
|
|
48
|
+
const primary = resolvePrimarySyncServer(options);
|
|
49
|
+
const classic = options.syncServers?.classic ?? DEFAULT_SYNC_SERVERS.classic;
|
|
50
|
+
const origins = [primary.url];
|
|
51
|
+
if (classic) origins.push(classic);
|
|
34
52
|
return origins.map(wsToHttpOrigin);
|
|
35
53
|
}
|
|
36
54
|
|
package/src/types.ts
CHANGED
|
@@ -78,12 +78,6 @@ export interface PatchworkOptions {
|
|
|
78
78
|
/** DOM id of the `<patchwork-view>` hosting the root tool. Defaults to "root". */
|
|
79
79
|
rootElementId?: string;
|
|
80
80
|
|
|
81
|
-
/**
|
|
82
|
-
* Initialize keyhive for access control. The Repo then uses keyhive's network
|
|
83
|
-
* adapter, peerId and idFactory instead of a sharePolicy.
|
|
84
|
-
*/
|
|
85
|
-
keyhive?: boolean;
|
|
86
|
-
|
|
87
81
|
/**
|
|
88
82
|
* Bring your own Repo. When provided, setup skips wasm initialization and
|
|
89
83
|
* repo creation entirely — you are responsible for having initialized
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
import wasm from "vite-plugin-wasm";
|
|
3
3
|
import type { PatchworkVitePluginOptions } from "./patchwork-plugin.js";
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_SYNC_SERVERS,
|
|
6
|
+
resolvePrimarySyncServer,
|
|
7
|
+
} from "../site-kit/sync-servers.js";
|
|
4
8
|
|
|
5
9
|
const CORS_HEADERS = { "Access-Control-Allow-Origin": "*" };
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
|
-
* Owns envPrefix, define (__SITE_NAME__/
|
|
12
|
+
* Owns envPrefix, define (__SITE_NAME__/sync-server configuration),
|
|
9
13
|
* server/preview CORS defaults, worker format + the wasm plugin, and build
|
|
10
14
|
* defaults (firefox150 target, unminified, sourcemapped) — everything a site
|
|
11
15
|
* used to hand-write in its own vite.config.ts. Each is switched off
|
|
@@ -17,11 +21,14 @@ export function configPlugin(
|
|
|
17
21
|
return {
|
|
18
22
|
name: "@patchwork/config",
|
|
19
23
|
config() {
|
|
24
|
+
const primarySyncServer = resolvePrimarySyncServer(options);
|
|
25
|
+
const classicSyncServer =
|
|
26
|
+
options.syncServers && typeof options.syncServers.classic === "string"
|
|
27
|
+
? options.syncServers.classic
|
|
28
|
+
: DEFAULT_SYNC_SERVERS.classic;
|
|
20
29
|
const define: Record<string, string> = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
options.keyhiveSyncServer ?? false
|
|
24
|
-
),
|
|
30
|
+
__SYNC_SERVER__: JSON.stringify(primarySyncServer),
|
|
31
|
+
__CLASSIC_SYNC_SERVER__: JSON.stringify(classicSyncServer),
|
|
25
32
|
};
|
|
26
33
|
if (options.siteName) {
|
|
27
34
|
define.__SITE_NAME__ = JSON.stringify(options.siteName);
|