@kamilio/wire 0.1.2 → 0.1.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/README.md +1 -1
- package/bin/wire-mcp.mjs +1 -1
- package/dist/adapters/root.d.ts +5 -2
- package/dist/adapters/root.d.ts.map +1 -1
- package/dist/adapters/root.js +58 -30
- package/dist/adapters/root.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +6 -26
- package/dist/auth.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/executable.d.ts +3 -1
- package/dist/executable.d.ts.map +1 -1
- package/dist/executable.js +5 -4
- package/dist/executable.js.map +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +4 -0
- package/dist/hooks.js.map +1 -1
- package/node_modules/provider-asana/dist/asana-project.d.ts.map +1 -1
- package/node_modules/provider-asana/dist/asana-project.js +3 -0
- package/node_modules/provider-asana/dist/asana-project.js.map +1 -1
- package/node_modules/provider-asana/src/asana-project.ts +2 -0
- package/node_modules/provider-chatgpt/dist/chatgpt.d.ts.map +1 -1
- package/node_modules/provider-chatgpt/dist/chatgpt.js +2 -0
- package/node_modules/provider-chatgpt/dist/chatgpt.js.map +1 -1
- package/node_modules/provider-chatgpt/src/chatgpt.ts +1 -0
- package/node_modules/provider-gmail/dist/gmail.d.ts.map +1 -1
- package/node_modules/provider-gmail/dist/gmail.js +6 -2
- package/node_modules/provider-gmail/dist/gmail.js.map +1 -1
- package/node_modules/provider-gmail/src/gmail.ts +7 -2
- package/node_modules/provider-google-docs/dist/google-docs.d.ts.map +1 -1
- package/node_modules/provider-google-docs/dist/google-docs.js +370 -9
- package/node_modules/provider-google-docs/dist/google-docs.js.map +1 -1
- package/node_modules/provider-google-docs/dist/google-forms.d.ts +28 -0
- package/node_modules/provider-google-docs/dist/google-forms.d.ts.map +1 -0
- package/node_modules/provider-google-docs/dist/google-forms.js +191 -0
- package/node_modules/provider-google-docs/dist/google-forms.js.map +1 -0
- package/node_modules/provider-google-docs/dist/index.d.ts +26 -0
- package/node_modules/provider-google-docs/dist/index.d.ts.map +1 -1
- package/node_modules/provider-google-docs/dist/index.js +3 -1
- package/node_modules/provider-google-docs/dist/index.js.map +1 -1
- package/node_modules/provider-google-docs/src/google-docs.ts +339 -10
- package/node_modules/provider-google-docs/src/google-forms.ts +179 -0
- package/node_modules/provider-google-docs/src/index.ts +3 -1
- package/node_modules/provider-notion/dist/notion-sync.d.ts +1 -1
- package/node_modules/provider-notion/dist/notion-sync.d.ts.map +1 -1
- package/node_modules/provider-notion/dist/notion-sync.js +51 -29
- package/node_modules/provider-notion/dist/notion-sync.js.map +1 -1
- package/node_modules/provider-notion/src/notion-sync.ts +52 -26
- package/node_modules/provider-slack/dist/slack.d.ts.map +1 -1
- package/node_modules/provider-slack/dist/slack.js +14 -7
- package/node_modules/provider-slack/dist/slack.js.map +1 -1
- package/node_modules/provider-slack/src/slack.ts +14 -5
- package/node_modules/provider-zoom/dist/zoom-hub.d.ts.map +1 -1
- package/node_modules/provider-zoom/dist/zoom-hub.js +42 -35
- package/node_modules/provider-zoom/dist/zoom-hub.js.map +1 -1
- package/node_modules/provider-zoom/src/zoom-hub.ts +40 -35
- package/node_modules/wire-core/dist/core/model.d.ts +1 -1
- package/node_modules/wire-core/dist/core/model.d.ts.map +1 -1
- package/node_modules/wire-core/dist/index.d.ts +3 -2
- package/node_modules/wire-core/dist/index.d.ts.map +1 -1
- package/node_modules/wire-core/dist/index.js +2 -2
- package/node_modules/wire-core/dist/index.js.map +1 -1
- package/node_modules/wire-core/dist/operations.d.ts +3 -0
- package/node_modules/wire-core/dist/operations.d.ts.map +1 -1
- package/node_modules/wire-core/dist/operations.js +46 -7
- package/node_modules/wire-core/dist/operations.js.map +1 -1
- package/node_modules/wire-core/dist/ports.d.ts +1 -0
- package/node_modules/wire-core/dist/ports.d.ts.map +1 -1
- package/node_modules/wire-core/dist/runtime/chrome.d.ts.map +1 -1
- package/node_modules/wire-core/dist/runtime/chrome.js +27 -4
- package/node_modules/wire-core/dist/runtime/chrome.js.map +1 -1
- package/node_modules/wire-core/dist/runtime/cookies.d.ts.map +1 -1
- package/node_modules/wire-core/dist/runtime/cookies.js +7 -2
- package/node_modules/wire-core/dist/runtime/cookies.js.map +1 -1
- package/node_modules/wire-core/dist/runtime/node.d.ts.map +1 -1
- package/node_modules/wire-core/dist/runtime/node.js +4 -0
- package/node_modules/wire-core/dist/runtime/node.js.map +1 -1
- package/node_modules/wire-core/dist/storage/registry.d.ts.map +1 -1
- package/node_modules/wire-core/dist/storage/registry.js +95 -208
- package/node_modules/wire-core/dist/storage/registry.js.map +1 -1
- package/node_modules/wire-core/dist/storage/workspace.d.ts +3 -0
- package/node_modules/wire-core/dist/storage/workspace.d.ts.map +1 -1
- package/node_modules/wire-core/dist/storage/workspace.js +10 -1
- package/node_modules/wire-core/dist/storage/workspace.js.map +1 -1
- package/node_modules/wire-core/package.json +4 -0
- package/node_modules/wire-core/src/core/model.ts +1 -1
- package/node_modules/wire-core/src/index.ts +3 -2
- package/node_modules/wire-core/src/operations.ts +52 -8
- package/node_modules/wire-core/src/ports.ts +1 -0
- package/node_modules/wire-core/src/runtime/chrome.ts +30 -5
- package/node_modules/wire-core/src/runtime/cookies.ts +4 -2
- package/node_modules/wire-core/src/runtime/node.ts +4 -0
- package/node_modules/wire-core/src/storage/registry.ts +48 -15
- package/node_modules/wire-core/src/storage/workspace.ts +10 -1
- package/package.json +1 -1
- package/src/adapters/root.ts +51 -31
- package/src/auth.ts +7 -20
- package/src/cli.ts +2 -2
- package/src/executable.ts +5 -4
- package/src/hooks.ts +5 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/storage/workspace.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGjG,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/storage/workspace.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGjG,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5E,eAAO,MAAM,kBAAkB,UAAgC,CAAC;AAChE,eAAO,MAAM,uBAAuB,YAAY,CAAC;AAEjD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAInE;AAQD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWlF;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAI3F;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAE1E;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAOpF;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAgBvH;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAehG"}
|
|
@@ -3,6 +3,15 @@ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { stableJsonPretty } from "../core/json.js";
|
|
5
5
|
import { FileRegistry, SqliteRegistry } from "./registry.js";
|
|
6
|
+
export const defaultWireBackend = "files";
|
|
7
|
+
export const defaultWireRegistryPath = "records";
|
|
8
|
+
export function registryPathForBackend(backend) {
|
|
9
|
+
if (backend === "files")
|
|
10
|
+
return "records";
|
|
11
|
+
if (backend === "sqlite")
|
|
12
|
+
return "registry.sqlite3";
|
|
13
|
+
throw new Error(backend);
|
|
14
|
+
}
|
|
6
15
|
function canonicalPath(path) {
|
|
7
16
|
const resolved = resolve(path);
|
|
8
17
|
if (existsSync(resolved))
|
|
@@ -73,7 +82,7 @@ export async function switchWireBackend(path, home) {
|
|
|
73
82
|
const source = config.backend === "sqlite" ? new SqliteRegistry(fromPath) : new FileRegistry(fromPath);
|
|
74
83
|
const resources = await source.listResources();
|
|
75
84
|
const to = config.backend === "sqlite" ? "files" : "sqlite";
|
|
76
|
-
const targetRelativePath = to
|
|
85
|
+
const targetRelativePath = registryPathForBackend(to);
|
|
77
86
|
const toPath = join(wireRoot, targetRelativePath);
|
|
78
87
|
await rm(toPath, { recursive: true, force: true });
|
|
79
88
|
const target = to === "sqlite" ? new SqliteRegistry(toPath) : new FileRegistry(toPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/storage/workspace.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/storage/workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ResourceType = "document" | "email-thread" | "message-thread" | "project" | "spreadsheet" | "task" | "transcript";
|
|
1
|
+
export type ResourceType = "document" | "email-thread" | "form" | "message-thread" | "presentation" | "project" | "spreadsheet" | "task" | "transcript";
|
|
2
2
|
|
|
3
3
|
export type JsonPrimitive = boolean | null | number | string;
|
|
4
4
|
export type JsonObject = Readonly<{ [key: string]: JsonValue }>;
|
|
@@ -13,5 +13,6 @@ export { createGoogleTokensCapability, googleTokenExpired, mergeGoogleRefresh, p
|
|
|
13
13
|
export { composeNodeRuntime, createNodeClock, createNodeConfiguration, createNodeFilesystem, createNodeHttp, createNodeOpenFiles, createNodeProcess, createNodeRuntime, createNodeSecrets, createNodeWatch } from "./runtime/node.js";
|
|
14
14
|
export type { NodeEnvironment, NodeRuntimeDependencies } from "./runtime/node.js";
|
|
15
15
|
export { FileRegistry, SqliteRegistry } from "./storage/registry.js";
|
|
16
|
-
export { configuredWireRoot, discoverWireRoot, initializeWire, loadWireConfig, openWireRegistry, switchWireBackend, wireRelativePath } from "./storage/workspace.js";
|
|
17
|
-
export
|
|
16
|
+
export { configuredWireRoot, defaultWireBackend, defaultWireRegistryPath, discoverWireRoot, initializeWire, loadWireConfig, openWireRegistry, registryPathForBackend, switchWireBackend, wireRelativePath } from "./storage/workspace.js";
|
|
17
|
+
export { composeWire } from "./operations.js";
|
|
18
|
+
export type { Wire, WireAction, WireDependencies, WireFilesystem, WireResult, WireWatchSession } from "./operations.js";
|
|
@@ -55,6 +55,10 @@ export type WireWatchSession = Readonly<{
|
|
|
55
55
|
close(): void;
|
|
56
56
|
}>;
|
|
57
57
|
|
|
58
|
+
export type WireWatchSyncCommand = "sync" | "download";
|
|
59
|
+
export type WireWatchSyncHook = (command: WireWatchSyncCommand, result: WireResult) => Promise<WireResult>;
|
|
60
|
+
export const wireWatchHooks = Symbol("wireWatchHooks");
|
|
61
|
+
|
|
58
62
|
export type Wire = Readonly<{
|
|
59
63
|
attach(url: string, path: string): Promise<WireResult>;
|
|
60
64
|
create(url: string, path: string): Promise<WireResult>;
|
|
@@ -73,6 +77,10 @@ export type Wire = Readonly<{
|
|
|
73
77
|
switchBackend(path: string): Promise<SwitchedWireBackend>;
|
|
74
78
|
}>;
|
|
75
79
|
|
|
80
|
+
type WireInternal = Wire & Readonly<{
|
|
81
|
+
[wireWatchHooks](value: string, path: string, hooks: readonly WireWatchSyncHook[]): Promise<WireWatchSession>;
|
|
82
|
+
}>;
|
|
83
|
+
|
|
76
84
|
async function wireRoot<FetchInput>(dependencies: WireDependencies<FetchInput>, path: string): Promise<string> {
|
|
77
85
|
const configured = await dependencies.workspace.configuredRoot(path, dependencies.home);
|
|
78
86
|
if (configured !== null) return configured;
|
|
@@ -155,6 +163,15 @@ function relativePathContains(parent: string, child: string): boolean {
|
|
|
155
163
|
return parent === "" || child === parent || child.startsWith(`${parent}/`);
|
|
156
164
|
}
|
|
157
165
|
|
|
166
|
+
function relativePathEscapes(path: string): boolean {
|
|
167
|
+
return path === ".." || path.startsWith("../");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function serviceCanSynchronize<FetchInput>(url: string, catalog: ServiceCatalog<FetchInput>): boolean {
|
|
171
|
+
const parsed = new URL(url);
|
|
172
|
+
return catalog.find((service) => service.matches(parsed))!.synchronize !== undefined;
|
|
173
|
+
}
|
|
174
|
+
|
|
158
175
|
function errorMessage(error: unknown): string {
|
|
159
176
|
if (error instanceof Error) return error.message;
|
|
160
177
|
if (typeof error === "object" && error !== null && "message" in error && typeof error["message"] === "string") return error["message"];
|
|
@@ -177,6 +194,11 @@ export function composeWire<FetchInput>(dependencies: WireDependencies<FetchInpu
|
|
|
177
194
|
}
|
|
178
195
|
const relativePath = dependencies.workspace.relativePath(outputPath, root);
|
|
179
196
|
const previous = previousMarkdown === null ? await dependencies.filesystem.exists(outputPath) ? await dependencies.filesystem.readText(outputPath) : "" : previousMarkdown;
|
|
197
|
+
if (action === "attached" && current !== null) {
|
|
198
|
+
const snapshot = current.data.find((item) => item.namespace === source.service && item.key === "snapshot")!.value;
|
|
199
|
+
const baseMarkdown = markdownSnapshot(syncBase(source.service, snapshot, current.data));
|
|
200
|
+
if (baseMarkdown !== null && previous !== baseMarkdown) throw new Error(`Local edits exist for ${primaryLink(current).path}. Run \`wire sync ${primaryLink(current).path}\` before attaching this URL again.`);
|
|
201
|
+
}
|
|
180
202
|
await dependencies.filesystem.writeText(outputPath, fetched.markdown);
|
|
181
203
|
const id = resourceId(source);
|
|
182
204
|
const primary = current?.filesystem_links.find((link) => link.path === relativePath && link.role === "primary");
|
|
@@ -217,7 +239,14 @@ export function composeWire<FetchInput>(dependencies: WireDependencies<FetchInpu
|
|
|
217
239
|
const fetched = await fetchSource(dependencies.fetchInput, url, dependencies.catalog);
|
|
218
240
|
const source = parseSourceUrl(url, dependencies.catalog);
|
|
219
241
|
const cleanPath = join(resolve(path), markdownFilename(fetched.title));
|
|
220
|
-
|
|
242
|
+
let outputPath = cleanPath;
|
|
243
|
+
if (await dependencies.filesystem.exists(cleanPath)) {
|
|
244
|
+
const root = await dependencies.workspace.configuredRoot(cleanPath, dependencies.home);
|
|
245
|
+
const current = root === null ? null : await existingResource(await dependencies.workspace.openRegistry(root, dependencies.home), source.service, source.identifier);
|
|
246
|
+
const currentPrimaryPath = current === null ? null : join(dirname(root!), primaryLink(current).path);
|
|
247
|
+
const existingMarkdown = await dependencies.filesystem.readText(cleanPath);
|
|
248
|
+
if (currentPrimaryPath !== cleanPath && existingMarkdown !== fetched.markdown) outputPath = join(resolve(path), collisionFilename(fetched.title, source.service, source.identifier));
|
|
249
|
+
}
|
|
221
250
|
const previous = await dependencies.filesystem.exists(outputPath) ? await dependencies.filesystem.readText(outputPath) : "";
|
|
222
251
|
await dependencies.filesystem.writeText(outputPath, fetched.markdown);
|
|
223
252
|
const id = resourceId(source);
|
|
@@ -273,10 +302,12 @@ export function composeWire<FetchInput>(dependencies: WireDependencies<FetchInpu
|
|
|
273
302
|
const outputDirectory = dirname(outputPath);
|
|
274
303
|
const source = parseSourceUrl(resource.urls[0]!, dependencies.catalog);
|
|
275
304
|
const snapshot = resource.data.find((item) => item.namespace === source.service && item.key === "snapshot")!.value;
|
|
276
|
-
|
|
305
|
+
if (!(await dependencies.filesystem.exists(outputPath))) throw new Error(`Linked file missing: ${primaryLink(resource).path} - restore it or run wire detach`);
|
|
306
|
+
const markdown = await dependencies.filesystem.readText(outputPath);
|
|
277
307
|
const base = syncBase(source.service, snapshot, resource.data);
|
|
278
308
|
const baseMarkdown = markdownSnapshot(base);
|
|
279
309
|
const localChanged = baseMarkdown !== null && markdown !== baseMarkdown;
|
|
310
|
+
if (localChanged && !serviceCanSynchronize(resource.urls[0]!, dependencies.catalog)) throw new Error(`${source.service} is download-only and the local file has edits. Run \`wire download ${primaryLink(resource).path}\` to discard them.`);
|
|
280
311
|
const fetched = await synchronizeSource(dependencies.fetchInput, resource.urls[0]!, dependencies.catalog, base, markdown, outputPath);
|
|
281
312
|
const action = localChanged ? fetched.markdown === baseMarkdown ? "synced" : "uploaded" : fetched.markdown === markdown ? "synced" : "downloaded";
|
|
282
313
|
return store(resource.urls[0]!, outputDirectory, fetched, markdown, action, undefined, action === "uploaded" && baseMarkdown !== null ? baseMarkdown : undefined, action === "uploaded" ? markdown : fetched.markdown);
|
|
@@ -298,27 +329,36 @@ export function composeWire<FetchInput>(dependencies: WireDependencies<FetchInpu
|
|
|
298
329
|
const root = await existingWireRoot(dependencies, await dependencies.filesystem.exists(candidatePath) ? candidatePath : path);
|
|
299
330
|
const registry = await dependencies.workspace.openRegistry(root, dependencies.home);
|
|
300
331
|
const resource = await resolveResource(registry, value, root, path);
|
|
301
|
-
const
|
|
332
|
+
const outputPath = join(dirname(root), primaryLink(resource).path);
|
|
333
|
+
const previous = await dependencies.filesystem.exists(outputPath) ? await dependencies.filesystem.readText(outputPath) : "";
|
|
334
|
+
const fetched = await fetchSource(dependencies.fetchInput, resource.urls[0]!, dependencies.catalog);
|
|
335
|
+
await dependencies.filesystem.writeText(outputPath, fetched.markdown);
|
|
302
336
|
await registry.delete(resource.id);
|
|
303
|
-
return {
|
|
337
|
+
return { resource, path: outputPath, markdown: fetched.markdown, summary: { action: "detached", ...changeSummary(previous, fetched.markdown), remote: resource.urls[0]!, local: outputPath } };
|
|
304
338
|
};
|
|
305
339
|
const unlink = detach;
|
|
306
340
|
|
|
307
|
-
const
|
|
341
|
+
const runWatchHooks = async (hooks: readonly WireWatchSyncHook[], command: WireWatchSyncCommand, result: WireResult): Promise<WireResult> => {
|
|
342
|
+
let current = result;
|
|
343
|
+
for (const hook of hooks) current = await hook(command, current);
|
|
344
|
+
return current;
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const watchWithHooks = async (value: string, path: string, hooks: readonly WireWatchSyncHook[]): Promise<WireWatchSession> => {
|
|
308
348
|
const candidatePath = resolve(path, value);
|
|
309
349
|
const root = await existingWireRoot(dependencies, await dependencies.filesystem.exists(candidatePath) ? candidatePath : path);
|
|
310
350
|
const config = watchConfig(await dependencies.workspace.loadConfig!(root));
|
|
311
351
|
const registry = await dependencies.workspace.openRegistry(root, dependencies.home);
|
|
312
352
|
const resource = await resolveResource(registry, value, root, path);
|
|
313
353
|
const outputPath = join(dirname(root), primaryLink(resource).path);
|
|
314
|
-
const initial = await dependencies.filesystem.exists(outputPath) ? null : await download(value, path);
|
|
354
|
+
const initial = await dependencies.filesystem.exists(outputPath) ? null : await runWatchHooks(hooks, "download", await download(value, path));
|
|
315
355
|
let lastSyncedMarkdown = initial === null ? await dependencies.filesystem.readText(outputPath) : initial.markdown;
|
|
316
356
|
let debounce: ReturnType<typeof setTimeout> | undefined;
|
|
317
357
|
let resolveClosed!: () => void;
|
|
318
358
|
const closed = new Promise<void>((resolveClosedPromise) => { resolveClosed = resolveClosedPromise; });
|
|
319
359
|
const handles: WatchHandle[] = [];
|
|
320
360
|
const synchronize = async () => {
|
|
321
|
-
const result = config.mode === "download" ? await download(value, path) : await sync(value, path);
|
|
361
|
+
const result = config.mode === "download" ? await runWatchHooks(hooks, "download", await download(value, path)) : await runWatchHooks(hooks, "sync", await sync(value, path));
|
|
322
362
|
lastSyncedMarkdown = result.markdown;
|
|
323
363
|
};
|
|
324
364
|
const schedule = () => {
|
|
@@ -349,6 +389,8 @@ export function composeWire<FetchInput>(dependencies: WireDependencies<FetchInpu
|
|
|
349
389
|
});
|
|
350
390
|
};
|
|
351
391
|
|
|
392
|
+
const watch = (value: string, path: string): Promise<WireWatchSession> => watchWithHooks(value, path, []);
|
|
393
|
+
|
|
352
394
|
const openResource = async (value: string, path: string): Promise<Resource> => {
|
|
353
395
|
const candidatePath = resolve(path, value);
|
|
354
396
|
const root = await existingWireRoot(dependencies, await dependencies.filesystem.exists(candidatePath) ? candidatePath : path);
|
|
@@ -362,6 +404,7 @@ export function composeWire<FetchInput>(dependencies: WireDependencies<FetchInpu
|
|
|
362
404
|
const root = await existingWireRoot(dependencies, path);
|
|
363
405
|
const registry = await dependencies.workspace.openRegistry(root, dependencies.home);
|
|
364
406
|
const scope = dependencies.workspace.relativePath(path, root);
|
|
407
|
+
if (relativePathEscapes(scope)) throw new Error(`Sync scope is outside the Wire workspace: root ${dirname(root)}, path ${path}`);
|
|
365
408
|
const results: WireResult[] = [];
|
|
366
409
|
for (const resource of await registry.listResources()) {
|
|
367
410
|
const outputPath = join(dirname(root), primaryLink(resource).path);
|
|
@@ -404,5 +447,6 @@ export function composeWire<FetchInput>(dependencies: WireDependencies<FetchInpu
|
|
|
404
447
|
showResource,
|
|
405
448
|
init: dependencies.workspace.initialize,
|
|
406
449
|
switchBackend: (path: string) => dependencies.workspace.switchBackend!(path, dependencies.home),
|
|
407
|
-
|
|
450
|
+
[wireWatchHooks]: watchWithHooks,
|
|
451
|
+
}) as WireInternal;
|
|
408
452
|
}
|
|
@@ -23,6 +23,7 @@ export async function chromeLaunchArguments(environment: NodeEnvironment, startU
|
|
|
23
23
|
"--remote-debugging-port=0",
|
|
24
24
|
"--no-first-run",
|
|
25
25
|
"--no-default-browser-check",
|
|
26
|
+
"--restore-last-session",
|
|
26
27
|
startUrl,
|
|
27
28
|
]);
|
|
28
29
|
}
|
|
@@ -42,23 +43,39 @@ interface PendingRequest {
|
|
|
42
43
|
readonly reject: (reason: unknown) => void;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
interface PendingEvent {
|
|
47
|
+
readonly resolve: (value: Record<string, unknown>) => void;
|
|
48
|
+
readonly reject: (reason: unknown) => void;
|
|
49
|
+
}
|
|
50
|
+
|
|
45
51
|
class ChromeConnection {
|
|
46
52
|
readonly socket: WebSocket;
|
|
47
53
|
readonly pending = new Map<number, PendingRequest>();
|
|
48
|
-
readonly events = new Map<string,
|
|
54
|
+
readonly events = new Map<string, PendingEvent[]>();
|
|
49
55
|
nextId = 1;
|
|
56
|
+
closed = false;
|
|
50
57
|
|
|
51
58
|
constructor(url: string) {
|
|
52
59
|
this.socket = new WebSocket(url);
|
|
60
|
+
const rejectPending = () => {
|
|
61
|
+
this.closed = true;
|
|
62
|
+
const error = new Error("Chrome window closed before login completed");
|
|
63
|
+
for (const request of this.pending.values()) request.reject(error);
|
|
64
|
+
this.pending.clear();
|
|
65
|
+
for (const events of this.events.values()) for (const event of events) event.reject(error);
|
|
66
|
+
this.events.clear();
|
|
67
|
+
};
|
|
68
|
+
this.socket.addEventListener("close", rejectPending, { once: true });
|
|
69
|
+
this.socket.addEventListener("error", rejectPending, { once: true });
|
|
53
70
|
this.socket.addEventListener("message", (event) => {
|
|
54
71
|
const message = JSON.parse(event.data.toString()) as { id?: number; method?: string; params?: Record<string, unknown>; result?: unknown; error?: unknown };
|
|
55
72
|
if (message.id === undefined) {
|
|
56
73
|
if (message.method !== undefined) {
|
|
57
74
|
const events = this.events.get(message.method);
|
|
58
75
|
if (events !== undefined) {
|
|
59
|
-
const
|
|
76
|
+
const pending = events.shift()!;
|
|
60
77
|
if (events.length === 0) this.events.delete(message.method);
|
|
61
|
-
resolve(message.params!);
|
|
78
|
+
pending.resolve(message.params!);
|
|
62
79
|
}
|
|
63
80
|
}
|
|
64
81
|
return;
|
|
@@ -81,15 +98,23 @@ class ChromeConnection {
|
|
|
81
98
|
const id = this.nextId;
|
|
82
99
|
this.nextId += 1;
|
|
83
100
|
return new Promise((resolve, reject) => {
|
|
101
|
+
if (this.closed) {
|
|
102
|
+
reject(new Error("Chrome window closed before login completed"));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
84
105
|
this.pending.set(id, { resolve, reject });
|
|
85
106
|
this.socket.send(JSON.stringify({ id, method, params }));
|
|
86
107
|
});
|
|
87
108
|
}
|
|
88
109
|
|
|
89
110
|
event(method: string): Promise<Record<string, unknown>> {
|
|
90
|
-
return new Promise((resolve) => {
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
if (this.closed) {
|
|
113
|
+
reject(new Error("Chrome window closed before login completed"));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
91
116
|
const events = this.events.get(method) ?? [];
|
|
92
|
-
events.push(resolve);
|
|
117
|
+
events.push({ resolve, reject });
|
|
93
118
|
this.events.set(method, events);
|
|
94
119
|
});
|
|
95
120
|
}
|
|
@@ -191,8 +191,10 @@ export function createCookiesCapability(filesystem: FilesystemCapability, home:
|
|
|
191
191
|
},
|
|
192
192
|
save: async (service: string, cookies: readonly Cookie[], metadata: Readonly<Record<string, string>>) => {
|
|
193
193
|
const candidatePaths = paths(service);
|
|
194
|
-
const
|
|
195
|
-
|
|
194
|
+
const contents = serializeNetscapeCookies(cookies, metadata);
|
|
195
|
+
const existingPaths = [];
|
|
196
|
+
for (const path of candidatePaths) if (await filesystem.exists(path)) existingPaths.push(path);
|
|
197
|
+
for (const path of existingPaths.length === 0 ? [candidatePaths[0]!] : existingPaths) await filesystem.writeText(path, contents);
|
|
196
198
|
},
|
|
197
199
|
delete: async (service: string) => {
|
|
198
200
|
for (const path of paths(service)) if (await filesystem.exists(path)) await filesystem.delete(path);
|
|
@@ -100,6 +100,10 @@ export function composeNodeRuntime(dependencies: NodeRuntimeDependencies): Runti
|
|
|
100
100
|
load: () => createGoogleTokensCapability(dependencies.filesystem, dependencies.http, dependencies.clock, configuration.get("GOOGLE_CREDENTIALS_FILE"), configuration.get("GOOGLE_TOKEN_FILE")).load(),
|
|
101
101
|
refresh: () => createGoogleTokensCapability(dependencies.filesystem, dependencies.http, dependencies.clock, configuration.get("GOOGLE_CREDENTIALS_FILE"), configuration.get("GOOGLE_TOKEN_FILE")).refresh(),
|
|
102
102
|
}),
|
|
103
|
+
googleFormsTokens: Object.freeze({
|
|
104
|
+
load: () => createGoogleTokensCapability(dependencies.filesystem, dependencies.http, dependencies.clock, configuration.get("GOOGLE_CREDENTIALS_FILE"), configuration.get("GOOGLE_FORMS_TOKEN_FILE")).load(),
|
|
105
|
+
refresh: () => createGoogleTokensCapability(dependencies.filesystem, dependencies.http, dependencies.clock, configuration.get("GOOGLE_CREDENTIALS_FILE"), configuration.get("GOOGLE_FORMS_TOKEN_FILE")).refresh(),
|
|
106
|
+
}),
|
|
103
107
|
});
|
|
104
108
|
}
|
|
105
109
|
|
|
@@ -19,7 +19,7 @@ type ResourceIdRow = Readonly<{ resource_id: string }>;
|
|
|
19
19
|
type IdRow = Readonly<{ id: string }>;
|
|
20
20
|
type SqliteModule = Readonly<{ DatabaseSync: new (path: string) => DatabaseSync }>;
|
|
21
21
|
|
|
22
|
-
const require = createRequire(
|
|
22
|
+
const require = createRequire("/wire-core/storage/registry.js");
|
|
23
23
|
|
|
24
24
|
function compareStrings(left: string, right: string): number {
|
|
25
25
|
const leftCodePoints = Array.from(left, (character) => character.codePointAt(0)!);
|
|
@@ -77,7 +77,7 @@ export class SqliteRegistry implements Registry {
|
|
|
77
77
|
|
|
78
78
|
constructor(path: string) {
|
|
79
79
|
this.path = realpathSyncParent(path);
|
|
80
|
-
|
|
80
|
+
const database = this.connect();
|
|
81
81
|
database.exec(`
|
|
82
82
|
PRAGMA journal_mode=DELETE;
|
|
83
83
|
PRAGMA foreign_keys=ON;
|
|
@@ -121,11 +121,27 @@ export class SqliteRegistry implements Registry {
|
|
|
121
121
|
);
|
|
122
122
|
CREATE INDEX IF NOT EXISTS resource_relationships_target ON resource_relationships(target_id);
|
|
123
123
|
`);
|
|
124
|
+
database.close();
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
async put(resource: Resource): Promise<Resource> {
|
|
127
128
|
const normalized = storageResource(resource);
|
|
128
|
-
|
|
129
|
+
assertUniqueFileResource(normalized);
|
|
130
|
+
const database = this.connect();
|
|
131
|
+
for (const identifier of normalized.identifiers) {
|
|
132
|
+
const row = database.prepare("SELECT resource_id FROM resource_identifiers WHERE service = ? AND identifier = ? AND resource_id != ?").get(identifier.service, identifier.identifier, normalized.id) as ResourceIdRow | undefined;
|
|
133
|
+
if (row !== undefined) {
|
|
134
|
+
database.close();
|
|
135
|
+
throw new Error(`${identifier.service}/${identifier.identifier}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
for (const url of normalized.urls) {
|
|
139
|
+
const row = database.prepare("SELECT resource_id FROM resource_urls WHERE url = ? AND resource_id != ?").get(url, normalized.id) as ResourceIdRow | undefined;
|
|
140
|
+
if (row !== undefined) {
|
|
141
|
+
database.close();
|
|
142
|
+
throw new Error(url);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
129
145
|
database.exec("BEGIN");
|
|
130
146
|
database.prepare("INSERT INTO resources (id, type) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET type=excluded.type").run(normalized.id, normalized.type);
|
|
131
147
|
database.prepare("DELETE FROM resource_identifiers WHERE resource_id = ?").run(normalized.id);
|
|
@@ -144,58 +160,76 @@ export class SqliteRegistry implements Registry {
|
|
|
144
160
|
const insertRelationship = database.prepare("INSERT INTO resource_relationships (source_id, target_id, type, data_json) VALUES (?, ?, ?, ?)");
|
|
145
161
|
for (const relationship of normalized.relationships) insertRelationship.run(normalized.id, relationship.target_id, relationship.type, stableJsonCompact(relationship.data));
|
|
146
162
|
database.exec("COMMIT");
|
|
163
|
+
database.close();
|
|
147
164
|
return normalized;
|
|
148
165
|
}
|
|
149
166
|
|
|
150
167
|
async get(resourceId: string): Promise<Resource> {
|
|
151
|
-
|
|
168
|
+
const database = this.connect();
|
|
169
|
+
const row = database.prepare("SELECT id FROM resources WHERE id = ?").get(resourceId) as IdRow | undefined;
|
|
170
|
+
if (row === undefined) {
|
|
171
|
+
database.close();
|
|
172
|
+
throw missingResource(resourceId);
|
|
173
|
+
}
|
|
152
174
|
database.exec("BEGIN");
|
|
153
175
|
const resource = this.getResource(database, resourceId);
|
|
154
176
|
database.exec("COMMIT");
|
|
177
|
+
database.close();
|
|
155
178
|
return resource;
|
|
156
179
|
}
|
|
157
180
|
|
|
158
181
|
async findByIdentifier(service: string, identifier: string): Promise<Resource> {
|
|
159
|
-
|
|
182
|
+
const database = this.connect();
|
|
160
183
|
database.exec("BEGIN");
|
|
161
184
|
const row = database.prepare("SELECT resource_id FROM resource_identifiers WHERE service = ? AND identifier = ?").get(service, identifier) as ResourceIdRow | undefined;
|
|
162
|
-
if (row === undefined)
|
|
185
|
+
if (row === undefined) {
|
|
186
|
+
database.close();
|
|
187
|
+
throw missingIdentifier(service, identifier);
|
|
188
|
+
}
|
|
163
189
|
const resource = this.getResource(database, row.resource_id);
|
|
164
190
|
database.exec("COMMIT");
|
|
191
|
+
database.close();
|
|
165
192
|
return resource;
|
|
166
193
|
}
|
|
167
194
|
|
|
168
195
|
async findByUrl(url: string): Promise<Resource> {
|
|
169
|
-
|
|
196
|
+
const database = this.connect();
|
|
170
197
|
database.exec("BEGIN");
|
|
171
198
|
const row = database.prepare("SELECT resource_id FROM resource_urls WHERE url = ?").get(url) as ResourceIdRow | undefined;
|
|
172
|
-
if (row === undefined)
|
|
199
|
+
if (row === undefined) {
|
|
200
|
+
database.close();
|
|
201
|
+
throw missingUrl(url);
|
|
202
|
+
}
|
|
173
203
|
const resource = this.getResource(database, row.resource_id);
|
|
174
204
|
database.exec("COMMIT");
|
|
205
|
+
database.close();
|
|
175
206
|
return resource;
|
|
176
207
|
}
|
|
177
208
|
|
|
178
209
|
async findByPath(path: string): Promise<readonly Resource[]> {
|
|
179
|
-
|
|
210
|
+
const database = this.connect();
|
|
180
211
|
database.exec("BEGIN");
|
|
181
212
|
const rows = database.prepare("SELECT DISTINCT resource_id FROM filesystem_links WHERE path = ? ORDER BY resource_id").all(path.replaceAll(sep, "/")) as ResourceIdRow[];
|
|
182
213
|
const resources = rows.map((row) => this.getResource(database, row.resource_id));
|
|
183
214
|
database.exec("COMMIT");
|
|
215
|
+
database.close();
|
|
184
216
|
return resources;
|
|
185
217
|
}
|
|
186
218
|
|
|
187
219
|
async listResources(): Promise<readonly Resource[]> {
|
|
188
|
-
|
|
220
|
+
const database = this.connect();
|
|
189
221
|
database.exec("BEGIN");
|
|
190
222
|
const rows = database.prepare("SELECT id FROM resources ORDER BY id").all() as IdRow[];
|
|
191
223
|
const resources = rows.map((row) => this.getResource(database, row.id));
|
|
192
224
|
database.exec("COMMIT");
|
|
225
|
+
database.close();
|
|
193
226
|
return resources;
|
|
194
227
|
}
|
|
195
228
|
|
|
196
229
|
async delete(resourceId: string): Promise<void> {
|
|
197
|
-
|
|
230
|
+
const database = this.connect();
|
|
198
231
|
database.prepare("DELETE FROM resources WHERE id = ?").run(resourceId);
|
|
232
|
+
database.close();
|
|
199
233
|
}
|
|
200
234
|
|
|
201
235
|
private getResource(database: DatabaseSync, resourceId: string): Resource {
|
|
@@ -245,10 +279,9 @@ export class FileRegistry implements Registry {
|
|
|
245
279
|
if (existingUrls.has(url)) throw new Error(url);
|
|
246
280
|
}
|
|
247
281
|
const tempPath = join(this.path, randomUUID());
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
282
|
+
const handle = await open(tempPath, "wx", 0o600);
|
|
283
|
+
await handle.writeFile(`${stableJsonPretty(normalized)}\n`, "utf8");
|
|
284
|
+
await handle.close();
|
|
252
285
|
await rename(tempPath, this.resourcePath(normalized.id));
|
|
253
286
|
return normalized;
|
|
254
287
|
}
|
|
@@ -9,6 +9,15 @@ import { FileRegistry, SqliteRegistry } from "./registry.js";
|
|
|
9
9
|
|
|
10
10
|
export type { InitializedWire, WireBackend, WireConfig } from "../ports.js";
|
|
11
11
|
|
|
12
|
+
export const defaultWireBackend = "files" satisfies WireBackend;
|
|
13
|
+
export const defaultWireRegistryPath = "records";
|
|
14
|
+
|
|
15
|
+
export function registryPathForBackend(backend: WireBackend): string {
|
|
16
|
+
if (backend === "files") return "records";
|
|
17
|
+
if (backend === "sqlite") return "registry.sqlite3";
|
|
18
|
+
throw new Error(backend);
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
function canonicalPath(path: string): string {
|
|
13
22
|
const resolved = resolve(path);
|
|
14
23
|
if (existsSync(resolved)) return realpathSync(resolved);
|
|
@@ -76,7 +85,7 @@ export async function switchWireBackend(path: string, home: string): Promise<Swi
|
|
|
76
85
|
const source = config.backend === "sqlite" ? new SqliteRegistry(fromPath) : new FileRegistry(fromPath);
|
|
77
86
|
const resources = await source.listResources();
|
|
78
87
|
const to = config.backend === "sqlite" ? "files" : "sqlite";
|
|
79
|
-
const targetRelativePath = to
|
|
88
|
+
const targetRelativePath = registryPathForBackend(to);
|
|
80
89
|
const toPath = join(wireRoot, targetRelativePath);
|
|
81
90
|
await rm(toPath, { recursive: true, force: true });
|
|
82
91
|
const target = to === "sqlite" ? new SqliteRegistry(toPath) : new FileRegistry(toPath);
|