@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.
Files changed (101) hide show
  1. package/README.md +1 -1
  2. package/bin/wire-mcp.mjs +1 -1
  3. package/dist/adapters/root.d.ts +5 -2
  4. package/dist/adapters/root.d.ts.map +1 -1
  5. package/dist/adapters/root.js +58 -30
  6. package/dist/adapters/root.js.map +1 -1
  7. package/dist/auth.d.ts.map +1 -1
  8. package/dist/auth.js +6 -26
  9. package/dist/auth.js.map +1 -1
  10. package/dist/cli.js +2 -2
  11. package/dist/cli.js.map +1 -1
  12. package/dist/executable.d.ts +3 -1
  13. package/dist/executable.d.ts.map +1 -1
  14. package/dist/executable.js +5 -4
  15. package/dist/executable.js.map +1 -1
  16. package/dist/hooks.d.ts.map +1 -1
  17. package/dist/hooks.js +4 -0
  18. package/dist/hooks.js.map +1 -1
  19. package/node_modules/provider-asana/dist/asana-project.d.ts.map +1 -1
  20. package/node_modules/provider-asana/dist/asana-project.js +3 -0
  21. package/node_modules/provider-asana/dist/asana-project.js.map +1 -1
  22. package/node_modules/provider-asana/src/asana-project.ts +2 -0
  23. package/node_modules/provider-chatgpt/dist/chatgpt.d.ts.map +1 -1
  24. package/node_modules/provider-chatgpt/dist/chatgpt.js +2 -0
  25. package/node_modules/provider-chatgpt/dist/chatgpt.js.map +1 -1
  26. package/node_modules/provider-chatgpt/src/chatgpt.ts +1 -0
  27. package/node_modules/provider-gmail/dist/gmail.d.ts.map +1 -1
  28. package/node_modules/provider-gmail/dist/gmail.js +6 -2
  29. package/node_modules/provider-gmail/dist/gmail.js.map +1 -1
  30. package/node_modules/provider-gmail/src/gmail.ts +7 -2
  31. package/node_modules/provider-google-docs/dist/google-docs.d.ts.map +1 -1
  32. package/node_modules/provider-google-docs/dist/google-docs.js +370 -9
  33. package/node_modules/provider-google-docs/dist/google-docs.js.map +1 -1
  34. package/node_modules/provider-google-docs/dist/google-forms.d.ts +28 -0
  35. package/node_modules/provider-google-docs/dist/google-forms.d.ts.map +1 -0
  36. package/node_modules/provider-google-docs/dist/google-forms.js +191 -0
  37. package/node_modules/provider-google-docs/dist/google-forms.js.map +1 -0
  38. package/node_modules/provider-google-docs/dist/index.d.ts +26 -0
  39. package/node_modules/provider-google-docs/dist/index.d.ts.map +1 -1
  40. package/node_modules/provider-google-docs/dist/index.js +3 -1
  41. package/node_modules/provider-google-docs/dist/index.js.map +1 -1
  42. package/node_modules/provider-google-docs/src/google-docs.ts +339 -10
  43. package/node_modules/provider-google-docs/src/google-forms.ts +179 -0
  44. package/node_modules/provider-google-docs/src/index.ts +3 -1
  45. package/node_modules/provider-notion/dist/notion-sync.d.ts +1 -1
  46. package/node_modules/provider-notion/dist/notion-sync.d.ts.map +1 -1
  47. package/node_modules/provider-notion/dist/notion-sync.js +51 -29
  48. package/node_modules/provider-notion/dist/notion-sync.js.map +1 -1
  49. package/node_modules/provider-notion/src/notion-sync.ts +52 -26
  50. package/node_modules/provider-slack/dist/slack.d.ts.map +1 -1
  51. package/node_modules/provider-slack/dist/slack.js +14 -7
  52. package/node_modules/provider-slack/dist/slack.js.map +1 -1
  53. package/node_modules/provider-slack/src/slack.ts +14 -5
  54. package/node_modules/provider-zoom/dist/zoom-hub.d.ts.map +1 -1
  55. package/node_modules/provider-zoom/dist/zoom-hub.js +42 -35
  56. package/node_modules/provider-zoom/dist/zoom-hub.js.map +1 -1
  57. package/node_modules/provider-zoom/src/zoom-hub.ts +40 -35
  58. package/node_modules/wire-core/dist/core/model.d.ts +1 -1
  59. package/node_modules/wire-core/dist/core/model.d.ts.map +1 -1
  60. package/node_modules/wire-core/dist/index.d.ts +3 -2
  61. package/node_modules/wire-core/dist/index.d.ts.map +1 -1
  62. package/node_modules/wire-core/dist/index.js +2 -2
  63. package/node_modules/wire-core/dist/index.js.map +1 -1
  64. package/node_modules/wire-core/dist/operations.d.ts +3 -0
  65. package/node_modules/wire-core/dist/operations.d.ts.map +1 -1
  66. package/node_modules/wire-core/dist/operations.js +46 -7
  67. package/node_modules/wire-core/dist/operations.js.map +1 -1
  68. package/node_modules/wire-core/dist/ports.d.ts +1 -0
  69. package/node_modules/wire-core/dist/ports.d.ts.map +1 -1
  70. package/node_modules/wire-core/dist/runtime/chrome.d.ts.map +1 -1
  71. package/node_modules/wire-core/dist/runtime/chrome.js +27 -4
  72. package/node_modules/wire-core/dist/runtime/chrome.js.map +1 -1
  73. package/node_modules/wire-core/dist/runtime/cookies.d.ts.map +1 -1
  74. package/node_modules/wire-core/dist/runtime/cookies.js +7 -2
  75. package/node_modules/wire-core/dist/runtime/cookies.js.map +1 -1
  76. package/node_modules/wire-core/dist/runtime/node.d.ts.map +1 -1
  77. package/node_modules/wire-core/dist/runtime/node.js +4 -0
  78. package/node_modules/wire-core/dist/runtime/node.js.map +1 -1
  79. package/node_modules/wire-core/dist/storage/registry.d.ts.map +1 -1
  80. package/node_modules/wire-core/dist/storage/registry.js +95 -208
  81. package/node_modules/wire-core/dist/storage/registry.js.map +1 -1
  82. package/node_modules/wire-core/dist/storage/workspace.d.ts +3 -0
  83. package/node_modules/wire-core/dist/storage/workspace.d.ts.map +1 -1
  84. package/node_modules/wire-core/dist/storage/workspace.js +10 -1
  85. package/node_modules/wire-core/dist/storage/workspace.js.map +1 -1
  86. package/node_modules/wire-core/package.json +4 -0
  87. package/node_modules/wire-core/src/core/model.ts +1 -1
  88. package/node_modules/wire-core/src/index.ts +3 -2
  89. package/node_modules/wire-core/src/operations.ts +52 -8
  90. package/node_modules/wire-core/src/ports.ts +1 -0
  91. package/node_modules/wire-core/src/runtime/chrome.ts +30 -5
  92. package/node_modules/wire-core/src/runtime/cookies.ts +4 -2
  93. package/node_modules/wire-core/src/runtime/node.ts +4 -0
  94. package/node_modules/wire-core/src/storage/registry.ts +48 -15
  95. package/node_modules/wire-core/src/storage/workspace.ts +10 -1
  96. package/package.json +1 -1
  97. package/src/adapters/root.ts +51 -31
  98. package/src/auth.ts +7 -20
  99. package/src/cli.ts +2 -2
  100. package/src/executable.ts +5 -4
  101. 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;AAQ5E,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"}
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 === "sqlite" ? "registry.sqlite3" : "records";
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":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAE5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAI7D,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxD,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,IAAY;IAC/D,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE;QAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACzG,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,QAAQ,CAAC;QAC9E,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,UAAU,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/D,WAAW,GAAG,UAAU,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAY,EAAE,IAAY;IACjE,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACjD,OAAO,UAAU,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,QAAgB;IAC7D,OAAO,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IACnD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAe,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,IAAY;IAC/D,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,MAAM,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,cAAc,CAAC,YAAY,CAAC,CAAC;IACzE,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO;QAAE,OAAO,IAAI,YAAY,CAAC,YAAY,CAAC,CAAC;IACtE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY,EAAE,OAAoB,EAAE,YAAoB;IAC3F,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACjD,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5D,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QAChD,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,QAAQ,CAAC,OAAO,gBAAgB,QAAQ,CAAC,IAAI,4CAA4C,CAAC,CAAC;QAC1N,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5G,CAAC;IACD,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAuB,CAAC;IACpE,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrE,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACtD,IAAI,OAAO,KAAK,QAAQ;QAAE,IAAI,cAAc,CAAC,gBAAgB,CAAC,CAAC;SAC1D,IAAI,OAAO,KAAK,OAAO;QAAE,IAAI,YAAY,CAAC,gBAAgB,CAAC,CAAC;;QAC5D,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY,EAAE,IAAY;IAChE,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvG,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;IAC/C,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC5D,MAAM,kBAAkB,GAAG,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IAClD,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACvF,KAAK,MAAM,QAAQ,IAAI,SAAS;QAAE,MAAM,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7D,MAAM,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,GAAG,gBAAgB,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtI,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC;AACrG,CAAC"}
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/storage/workspace.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,10 @@
10
10
  "./runtime/cookies": {
11
11
  "types": "./dist/runtime/cookies.d.ts",
12
12
  "import": "./dist/runtime/cookies.js"
13
+ },
14
+ "./internal/operations": {
15
+ "types": "./dist/operations.d.ts",
16
+ "import": "./dist/operations.js"
13
17
  }
14
18
  },
15
19
  "files": [
@@ -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 * from "./operations.js";
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
- const outputPath = await dependencies.filesystem.exists(cleanPath) ? join(resolve(path), collisionFilename(fetched.title, source.service, source.identifier)) : cleanPath;
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
- const markdown = await dependencies.filesystem.exists(outputPath) ? await dependencies.filesystem.readText(outputPath) : "";
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 result = await download(value, path);
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 { ...result, summary: { ...result.summary, action: "detached" } };
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 watch = async (value: string, path: string): Promise<WireWatchSession> => {
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
  }
@@ -134,4 +134,5 @@ export interface RuntimeCapabilities {
134
134
  readonly secrets: SecretsCapability;
135
135
  readonly cookies: CookiesCapability;
136
136
  readonly gmailTokens: GoogleTokensCapability;
137
+ readonly googleFormsTokens: GoogleTokensCapability;
137
138
  }
@@ -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, Array<(value: Record<string, unknown>) => void>>();
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 resolve = events.shift()!;
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 path = await existingCookiesFile(filesystem, candidatePaths) ?? candidatePaths[0]!;
195
- await filesystem.writeText(path, serializeNetscapeCookies(cookies, metadata));
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(import.meta.url);
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
- using database = this.connect();
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
- using database = this.connect();
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
- using database = this.connect();
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
- using database = this.connect();
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) throw missingIdentifier(service, identifier);
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
- using database = this.connect();
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) throw missingUrl(url);
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
- using database = this.connect();
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
- using database = this.connect();
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
- using database = this.connect();
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
- await using handle = await open(tempPath, "wx", 0o600);
250
- await handle.writeFile(`${stableJsonPretty(normalized)}\n`, "utf8");
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 === "sqlite" ? "registry.sqlite3" : "records";
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kamilio/wire",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Attach Notion, Google Docs, Slack, Gmail, Asana, ChatGPT, and Zoom resources as local Markdown you can sync.",
5
5
  "keywords": [
6
6
  "markdown",