@interop/was-react 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.
Files changed (223) hide show
  1. package/LICENSE.md +20 -0
  2. package/README.md +410 -0
  3. package/dist/auth/chapi.d.ts +43 -0
  4. package/dist/auth/chapi.d.ts.map +1 -0
  5. package/dist/auth/chapi.js +107 -0
  6. package/dist/auth/chapi.js.map +1 -0
  7. package/dist/auth/loginFlow.d.ts +93 -0
  8. package/dist/auth/loginFlow.d.ts.map +1 -0
  9. package/dist/auth/loginFlow.js +149 -0
  10. package/dist/auth/loginFlow.js.map +1 -0
  11. package/dist/auth/loginRequest.d.ts +66 -0
  12. package/dist/auth/loginRequest.d.ts.map +1 -0
  13. package/dist/auth/loginRequest.js +83 -0
  14. package/dist/auth/loginRequest.js.map +1 -0
  15. package/dist/auth/verifyResponse.d.ts +52 -0
  16. package/dist/auth/verifyResponse.d.ts.map +1 -0
  17. package/dist/auth/verifyResponse.js +138 -0
  18. package/dist/auth/verifyResponse.js.map +1 -0
  19. package/dist/auth/verifyResponse.test.d.ts +2 -0
  20. package/dist/auth/verifyResponse.test.d.ts.map +1 -0
  21. package/dist/auth/verifyResponse.test.js +282 -0
  22. package/dist/auth/verifyResponse.test.js.map +1 -0
  23. package/dist/auth/walletRequestTypes.d.ts +143 -0
  24. package/dist/auth/walletRequestTypes.d.ts.map +1 -0
  25. package/dist/auth/walletRequestTypes.js +2 -0
  26. package/dist/auth/walletRequestTypes.js.map +1 -0
  27. package/dist/config.d.ts +150 -0
  28. package/dist/config.d.ts.map +1 -0
  29. package/dist/config.js +27 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/dev/cli.d.ts +16 -0
  32. package/dist/dev/cli.d.ts.map +1 -0
  33. package/dist/dev/cli.js +122 -0
  34. package/dist/dev/cli.js.map +1 -0
  35. package/dist/dev/cli.test.d.ts +2 -0
  36. package/dist/dev/cli.test.d.ts.map +1 -0
  37. package/dist/dev/cli.test.js +39 -0
  38. package/dist/dev/cli.test.js.map +1 -0
  39. package/dist/dev/index.d.ts +10 -0
  40. package/dist/dev/index.d.ts.map +1 -0
  41. package/dist/dev/index.js +10 -0
  42. package/dist/dev/index.js.map +1 -0
  43. package/dist/dev/provisionDevGrants.d.ts +73 -0
  44. package/dist/dev/provisionDevGrants.d.ts.map +1 -0
  45. package/dist/dev/provisionDevGrants.js +176 -0
  46. package/dist/dev/provisionDevGrants.js.map +1 -0
  47. package/dist/grants.d.ts +59 -0
  48. package/dist/grants.d.ts.map +1 -0
  49. package/dist/grants.js +82 -0
  50. package/dist/grants.js.map +1 -0
  51. package/dist/grants.test.d.ts +2 -0
  52. package/dist/grants.test.d.ts.map +1 -0
  53. package/dist/grants.test.js +79 -0
  54. package/dist/grants.test.js.map +1 -0
  55. package/dist/identity/agents.d.ts +99 -0
  56. package/dist/identity/agents.d.ts.map +1 -0
  57. package/dist/identity/agents.js +132 -0
  58. package/dist/identity/agents.js.map +1 -0
  59. package/dist/identity/appSession.d.ts +78 -0
  60. package/dist/identity/appSession.d.ts.map +1 -0
  61. package/dist/identity/appSession.js +93 -0
  62. package/dist/identity/appSession.js.map +1 -0
  63. package/dist/identity/documentLoader.d.ts +20 -0
  64. package/dist/identity/documentLoader.d.ts.map +1 -0
  65. package/dist/identity/documentLoader.js +99 -0
  66. package/dist/identity/documentLoader.js.map +1 -0
  67. package/dist/identity/initAppSession.d.ts +27 -0
  68. package/dist/identity/initAppSession.d.ts.map +1 -0
  69. package/dist/identity/initAppSession.js +30 -0
  70. package/dist/identity/initAppSession.js.map +1 -0
  71. package/dist/identity/seedCredential.d.ts +74 -0
  72. package/dist/identity/seedCredential.d.ts.map +1 -0
  73. package/dist/identity/seedCredential.js +165 -0
  74. package/dist/identity/seedCredential.js.map +1 -0
  75. package/dist/identity/seedCredential.test.d.ts +2 -0
  76. package/dist/identity/seedCredential.test.d.ts.map +1 -0
  77. package/dist/identity/seedCredential.test.js +205 -0
  78. package/dist/identity/seedCredential.test.js.map +1 -0
  79. package/dist/identity/seedStore.d.ts +27 -0
  80. package/dist/identity/seedStore.d.ts.map +1 -0
  81. package/dist/identity/seedStore.js +74 -0
  82. package/dist/identity/seedStore.js.map +1 -0
  83. package/dist/index.d.ts +37 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +46 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/mui/ProtectedRoute.d.ts +10 -0
  88. package/dist/mui/ProtectedRoute.d.ts.map +1 -0
  89. package/dist/mui/ProtectedRoute.js +54 -0
  90. package/dist/mui/ProtectedRoute.js.map +1 -0
  91. package/dist/mui/ReconnectBanner.d.ts +2 -0
  92. package/dist/mui/ReconnectBanner.d.ts.map +1 -0
  93. package/dist/mui/ReconnectBanner.js +20 -0
  94. package/dist/mui/ReconnectBanner.js.map +1 -0
  95. package/dist/mui/SyncStatusChip.d.ts +2 -0
  96. package/dist/mui/SyncStatusChip.d.ts.map +1 -0
  97. package/dist/mui/SyncStatusChip.js +27 -0
  98. package/dist/mui/SyncStatusChip.js.map +1 -0
  99. package/dist/mui/index.d.ts +12 -0
  100. package/dist/mui/index.d.ts.map +1 -0
  101. package/dist/mui/index.js +12 -0
  102. package/dist/mui/index.js.map +1 -0
  103. package/dist/react/WasSessionProvider.d.ts +36 -0
  104. package/dist/react/WasSessionProvider.d.ts.map +1 -0
  105. package/dist/react/WasSessionProvider.js +35 -0
  106. package/dist/react/WasSessionProvider.js.map +1 -0
  107. package/dist/react/hooks.d.ts +66 -0
  108. package/dist/react/hooks.d.ts.map +1 -0
  109. package/dist/react/hooks.js +121 -0
  110. package/dist/react/hooks.js.map +1 -0
  111. package/dist/react/index.d.ts +11 -0
  112. package/dist/react/index.d.ts.map +1 -0
  113. package/dist/react/index.js +11 -0
  114. package/dist/react/index.js.map +1 -0
  115. package/dist/session/appReadyStore.d.ts +10 -0
  116. package/dist/session/appReadyStore.d.ts.map +1 -0
  117. package/dist/session/appReadyStore.js +22 -0
  118. package/dist/session/appReadyStore.js.map +1 -0
  119. package/dist/session/authStore.d.ts +71 -0
  120. package/dist/session/authStore.d.ts.map +1 -0
  121. package/dist/session/authStore.js +347 -0
  122. package/dist/session/authStore.js.map +1 -0
  123. package/dist/session/index.d.ts +10 -0
  124. package/dist/session/index.d.ts.map +1 -0
  125. package/dist/session/index.js +10 -0
  126. package/dist/session/index.js.map +1 -0
  127. package/dist/storage/entityStore.d.ts +51 -0
  128. package/dist/storage/entityStore.d.ts.map +1 -0
  129. package/dist/storage/entityStore.js +78 -0
  130. package/dist/storage/entityStore.js.map +1 -0
  131. package/dist/storage/localStore.d.ts +144 -0
  132. package/dist/storage/localStore.d.ts.map +1 -0
  133. package/dist/storage/localStore.js +289 -0
  134. package/dist/storage/localStore.js.map +1 -0
  135. package/dist/storage/rehydrate.d.ts +56 -0
  136. package/dist/storage/rehydrate.d.ts.map +1 -0
  137. package/dist/storage/rehydrate.js +87 -0
  138. package/dist/storage/rehydrate.js.map +1 -0
  139. package/dist/storage/rehydrate.test.d.ts +2 -0
  140. package/dist/storage/rehydrate.test.d.ts.map +1 -0
  141. package/dist/storage/rehydrate.test.js +172 -0
  142. package/dist/storage/rehydrate.test.js.map +1 -0
  143. package/dist/storage/storageManager.d.ts +39 -0
  144. package/dist/storage/storageManager.d.ts.map +1 -0
  145. package/dist/storage/storageManager.js +68 -0
  146. package/dist/storage/storageManager.js.map +1 -0
  147. package/dist/storage/syncController.d.ts +79 -0
  148. package/dist/storage/syncController.d.ts.map +1 -0
  149. package/dist/storage/syncController.js +189 -0
  150. package/dist/storage/syncController.js.map +1 -0
  151. package/dist/storage/syncStatusStore.d.ts +17 -0
  152. package/dist/storage/syncStatusStore.d.ts.map +1 -0
  153. package/dist/storage/syncStatusStore.js +19 -0
  154. package/dist/storage/syncStatusStore.js.map +1 -0
  155. package/dist/storage/wasRemoteStore.d.ts +73 -0
  156. package/dist/storage/wasRemoteStore.d.ts.map +1 -0
  157. package/dist/storage/wasRemoteStore.js +76 -0
  158. package/dist/storage/wasRemoteStore.js.map +1 -0
  159. package/dist/storage/wasSync.d.ts +42 -0
  160. package/dist/storage/wasSync.d.ts.map +1 -0
  161. package/dist/storage/wasSync.js +34 -0
  162. package/dist/storage/wasSync.js.map +1 -0
  163. package/dist/sync/changesQuery.d.ts +44 -0
  164. package/dist/sync/changesQuery.d.ts.map +1 -0
  165. package/dist/sync/changesQuery.js +61 -0
  166. package/dist/sync/changesQuery.js.map +1 -0
  167. package/dist/sync/changesQuery.test.d.ts +2 -0
  168. package/dist/sync/changesQuery.test.d.ts.map +1 -0
  169. package/dist/sync/changesQuery.test.js +145 -0
  170. package/dist/sync/changesQuery.test.js.map +1 -0
  171. package/dist/sync/docCipher.d.ts +68 -0
  172. package/dist/sync/docCipher.d.ts.map +1 -0
  173. package/dist/sync/docCipher.js +89 -0
  174. package/dist/sync/docCipher.js.map +1 -0
  175. package/dist/sync/feedMasterPort.d.ts +30 -0
  176. package/dist/sync/feedMasterPort.d.ts.map +1 -0
  177. package/dist/sync/feedMasterPort.js +58 -0
  178. package/dist/sync/feedMasterPort.js.map +1 -0
  179. package/dist/sync/index.d.ts +21 -0
  180. package/dist/sync/index.d.ts.map +1 -0
  181. package/dist/sync/index.js +21 -0
  182. package/dist/sync/index.js.map +1 -0
  183. package/dist/sync/lww.d.ts +29 -0
  184. package/dist/sync/lww.d.ts.map +1 -0
  185. package/dist/sync/lww.js +28 -0
  186. package/dist/sync/lww.js.map +1 -0
  187. package/dist/sync/lww.test.d.ts +2 -0
  188. package/dist/sync/lww.test.d.ts.map +1 -0
  189. package/dist/sync/lww.test.js +28 -0
  190. package/dist/sync/lww.test.js.map +1 -0
  191. package/dist/sync/lwwConflictHandler.d.ts +49 -0
  192. package/dist/sync/lwwConflictHandler.d.ts.map +1 -0
  193. package/dist/sync/lwwConflictHandler.js +65 -0
  194. package/dist/sync/lwwConflictHandler.js.map +1 -0
  195. package/dist/sync/lwwConflictHandler.test.d.ts +2 -0
  196. package/dist/sync/lwwConflictHandler.test.d.ts.map +1 -0
  197. package/dist/sync/lwwConflictHandler.test.js +78 -0
  198. package/dist/sync/lwwConflictHandler.test.js.map +1 -0
  199. package/dist/sync/pushWrites.d.ts +57 -0
  200. package/dist/sync/pushWrites.d.ts.map +1 -0
  201. package/dist/sync/pushWrites.js +159 -0
  202. package/dist/sync/pushWrites.js.map +1 -0
  203. package/dist/sync/pushWrites.test.d.ts +2 -0
  204. package/dist/sync/pushWrites.test.d.ts.map +1 -0
  205. package/dist/sync/pushWrites.test.js +287 -0
  206. package/dist/sync/pushWrites.test.js.map +1 -0
  207. package/dist/sync/syncedDocSchema.d.ts +22 -0
  208. package/dist/sync/syncedDocSchema.d.ts.map +1 -0
  209. package/dist/sync/syncedDocSchema.js +26 -0
  210. package/dist/sync/syncedDocSchema.js.map +1 -0
  211. package/dist/sync/types.d.ts +194 -0
  212. package/dist/sync/types.d.ts.map +1 -0
  213. package/dist/sync/types.js +36 -0
  214. package/dist/sync/types.js.map +1 -0
  215. package/dist/sync/wasReplication.d.ts +47 -0
  216. package/dist/sync/wasReplication.d.ts.map +1 -0
  217. package/dist/sync/wasReplication.js +55 -0
  218. package/dist/sync/wasReplication.js.map +1 -0
  219. package/dist/sync/wasSyncPort.d.ts +45 -0
  220. package/dist/sync/wasSyncPort.d.ts.map +1 -0
  221. package/dist/sync/wasSyncPort.js +170 -0
  222. package/dist/sync/wasSyncPort.js.map +1 -0
  223. package/package.json +142 -0
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ /*!
3
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
4
+ */
5
+ /**
6
+ * CLI wrapper around `provisionDevGrants`. Creates a dev Space + collections on a
7
+ * running was-teaching-server and delegates per-collection RW zcaps to the app
8
+ * DID derived from `--seed`, optionally writing the grants JSON to `--out`.
9
+ *
10
+ * Usage:
11
+ * was-provision-dev-grants \
12
+ * --server-url http://localhost:3002 \
13
+ * --seed <hex-or-base64url 32-byte seed> \
14
+ * --collections action-items,projects,goals \
15
+ * [--space-name "Dev Space"] [--out ./public/dev-grants.local.json] [--probe]
16
+ */
17
+ import { parseArgs } from 'node:util';
18
+ import { argv } from 'node:process';
19
+ import { pathToFileURL } from 'node:url';
20
+ import { provisionDevGrants } from './provisionDevGrants.js';
21
+ const USAGE = `Usage: was-provision-dev-grants [options]
22
+
23
+ Required:
24
+ --server-url <url> base URL of a running was-teaching-server
25
+ --seed <string> the app master seed, hex or base64url encoded
26
+ --collections <ids> comma-separated WAS collection ids
27
+
28
+ Optional:
29
+ --space-name <name> Space name (default "Dev Space")
30
+ --out <path> write the { grants } JSON to this file
31
+ --probe probe whether the delegated RW zcap authorizes the
32
+ encryption-marker PUT
33
+ --help show this message
34
+ `;
35
+ /**
36
+ * Decodes a seed string as hex (all hex chars, even length) or base64url.
37
+ *
38
+ * @param input {string}
39
+ * @returns {Uint8Array}
40
+ */
41
+ export function parseSeed(input) {
42
+ const value = input.trim();
43
+ if (/^[0-9a-fA-F]+$/.test(value) && value.length % 2 === 0) {
44
+ const bytes = new Uint8Array(value.length / 2);
45
+ for (let index = 0; index < bytes.length; index++) {
46
+ bytes[index] = parseInt(value.slice(index * 2, index * 2 + 2), 16);
47
+ }
48
+ return bytes;
49
+ }
50
+ const base64 = value.replace(/-/g, '+').replace(/_/g, '/');
51
+ return new Uint8Array(Buffer.from(base64, 'base64'));
52
+ }
53
+ /**
54
+ * Splits a comma-separated collection-ids string into a trimmed, non-empty list.
55
+ *
56
+ * @param input {string}
57
+ * @returns {string[]}
58
+ */
59
+ export function parseCollections(input) {
60
+ return input
61
+ .split(',')
62
+ .map(id => id.trim())
63
+ .filter(id => id.length > 0);
64
+ }
65
+ async function main() {
66
+ const { values } = parseArgs({
67
+ options: {
68
+ 'server-url': { type: 'string' },
69
+ seed: { type: 'string' },
70
+ collections: { type: 'string' },
71
+ 'space-name': { type: 'string' },
72
+ out: { type: 'string' },
73
+ probe: { type: 'boolean', default: false },
74
+ help: { type: 'boolean', default: false }
75
+ }
76
+ });
77
+ if (values.help) {
78
+ console.log(USAGE);
79
+ return;
80
+ }
81
+ const serverUrl = values['server-url'];
82
+ const seedInput = values.seed;
83
+ const collectionsInput = values.collections;
84
+ const missing = [];
85
+ if (!serverUrl) {
86
+ missing.push('--server-url');
87
+ }
88
+ if (!seedInput) {
89
+ missing.push('--seed');
90
+ }
91
+ if (!collectionsInput) {
92
+ missing.push('--collections');
93
+ }
94
+ if (missing.length > 0) {
95
+ console.error(`Missing required argument(s): ${missing.join(', ')}\n`);
96
+ console.error(USAGE);
97
+ process.exit(1);
98
+ }
99
+ const collections = parseCollections(collectionsInput);
100
+ if (collections.length === 0) {
101
+ console.error('--collections must list at least one collection id.\n');
102
+ console.error(USAGE);
103
+ process.exit(1);
104
+ }
105
+ await provisionDevGrants({
106
+ serverUrl: serverUrl,
107
+ seed: parseSeed(seedInput),
108
+ collections,
109
+ spaceName: values['space-name'],
110
+ outFile: values.out,
111
+ probe: values.probe,
112
+ log: console.log
113
+ });
114
+ }
115
+ // Run only when invoked as a script, not when imported (e.g. by tests).
116
+ if (argv[1] !== undefined && import.meta.url === pathToFileURL(argv[1]).href) {
117
+ main().catch(err => {
118
+ console.error('Provisioning failed:', err);
119
+ process.exit(1);
120
+ });
121
+ }
122
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/dev/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.test.d.ts","sourceRoot":"","sources":["../../src/dev/cli.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { parseSeed, parseCollections } from './cli.js';
6
+ describe('parseSeed', () => {
7
+ it('decodes a hex seed to raw bytes', () => {
8
+ // "life-advisor-dev-seed-0123456789" as hex (32 bytes).
9
+ const hex = '6c6966652d6164766973';
10
+ expect(Array.from(parseSeed(hex))).toEqual([
11
+ 0x6c, 0x69, 0x66, 0x65, 0x2d, 0x61, 0x64, 0x76, 0x69, 0x73
12
+ ]);
13
+ });
14
+ it('decodes uppercase hex', () => {
15
+ expect(Array.from(parseSeed('DEADBEEF'))).toEqual([0xde, 0xad, 0xbe, 0xef]);
16
+ });
17
+ it('decodes a base64url seed to raw bytes', () => {
18
+ // Bytes [0xfb, 0xff, 0xbf] encode as base64url "-_-_" (uses - and _).
19
+ expect(Array.from(parseSeed('-_-_'))).toEqual([0xfb, 0xff, 0xbf]);
20
+ });
21
+ it('trims surrounding whitespace', () => {
22
+ expect(Array.from(parseSeed(' deadbeef '))).toEqual([
23
+ 0xde, 0xad, 0xbe, 0xef
24
+ ]);
25
+ });
26
+ });
27
+ describe('parseCollections', () => {
28
+ it('splits a comma-separated list', () => {
29
+ expect(parseCollections('action-items,projects,goals')).toEqual([
30
+ 'action-items',
31
+ 'projects',
32
+ 'goals'
33
+ ]);
34
+ });
35
+ it('trims and drops empty entries', () => {
36
+ expect(parseCollections(' a , , b ,')).toEqual(['a', 'b']);
37
+ });
38
+ });
39
+ //# sourceMappingURL=cli.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../../src/dev/cli.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEtD,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,wDAAwD;QACxD,MAAM,GAAG,GAAG,sBAAsB,CAAA;QAClC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACzC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;SAC3D,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IAC7E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,sEAAsE;QACtE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACpD,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;SACvB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,gBAAgB,CAAC,6BAA6B,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9D,cAAc;YACd,UAAU;YACV,OAAO;SACR,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IAC5D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,10 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * Node-only dev tooling, exposed through the package `./dev` subpath. Provisions
6
+ * dev grants against a running was-teaching-server so an app can dev-sync
7
+ * without a CHAPI wallet in the loop.
8
+ */
9
+ export { provisionDevGrants, DEFAULT_PROVISIONER_SEED, type ProvisionDevGrantsResult } from './provisionDevGrants.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;GAIG;AACH,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,wBAAwB,EAC9B,MAAM,yBAAyB,CAAA"}
@@ -0,0 +1,10 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * Node-only dev tooling, exposed through the package `./dev` subpath. Provisions
6
+ * dev grants against a running was-teaching-server so an app can dev-sync
7
+ * without a CHAPI wallet in the loop.
8
+ */
9
+ export { provisionDevGrants, DEFAULT_PROVISIONER_SEED } from './provisionDevGrants.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;GAIG;AACH,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EAEzB,MAAM,yBAAyB,CAAA"}
@@ -0,0 +1,73 @@
1
+ import { type ActionInput } from '@interop/was-client';
2
+ import type { IDelegatedZcap } from '@interop/data-integrity-core';
3
+ /**
4
+ * A fixed, distinct default provisioner seed -- the "wallet" that owns the dev
5
+ * Space. Kept separate from the app seed (the relying party) so the delegation
6
+ * is a genuine cross-identity grant, exactly as in the real wallet-to-RP flow.
7
+ */
8
+ export declare const DEFAULT_PROVISIONER_SEED: Uint8Array;
9
+ /**
10
+ * The outcome of a provisioning run: the signed grants plus the topology and
11
+ * identities they were minted against. The JSON written to `outFile` (when
12
+ * given) is `{ grants }`.
13
+ */
14
+ export interface ProvisionDevGrantsResult {
15
+ /** One delegated read/write zcap per requested collection. */
16
+ grants: IDelegatedZcap[];
17
+ /** The created space id. */
18
+ spaceId: string;
19
+ /** The absolute space URL (`<serverUrl>/space/<spaceId>`). */
20
+ spaceUrl: string;
21
+ /** The app (relying party) controller DID the grants were delegated to. */
22
+ appDid: string;
23
+ /** The throwaway provisioner (space owner) DID. */
24
+ provisionerDid: string;
25
+ /**
26
+ * Present only when `probe` was requested: the result of PUTting the
27
+ * encryption marker with the app's delegated RW zcap.
28
+ */
29
+ probe?: {
30
+ authorized: boolean;
31
+ status?: number;
32
+ body?: unknown;
33
+ };
34
+ }
35
+ /**
36
+ * Provisions a dev Space, its collections, and per-collection RW zcaps delegated
37
+ * to the app DID derived from `seed`.
38
+ *
39
+ * @param options {object}
40
+ * @param options.serverUrl {string} base URL of a running was-teaching-server
41
+ * @param options.seed {Uint8Array} the app (relying party) master seed; the
42
+ * app DID the grants are delegated to is derived from it
43
+ * @param options.collections {string[]} the WAS collection ids to create and
44
+ * grant (e.g. `['action-items', 'projects']`)
45
+ * @param [options.spaceName] {string} human-readable Space name (defaults to
46
+ * `'Dev Space'`)
47
+ * @param [options.outFile] {string} when given, the `{ grants }` JSON is
48
+ * written here (parent directories are created)
49
+ * @param [options.provisionerSeed] {Uint8Array} the space-owner seed (defaults
50
+ * to `DEFAULT_PROVISIONER_SEED`)
51
+ * @param [options.identityHandle] {string} cosmetic label for the app identity
52
+ * agent; does not affect the derived DID
53
+ * @param [options.actions] {ActionInput[]} the RW action set delegated per
54
+ * collection (defaults to the auth layer's `RW_ACTIONS`)
55
+ * @param [options.probe] {boolean} when true, probe whether the delegated RW
56
+ * zcap authorizes a PUT of the `{ encryption: { scheme: 'edv' } }` marker
57
+ * @param [options.log] {(message: string) => void} progress sink (defaults to
58
+ * a no-op; the CLI passes `console.log`)
59
+ * @returns {Promise<ProvisionDevGrantsResult>}
60
+ */
61
+ export declare function provisionDevGrants({ serverUrl, seed, collections, spaceName, outFile, provisionerSeed, identityHandle, actions, probe, log }: {
62
+ serverUrl: string;
63
+ seed: Uint8Array;
64
+ collections: string[];
65
+ spaceName?: string;
66
+ outFile?: string;
67
+ provisionerSeed?: Uint8Array;
68
+ identityHandle?: string;
69
+ actions?: ActionInput[];
70
+ probe?: boolean;
71
+ log?: (message: string) => void;
72
+ }): Promise<ProvisionDevGrantsResult>;
73
+ //# sourceMappingURL=provisionDevGrants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisionDevGrants.d.ts","sourceRoot":"","sources":["../../src/dev/provisionDevGrants.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAOlE;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,UAIrC,CAAA;AAEF;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,8DAA8D;IAC9D,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAA;IACd,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,KAAK,CAAC,EAAE;QACN,UAAU,EAAE,OAAO,CAAA;QACnB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,IAAI,CAAC,EAAE,OAAO,CAAA;KACf,CAAA;CACF;AA+BD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,kBAAkB,CAAC,EACvC,SAAS,EACT,IAAI,EACJ,WAAW,EACX,SAAuB,EACvB,OAAO,EACP,eAA0C,EAC1C,cAAc,EAGd,OAAqC,EACrC,KAAa,EACb,GAAc,EACf,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,UAAU,CAAA;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAgGpC"}
@@ -0,0 +1,176 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * Dev grant provisioning (CHAPI bypassed). Against a running was-teaching-server
6
+ * this:
7
+ *
8
+ * 1. derives a throwaway "provisioner" identity (stands in for the wallet that
9
+ * owns the Space) and the app's own controller DID from the supplied seed;
10
+ * 2. creates a Space (owned by the provisioner) and the requested collections,
11
+ * PLAINTEXT -- deliberately WITHOUT an encryption marker, mirroring what a
12
+ * wallet does when it provisions RP-requested collections;
13
+ * 3. delegates a per-collection read/write zcap to the app's controller DID;
14
+ * 4. returns the signed grants and (optionally) writes them to a JSON file the
15
+ * app loads in dev-sync mode;
16
+ * 5. optionally probes the open question: does the delegated, collection-scoped
17
+ * RW zcap authorize an RP-side PUT of the collection description carrying the
18
+ * { encryption: { scheme: 'edv' } } marker?
19
+ *
20
+ * Node only (uses `fs`); consumed through the package `./dev` subpath.
21
+ */
22
+ import { mkdir, writeFile } from 'node:fs/promises';
23
+ import { dirname } from 'node:path';
24
+ import { WasClient } from '@interop/was-client';
25
+ import { ZcapClient } from '@interop/ezcap';
26
+ import { Ed25519Signature2020 } from '@interop/ed25519-signature';
27
+ import { CapabilityAgent } from '@interop/webkms-client';
28
+ import { deriveIdentity } from '../identity/agents.js';
29
+ import { RW_ACTIONS } from '../auth/loginRequest.js';
30
+ /**
31
+ * A fixed, distinct default provisioner seed -- the "wallet" that owns the dev
32
+ * Space. Kept separate from the app seed (the relying party) so the delegation
33
+ * is a genuine cross-identity grant, exactly as in the real wallet-to-RP flow.
34
+ */
35
+ export const DEFAULT_PROVISIONER_SEED = new Uint8Array([
36
+ 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2d, 0x64,
37
+ 0x65, 0x76, 0x2d, 0x73, 0x65, 0x65, 0x64, 0x2d, 0x30, 0x31, 0x32, 0x33, 0x34,
38
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x41
39
+ ]);
40
+ /**
41
+ * Builds the provisioner's WAS client (owns / provisions the Space).
42
+ *
43
+ * @param options {object}
44
+ * @param options.serverUrl {string}
45
+ * @param options.seed {Uint8Array} the provisioner (space-owner) seed
46
+ * @returns {Promise<{ was: WasClient, did: string }>}
47
+ */
48
+ async function provisionerClient({ serverUrl, seed }) {
49
+ const agent = await CapabilityAgent.fromSeed({
50
+ seed,
51
+ handle: 'dev-provisioner',
52
+ keyName: 'provisioner-key'
53
+ });
54
+ const signer = agent.getSigner();
55
+ const zcapClient = new ZcapClient({
56
+ SuiteClass: Ed25519Signature2020,
57
+ invocationSigner: signer,
58
+ delegationSigner: signer
59
+ });
60
+ return { was: new WasClient({ serverUrl, zcapClient }), did: agent.id };
61
+ }
62
+ /**
63
+ * Provisions a dev Space, its collections, and per-collection RW zcaps delegated
64
+ * to the app DID derived from `seed`.
65
+ *
66
+ * @param options {object}
67
+ * @param options.serverUrl {string} base URL of a running was-teaching-server
68
+ * @param options.seed {Uint8Array} the app (relying party) master seed; the
69
+ * app DID the grants are delegated to is derived from it
70
+ * @param options.collections {string[]} the WAS collection ids to create and
71
+ * grant (e.g. `['action-items', 'projects']`)
72
+ * @param [options.spaceName] {string} human-readable Space name (defaults to
73
+ * `'Dev Space'`)
74
+ * @param [options.outFile] {string} when given, the `{ grants }` JSON is
75
+ * written here (parent directories are created)
76
+ * @param [options.provisionerSeed] {Uint8Array} the space-owner seed (defaults
77
+ * to `DEFAULT_PROVISIONER_SEED`)
78
+ * @param [options.identityHandle] {string} cosmetic label for the app identity
79
+ * agent; does not affect the derived DID
80
+ * @param [options.actions] {ActionInput[]} the RW action set delegated per
81
+ * collection (defaults to the auth layer's `RW_ACTIONS`)
82
+ * @param [options.probe] {boolean} when true, probe whether the delegated RW
83
+ * zcap authorizes a PUT of the `{ encryption: { scheme: 'edv' } }` marker
84
+ * @param [options.log] {(message: string) => void} progress sink (defaults to
85
+ * a no-op; the CLI passes `console.log`)
86
+ * @returns {Promise<ProvisionDevGrantsResult>}
87
+ */
88
+ export async function provisionDevGrants({ serverUrl, seed, collections, spaceName = 'Dev Space', outFile, provisionerSeed = DEFAULT_PROVISIONER_SEED, identityHandle,
89
+ // The server accepts HEAD even though storage-core's ActionInput union omits
90
+ // it, hence the assertion.
91
+ actions = RW_ACTIONS, probe = false, log = () => { } }) {
92
+ const { controllerDid: appDid, zcapClient: appZcapClient } = await deriveIdentity({ seed, identityHandle });
93
+ const { was: provisioner, did: provisionerDid } = await provisionerClient({
94
+ serverUrl,
95
+ seed: provisionerSeed
96
+ });
97
+ log(`Provisioning against ${serverUrl}`);
98
+ log(` provisioner DID: ${provisionerDid}`);
99
+ log(` app (RP) DID: ${appDid}`);
100
+ const space = await provisioner.createSpace({
101
+ name: spaceName,
102
+ controller: provisionerDid
103
+ });
104
+ log(` space id: ${space.id}`);
105
+ // Each collection grant is delegated from the SPACE ROOT (not the collection
106
+ // root) attenuating down to the collection URL. This is what the reference
107
+ // server authorizes for a collection's sub-resources: a chain rooted at the
108
+ // space root, whose invocationTarget (the collection URL) is a RESTful prefix
109
+ // of every `/<collection>/<resource>` and `/<collection>/query` request. A
110
+ // grant rooted at the collection's own root authorizes only the exact
111
+ // collection-description URL, not its resources or the changes feed.
112
+ const spaceUrl = `${serverUrl}/space/${space.id}`;
113
+ const spaceRoot = {
114
+ '@context': 'https://w3id.org/zcap/v1',
115
+ id: `urn:zcap:root:${encodeURIComponent(spaceUrl)}`,
116
+ controller: provisionerDid,
117
+ invocationTarget: spaceUrl
118
+ };
119
+ const grants = [];
120
+ for (const id of collections) {
121
+ // Plaintext collection (no encryption marker) -- mirrors wallet provisioning.
122
+ await space.createCollection({ id, name: id });
123
+ const zcap = await provisioner.grant({
124
+ to: appDid,
125
+ actions,
126
+ target: `${spaceUrl}/${id}`,
127
+ capability: spaceRoot
128
+ });
129
+ grants.push(zcap);
130
+ log(` collection "${id}": created + delegated RW to app`);
131
+ }
132
+ if (outFile !== undefined) {
133
+ await mkdir(dirname(outFile), { recursive: true });
134
+ await writeFile(outFile, JSON.stringify({ grants }, null, 2));
135
+ log(`\nWrote ${grants.length} grants to ${outFile}`);
136
+ }
137
+ const result = {
138
+ grants,
139
+ spaceId: space.id,
140
+ spaceUrl,
141
+ appDid,
142
+ provisionerDid
143
+ };
144
+ if (!probe) {
145
+ return result;
146
+ }
147
+ // --- Encryption-marker probe ---------------------------------------------
148
+ // Using the app's OWN delegated RW zcap (not the provisioner root key),
149
+ // attempt to PUT the collection description with the edv marker.
150
+ const appWas = new WasClient({ serverUrl, zcapClient: appZcapClient });
151
+ const probeCollectionId = collections[0];
152
+ const probeCapability = grants[0];
153
+ log(`\nEncryption-marker probe on "${probeCollectionId}" (delegated RW zcap):`);
154
+ try {
155
+ const response = await appWas.request({
156
+ capability: probeCapability,
157
+ path: `/space/${space.id}/${probeCollectionId}`,
158
+ method: 'PUT',
159
+ json: { id: probeCollectionId, encryption: { scheme: 'edv' } }
160
+ });
161
+ log(` AUTHORIZED -- server responded ${response.status}`);
162
+ result.probe = { authorized: true, status: response.status };
163
+ }
164
+ catch (err) {
165
+ const status = err.status ??
166
+ err.response?.status;
167
+ const data = err.data;
168
+ log(` NOT AUTHORIZED -- status ${status ?? 'n/a'}`);
169
+ if (data !== undefined) {
170
+ log(` server body: ${JSON.stringify(data)}`);
171
+ }
172
+ result.probe = { authorized: false, status, body: data };
173
+ }
174
+ return result;
175
+ }
176
+ //# sourceMappingURL=provisionDevGrants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisionDevGrants.js","sourceRoot":"","sources":["../../src/dev/provisionDevGrants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,SAAS,EAAoB,MAAM,qBAAqB,CAAA;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEpD;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAe,IAAI,UAAU,CAAC;IACjE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC5E,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC5E,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CACnC,CAAC,CAAA;AA6BF;;;;;;;GAOG;AACH,KAAK,UAAU,iBAAiB,CAAC,EAC/B,SAAS,EACT,IAAI,EAIL;IACC,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC;QAC3C,IAAI;QACJ,MAAM,EAAE,iBAAiB;QACzB,OAAO,EAAE,iBAAiB;KAC3B,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,CAAA;IAChC,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC;QAChC,UAAU,EAAE,oBAAoB;QAChC,gBAAgB,EAAE,MAAM;QACxB,gBAAgB,EAAE,MAAM;KACzB,CAAC,CAAA;IACF,OAAO,EAAE,GAAG,EAAE,IAAI,SAAS,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAA;AACzE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EACvC,SAAS,EACT,IAAI,EACJ,WAAW,EACX,SAAS,GAAG,WAAW,EACvB,OAAO,EACP,eAAe,GAAG,wBAAwB,EAC1C,cAAc;AACd,6EAA6E;AAC7E,2BAA2B;AAC3B,OAAO,GAAG,UAA2B,EACrC,KAAK,GAAG,KAAK,EACb,GAAG,GAAG,GAAG,EAAE,GAAE,CAAC,EAYf;IACC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GACxD,MAAM,cAAc,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAA;IAChD,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,MAAM,iBAAiB,CAAC;QACxE,SAAS;QACT,IAAI,EAAE,eAAe;KACtB,CAAC,CAAA;IAEF,GAAG,CAAC,wBAAwB,SAAS,EAAE,CAAC,CAAA;IACxC,GAAG,CAAC,sBAAsB,cAAc,EAAE,CAAC,CAAA;IAC3C,GAAG,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAA;IAEnC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC;QAC1C,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,cAAc;KAC3B,CAAC,CAAA;IACF,GAAG,CAAC,sBAAsB,KAAK,CAAC,EAAE,EAAE,CAAC,CAAA;IAErC,6EAA6E;IAC7E,2EAA2E;IAC3E,4EAA4E;IAC5E,8EAA8E;IAC9E,2EAA2E;IAC3E,sEAAsE;IACtE,qEAAqE;IACrE,MAAM,QAAQ,GAAG,GAAG,SAAS,UAAU,KAAK,CAAC,EAAE,EAAE,CAAA;IACjD,MAAM,SAAS,GAAG;QAChB,UAAU,EAAE,0BAA0B;QACtC,EAAE,EAAE,iBAAiB,kBAAkB,CAAC,QAAQ,CAAC,EAAE;QACnD,UAAU,EAAE,cAAc;QAC1B,gBAAgB,EAAE,QAAQ;KACyC,CAAA;IAErE,MAAM,MAAM,GAAqB,EAAE,CAAA;IACnC,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC7B,8EAA8E;QAC9E,MAAM,KAAK,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;QAC9C,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC;YACnC,EAAE,EAAE,MAAM;YACV,OAAO;YACP,MAAM,EAAE,GAAG,QAAQ,IAAI,EAAE,EAAE;YAC3B,UAAU,EAAE,SAAS;SACtB,CAAC,CAAA;QACF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjB,GAAG,CAAC,iBAAiB,EAAE,kCAAkC,CAAC,CAAA;IAC5D,CAAC;IAED,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAClD,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAC7D,GAAG,CAAC,WAAW,MAAM,CAAC,MAAM,cAAc,OAAO,EAAE,CAAC,CAAA;IACtD,CAAC;IAED,MAAM,MAAM,GAA6B;QACvC,MAAM;QACN,OAAO,EAAE,KAAK,CAAC,EAAE;QACjB,QAAQ;QACR,MAAM;QACN,cAAc;KACf,CAAA;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,MAAM,CAAA;IACf,CAAC;IAED,4EAA4E;IAC5E,wEAAwE;IACxE,iEAAiE;IACjE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAA;IACtE,MAAM,iBAAiB,GAAG,WAAW,CAAC,CAAC,CAAE,CAAA;IACzC,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,CAAE,CAAA;IAClC,GAAG,CACD,iCAAiC,iBAAiB,wBAAwB,CAC3E,CAAA;IACD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;YACpC,UAAU,EAAE,eAAe;YAC3B,IAAI,EAAE,UAAU,KAAK,CAAC,EAAE,IAAI,iBAAiB,EAAE;YAC/C,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,EAAE,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;SAC/D,CAAC,CAAA;QACF,GAAG,CAAC,oCAAoC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;QAC1D,MAAM,CAAC,KAAK,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;IAC9D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GACT,GAA2B,CAAC,MAAM;YAClC,GAA0C,CAAC,QAAQ,EAAE,MAAM,CAAA;QAC9D,MAAM,IAAI,GAAI,GAA0B,CAAC,IAAI,CAAA;QAC7C,GAAG,CAAC,8BAA8B,MAAM,IAAI,KAAK,EAAE,CAAC,CAAA;QACpD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,GAAG,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC/C,CAAC;QACD,MAAM,CAAC,KAAK,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IAC1D,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -0,0 +1,59 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * Grant parsing and per-collection capability routing for the delegated
6
+ * (relying-party) sync model. The app never provisions the Space and never
7
+ * derives the spaceId itself; instead it receives a set of wallet-delegated
8
+ * zcaps -- minted by a provisioning script during development, or returned by
9
+ * the wallet through CHAPI -- and reads the WAS topology (server URL, space id,
10
+ * per-collection routing) straight out of their `invocationTarget` URLs.
11
+ *
12
+ * Every grant's `invocationTarget` is an absolute WAS URL of the form
13
+ * `<serverUrl>/space/<spaceId>/<collectionId>` (a trailing slash is tolerated).
14
+ * All grants MUST resolve to a single server origin and a single space; a
15
+ * mismatch aborts (a grant set spanning two spaces is never expected and would
16
+ * silently split writes).
17
+ */
18
+ import type { IZcap } from '@interop/data-integrity-core';
19
+ /**
20
+ * The topology parsed out of a delegated grant set: the WAS server origin (the
21
+ * exact string a `WasClient` / `SERVER_URL` must match), the single space id,
22
+ * and the per-collection capability keyed by WAS collection id.
23
+ */
24
+ export interface ParsedGrants {
25
+ serverUrl: string;
26
+ spaceId: string;
27
+ /** Keyed by WAS collection id (e.g. `action-items`). */
28
+ byCollectionId: Record<string, IZcap>;
29
+ }
30
+ /**
31
+ * One grant's target, split into server origin + space + collection. A space- or
32
+ * collection-scoped target may omit `collectionId`.
33
+ */
34
+ interface ParsedTarget {
35
+ serverUrl: string;
36
+ spaceId: string;
37
+ collectionId?: string;
38
+ }
39
+ /**
40
+ * Parses a single `invocationTarget` URL into its WAS components. `serverUrl` is
41
+ * the bare origin (`protocol//host`) with no trailing slash, matching the shape
42
+ * the reference server validates `SERVER_URL` into.
43
+ *
44
+ * @param target {string} an absolute WAS URL
45
+ * @returns {ParsedTarget}
46
+ */
47
+ export declare function parseInvocationTarget(target: string): ParsedTarget;
48
+ /**
49
+ * Parses a delegated grant set into the sync topology. Asserts a single server
50
+ * origin and a single space across every grant, and routes each collection-scoped
51
+ * grant to its WAS collection id. A space-scoped grant (no collection segment)
52
+ * still contributes its server/space but is not added to the routing table.
53
+ *
54
+ * @param zcaps {IZcap[]} the delegated capabilities
55
+ * @returns {ParsedGrants}
56
+ */
57
+ export declare function parseGrants(zcaps: IZcap[]): ParsedGrants;
58
+ export {};
59
+ //# sourceMappingURL=grants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AAEzD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,wDAAwD;IACxD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;CACtC;AAED;;;GAGG;AACH,UAAU,YAAY;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAqBlE;AAiBD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAkCxD"}
package/dist/grants.js ADDED
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Parses a single `invocationTarget` URL into its WAS components. `serverUrl` is
3
+ * the bare origin (`protocol//host`) with no trailing slash, matching the shape
4
+ * the reference server validates `SERVER_URL` into.
5
+ *
6
+ * @param target {string} an absolute WAS URL
7
+ * @returns {ParsedTarget}
8
+ */
9
+ export function parseInvocationTarget(target) {
10
+ let url;
11
+ try {
12
+ url = new URL(target);
13
+ }
14
+ catch {
15
+ throw new Error(`Grant invocationTarget is not an absolute URL: "${target}".`);
16
+ }
17
+ const segments = url.pathname.split('/').filter(Boolean);
18
+ const [root, spaceId, collectionId] = segments;
19
+ if (root !== 'space' || !spaceId) {
20
+ throw new Error(`Grant invocationTarget is not a WAS space URL: "${target}".`);
21
+ }
22
+ return {
23
+ serverUrl: `${url.protocol}//${url.host}`,
24
+ spaceId,
25
+ ...(collectionId !== undefined && { collectionId })
26
+ };
27
+ }
28
+ /**
29
+ * Reads a grant's single `invocationTarget` string. `@interop` zcaps carry it as
30
+ * a string; guard defensively (an array or missing target is a malformed grant).
31
+ *
32
+ * @param zcap {IZcap}
33
+ * @returns {string}
34
+ */
35
+ function invocationTargetOf(zcap) {
36
+ const target = zcap.invocationTarget;
37
+ if (typeof target !== 'string' || target.length === 0) {
38
+ throw new Error('Grant is missing a string invocationTarget.');
39
+ }
40
+ return target;
41
+ }
42
+ /**
43
+ * Parses a delegated grant set into the sync topology. Asserts a single server
44
+ * origin and a single space across every grant, and routes each collection-scoped
45
+ * grant to its WAS collection id. A space-scoped grant (no collection segment)
46
+ * still contributes its server/space but is not added to the routing table.
47
+ *
48
+ * @param zcaps {IZcap[]} the delegated capabilities
49
+ * @returns {ParsedGrants}
50
+ */
51
+ export function parseGrants(zcaps) {
52
+ if (zcaps.length === 0) {
53
+ throw new Error('No grants to parse.');
54
+ }
55
+ let serverUrl;
56
+ let spaceId;
57
+ const byCollectionId = {};
58
+ for (const zcap of zcaps) {
59
+ const parsed = parseInvocationTarget(invocationTargetOf(zcap));
60
+ if (serverUrl === undefined) {
61
+ serverUrl = parsed.serverUrl;
62
+ }
63
+ else if (serverUrl !== parsed.serverUrl) {
64
+ throw new Error(`Grants span two servers: "${serverUrl}" vs "${parsed.serverUrl}".`);
65
+ }
66
+ if (spaceId === undefined) {
67
+ spaceId = parsed.spaceId;
68
+ }
69
+ else if (spaceId !== parsed.spaceId) {
70
+ throw new Error(`Grants span two spaces: "${spaceId}" vs "${parsed.spaceId}".`);
71
+ }
72
+ if (parsed.collectionId !== undefined) {
73
+ byCollectionId[parsed.collectionId] = zcap;
74
+ }
75
+ }
76
+ return {
77
+ serverUrl: serverUrl,
78
+ spaceId: spaceId,
79
+ byCollectionId
80
+ };
81
+ }
82
+ //# sourceMappingURL=grants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.js","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"AAyCA;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,IAAI,GAAQ,CAAA;IACZ,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,mDAAmD,MAAM,IAAI,CAC9D,CAAA;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACxD,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAA;IAC9C,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,mDAAmD,MAAM,IAAI,CAC9D,CAAA;IACH,CAAC;IACD,OAAO;QACL,SAAS,EAAE,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,IAAI,EAAE;QACzC,OAAO;QACP,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,EAAE,YAAY,EAAE,CAAC;KACpD,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,IAAW;IACrC,MAAM,MAAM,GAAI,IAAuC,CAAC,gBAAgB,CAAA;IACxE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAA;IACxC,CAAC;IACD,IAAI,SAA6B,CAAA;IACjC,IAAI,OAA2B,CAAA;IAC/B,MAAM,cAAc,GAA0B,EAAE,CAAA;IAEhD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,qBAAqB,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAA;QAC9D,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;QAC9B,CAAC;aAAM,IAAI,SAAS,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CACb,6BAA6B,SAAS,SAAS,MAAM,CAAC,SAAS,IAAI,CACpE,CAAA;QACH,CAAC;QACD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;QAC1B,CAAC;aAAM,IAAI,OAAO,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CACb,4BAA4B,OAAO,SAAS,MAAM,CAAC,OAAO,IAAI,CAC/D,CAAA;QACH,CAAC;QACD,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACtC,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI,CAAA;QAC5C,CAAC;IACH,CAAC;IAED,OAAO;QACL,SAAS,EAAE,SAAmB;QAC9B,OAAO,EAAE,OAAiB;QAC1B,cAAc;KACf,CAAA;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=grants.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.test.d.ts","sourceRoot":"","sources":["../src/grants.test.ts"],"names":[],"mappings":""}