@north-light/cli 0.3.548 → 0.3.550

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 (160) hide show
  1. package/dist/api/contract.d.ts +1 -1
  2. package/dist/api/contract.js +1 -1
  3. package/dist/api/dto/custom-objects.d.ts +1 -1
  4. package/dist/api/dto/docs.d.ts +12 -0
  5. package/dist/api/dto/objects.d.ts +17 -1
  6. package/dist/api/dto/objects.js +1 -1
  7. package/dist/api/dto/permissions.d.ts +76 -0
  8. package/dist/api/dto/permissions.js +1 -0
  9. package/dist/api/index.d.ts +3 -2
  10. package/dist/api/index.js +1 -1
  11. package/dist/api/routes.d.ts +4 -0
  12. package/dist/api/routes.js +1 -1
  13. package/dist/builtin-memory/crouter-concepts/documents.md +1 -1
  14. package/dist/builtin-memory/crouter-concepts/scopes-and-trust.md +2 -2
  15. package/dist/builtin-memory/crouter-sdk/release-notes.md +11 -0
  16. package/dist/builtin-memory/internal/INDEX.md +2 -1
  17. package/dist/builtin-memory/internal/agent-shaping.md +1 -1
  18. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  19. package/dist/builtin-memory/northlight-apps/guides/files-and-documents.md +3 -3
  20. package/dist/builtin-memory/northlight-apps/guides/many-users.md +1 -1
  21. package/dist/builtin-memory/northlight-apps/guides/test-your-app.md +1 -1
  22. package/dist/clients/attach/viewer.js +9 -9
  23. package/dist/commands/canvas/list.js +2 -2
  24. package/dist/commands/canvas/share.d.ts +2 -0
  25. package/dist/commands/canvas/share.js +2 -0
  26. package/dist/commands/canvas.js +1 -1
  27. package/dist/commands/doc/edit.js +1 -1
  28. package/dist/commands/doc/shared.js +1 -1
  29. package/dist/commands/doc/write.js +1 -1
  30. package/dist/commands/sys/sync-skills.js +2 -2
  31. package/dist/core/canvas/canvas.js +20 -20
  32. package/dist/core/canvas/db.js +4 -4
  33. package/dist/core/canvas/export-sqlite.js +2 -2
  34. package/dist/core/canvas/import-sqlite.js +5 -5
  35. package/dist/core/canvas/outcome-actions.js +3 -3
  36. package/dist/core/canvas/person.js +11 -9
  37. package/dist/core/canvas/schema-pg.sql +49 -5
  38. package/dist/core/environments.js +1 -1
  39. package/dist/core/feed/feed.js +1 -1
  40. package/dist/core/grants/mirror.d.ts +9 -1
  41. package/dist/core/grants/mirror.js +2 -2
  42. package/dist/core/grants/sync.js +1 -1
  43. package/dist/core/graph/access.d.ts +8 -49
  44. package/dist/core/graph/access.js +4 -7
  45. package/dist/core/graph/custom.d.ts +5 -2
  46. package/dist/core/graph/custom.js +9 -9
  47. package/dist/core/graph/deletion.js +5 -4
  48. package/dist/core/graph/documents.d.ts +12 -3
  49. package/dist/core/graph/documents.js +13 -7
  50. package/dist/core/graph/edges.js +3 -3
  51. package/dist/core/graph/events.js +12 -8
  52. package/dist/core/graph/kinds/document.js +4 -4
  53. package/dist/core/graph/kinds/kind.js +1 -1
  54. package/dist/core/graph/kinds/node.js +5 -5
  55. package/dist/core/graph/names.d.ts +16 -1
  56. package/dist/core/graph/names.js +11 -3
  57. package/dist/core/graph/objects.d.ts +19 -2
  58. package/dist/core/graph/objects.js +16 -10
  59. package/dist/core/graph/package-docs.js +5 -5
  60. package/dist/core/graph/package-files.js +2 -2
  61. package/dist/core/graph/reader.js +3 -3
  62. package/dist/core/graph/repo-sync/exchange.js +2 -2
  63. package/dist/core/graph/rules.d.ts +7 -5
  64. package/dist/core/graph/rules.js +3 -3
  65. package/dist/core/graph/types.d.ts +12 -1
  66. package/dist/core/graph/types.js +1 -1
  67. package/dist/core/graph/watches.d.ts +1 -1
  68. package/dist/core/graph/watches.js +9 -8
  69. package/dist/core/peer/envelope.d.ts +1 -1
  70. package/dist/core/peer/envelope.js +1 -1
  71. package/dist/core/peer/stubs.d.ts +1 -1
  72. package/dist/core/peer/stubs.js +1 -1
  73. package/dist/core/permissions/boot.d.ts +17 -0
  74. package/dist/core/permissions/boot.js +18 -0
  75. package/dist/core/permissions/builtin.d.ts +8 -0
  76. package/dist/core/permissions/builtin.js +20 -0
  77. package/dist/core/permissions/ceiling.d.ts +57 -0
  78. package/dist/core/permissions/ceiling.js +22 -0
  79. package/dist/core/permissions/compile.d.ts +14 -0
  80. package/dist/core/permissions/compile.js +1 -0
  81. package/dist/core/permissions/errors.d.ts +7 -0
  82. package/dist/core/permissions/errors.js +1 -0
  83. package/dist/core/permissions/evaluator.d.ts +28 -0
  84. package/dist/core/permissions/evaluator.js +6 -0
  85. package/dist/core/permissions/facts.d.ts +56 -0
  86. package/dist/core/permissions/facts.js +2 -0
  87. package/dist/core/permissions/schema-parser.d.ts +29 -0
  88. package/dist/core/permissions/schema-parser.js +2 -0
  89. package/dist/core/permissions/schemas.d.ts +21 -0
  90. package/dist/core/permissions/schemas.js +2 -0
  91. package/dist/core/permissions/sql.d.ts +16 -0
  92. package/dist/core/permissions/sql.js +1 -0
  93. package/dist/core/runtime/broker/frame-client.d.ts +1 -1
  94. package/dist/core/runtime/broker/frame-client.js +1 -1
  95. package/dist/core/runtime/broker/frame-dispatch.d.ts +1 -1
  96. package/dist/core/runtime/broker/frame-dispatch.js +1 -1
  97. package/dist/core/runtime/broker/frame-read.d.ts +4 -3
  98. package/dist/core/runtime/broker/frame-read.js +1 -1
  99. package/dist/core/runtime/broker-protocol.d.ts +1 -1
  100. package/dist/core/runtime/host.js +3 -3
  101. package/dist/core/runtime/placement.js +1 -1
  102. package/dist/core/runtime/roadmap.js +1 -1
  103. package/dist/core/substrate/delivery/corpus.d.ts +2 -2
  104. package/dist/core/substrate/delivery/corpus.js +3 -3
  105. package/dist/core/substrate/delivery/deliver.js +2 -2
  106. package/dist/core/substrate/delivery/render-event.js +6 -6
  107. package/dist/core/substrate/subject-fields.d.ts +2 -0
  108. package/dist/core/substrate/subject.js +1 -1
  109. package/dist/daemon/api/app-listener.js +12 -12
  110. package/dist/daemon/api/bridge.d.ts +1 -1
  111. package/dist/daemon/api/bridge.js +4 -4
  112. package/dist/daemon/api/handlers/attach.d.ts +4 -1
  113. package/dist/daemon/api/handlers/attach.js +1 -1
  114. package/dist/daemon/api/handlers/canvas.js +5 -5
  115. package/dist/daemon/api/handlers/check.d.ts +2 -0
  116. package/dist/daemon/api/handlers/check.js +1 -0
  117. package/dist/daemon/api/handlers/custom-objects.js +2 -2
  118. package/dist/daemon/api/handlers/docs.js +1 -1
  119. package/dist/daemon/api/handlers/files.js +1 -1
  120. package/dist/daemon/api/handlers/memory.js +7 -6
  121. package/dist/daemon/api/handlers/nodes.js +1 -1
  122. package/dist/daemon/api/handlers/objects.js +3 -3
  123. package/dist/daemon/api/handlers/relations.d.ts +2 -0
  124. package/dist/daemon/api/handlers/relations.js +1 -0
  125. package/dist/daemon/api/handlers/schemas.d.ts +12 -0
  126. package/dist/daemon/api/handlers/schemas.js +1 -0
  127. package/dist/daemon/api/handlers/shares.d.ts +2 -0
  128. package/dist/daemon/api/handlers/shares.js +1 -0
  129. package/dist/daemon/api/operations.js +1 -1
  130. package/dist/daemon/api/router.d.ts +10 -6
  131. package/dist/daemon/api/router.js +1 -1
  132. package/dist/daemon/api/server.js +1 -1
  133. package/dist/daemon/api/vendor-signin.js +21 -24
  134. package/dist/daemon/crtrd.js +12 -12
  135. package/dist/daemon/reconcilers/delivery-lane.js +2 -2
  136. package/dist/migrations/004-canvas-documents/fields.d.ts +1 -1
  137. package/dist/migrations/004-canvas-documents/fields.js +2 -2
  138. package/docs/apps/guides/files-and-documents.md +3 -3
  139. package/docs/apps/guides/many-users.md +1 -1
  140. package/docs/apps/guides/test-your-app.md +1 -1
  141. package/docs/cli/documents-and-preferences.md +1 -1
  142. package/docs/concepts/documents.md +1 -1
  143. package/docs/concepts/scopes-and-trust.md +2 -2
  144. package/docs/sdk/release-notes.md +11 -0
  145. package/package.json +2 -2
  146. package/packages/crouter-identity/dist/index.js +14 -1
  147. package/packages/crouter-identity/package.json +1 -1
  148. package/runtime.lock.json +13 -13
  149. package/dist/core/graph/spaces/app.d.ts +0 -3
  150. package/dist/core/graph/spaces/app.js +0 -1
  151. package/dist/core/graph/spaces/index.d.ts +0 -18
  152. package/dist/core/graph/spaces/index.js +0 -1
  153. package/dist/core/graph/spaces/own-memory.d.ts +0 -18
  154. package/dist/core/graph/spaces/own-memory.js +0 -1
  155. package/dist/core/graph/spaces/person.d.ts +0 -5
  156. package/dist/core/graph/spaces/person.js +0 -3
  157. package/dist/core/graph/spaces/repo.d.ts +0 -14
  158. package/dist/core/graph/spaces/repo.js +0 -1
  159. package/dist/core/runs/confinement.d.ts +0 -25
  160. package/dist/core/runs/confinement.js +0 -2
@@ -33,7 +33,7 @@ An installed plugin is an app named after the plugin, and the documentation that
33
33
 
34
34
  ## Who may read
35
35
 
36
- Each document is `public` (the default), `friends` or `private`. The person reads everything, a repo owns only public documents, and a reader that cannot see a document gets the same answer as for one that does not exist. A node's own owner space is open to it; an app's access to the person's documents is by privacy level and the scopes its grant holds (see [Scopes and trust](./scopes-and-trust.md)).
36
+ Each document is `public` (the default) or `private`. The person reads everything, a repo owns only public documents, and a reader that cannot see a document gets the same answer as for one that does not exist. A node's own owner space is open to it; an app's access to the person's documents is by privacy level and the scopes its grant holds (see [Scopes and trust](./scopes-and-trust.md)).
37
37
 
38
38
  ```mermaid
39
39
  flowchart LR
@@ -15,7 +15,7 @@ Scope strings are prefixed with `crtr:`. These are the ones the daemon and CLI c
15
15
  | `crtr:act` | Creating, forking, reviving, closing and messaging nodes; `bash` and `files`; creating a human request or review (the `crtr human` commands are hidden from a run without it) |
16
16
  | `crtr:schedule` | Creating, pausing, resuming, running and deleting crons (the `crtr cron` commands are hidden without it) |
17
17
  | `crtr:memory:read:user[:path]`, `crtr:memory:rw:user[:path]`, `crtr:memory:manage:user` | The person's documents: reading, writing (`crtr doc`), and `manage` for every privacy level and every document |
18
- | `crtr:memory:read_private:user` | Read-only access to the person's `public` and `private` documents, never `friends`; no path suffix; an optional permission the person switches on; `manage:user` covers it, `read:user` and `rw:user` do not |
18
+ | `crtr:memory:read_private:user` | Read-only access to the person's `public` and `private` documents; no path suffix; an optional permission the person switches on; `manage:user` covers it, `read:user` and `rw:user` do not |
19
19
  | `crtr:memory:read:app:<id>`, `crtr:memory:rw:app:<id>` | An app's documents; `…:profile:<profile>` narrows to one of its profiles. A run with no `scopes` list, and an app's own server, reads and writes its own app's space freely; a run started with a `scopes` list needs these for its own app too |
20
20
  | `crtr:files:read\|rw:user:<dir>`, `crtr:files:read\|rw:app:<id>:<dir>`, `crtr:files:share` | Host files the run may mount, and sharing files beyond the app's own space |
21
21
  | `crtr:conversations:read:app:<id>`, `crtr:objects:read:app:<id>` | Reading another app's conversations or node objects |
@@ -23,7 +23,7 @@ Scope strings are prefixed with `crtr:`. These are the ones the daemon and CLI c
23
23
 
24
24
  The `memory` in `crtr:memory:*` is the scope family's name for access to **documents** (see [Documents](./documents.md)); there is no separate memory store. The older short names (`ask`, `act`, `schedule`, `memory:read`, `memory:write`, `llm`) are not accepted by `crtr sys connect --scopes`. A node's own documents, and an app's documents for its own nodes, need no `crtr:memory` scope.
25
25
 
26
- This is an allow-list, not a claim that code will behave. The daemon checks the scope at the route that performs the action and rejects an unavailable one. The SDK’s [`nodes.create`](../sdk/nodes.md) `scopes` field narrows a run: a run's list must stay inside what its creator and grant hold, and `crtr:act` requires `crtr:llm`. `client.memory` is not scope-gated: it lists and reads the person's `knowledge` and `preference` documents, and the answer is filtered by privacy — an app sees `public` documents, a grant holding `crtr:memory:read_private:user` also sees `private` ones, and a grant holding `crtr:memory:manage:user` sees `friends` and `private` ones. Who may read any document is the owner-and-privacy model, not a per-call scope. The exception is a run started with a `scopes` list: it reads its own app's documents (including automatic delivery of them at boot) only with `crtr:memory:read:app:<id>` and writes or edits them only with `crtr:memory:rw:app:<id>`; a refused write answers `scope_missing` naming the scope. Such a run still publishes its own reports with `crtr push` and its promoted node still gets a roadmap, but cannot edit any other document through that path, and a child never regains a scope its parent's list dropped.
26
+ This is an allow-list, not a claim that code will behave. The daemon checks the scope at the route that performs the action and rejects an unavailable one. The SDK’s [`nodes.create`](../sdk/nodes.md) `scopes` field narrows a run: a run's list must stay inside what its creator and grant hold, and `crtr:act` requires `crtr:llm`. `client.memory` is not scope-gated: it lists and reads the person's `knowledge` and `preference` documents, and the answer is filtered by privacy, which is `public` or `private`. An app's ceiling is `public` documents; a grant holding `crtr:memory:read_private:user` or `crtr:memory:manage:user` widens it to `private` ones. Within that ceiling, the app's registered schema and the relation facts it writes decide who may read a document, not a per-call scope. The exception is a run started with a `scopes` list: it reads its own app's documents (including automatic delivery of them at boot) only with `crtr:memory:read:app:<id>` and writes or edits them only with `crtr:memory:rw:app:<id>`; a refused write answers `scope_missing` naming the scope. Such a run still publishes its own reports with `crtr push` and its promoted node still gets a roadmap, but cannot edit any other document through that path, and a child never regains a scope its parent's list dropped.
27
27
 
28
28
  ```mermaid
29
29
  flowchart LR
@@ -7,6 +7,17 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
7
7
 
8
8
  Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
9
9
 
10
+ ## 0.3.550
11
+
12
+ An app registers a permission schema for its own object types and decides who may read each object with relations. Additive, except that `friends` leaves the privacy levels and nodes move under their profile.
13
+
14
+ - **Schemas, relations, check.** `client.schemas.register({ namespace, source })` (`POST /v1/schemas`) registers the schema for a namespace the app first claims; `client.relations.write | replace | list` (`/v1/relations`) writes and reads facts such as `firstlight/memory:<id> editor user:<id>`; `client.check(subject, permission, resource)` (`POST /v1/check`) answers whether a person may act. A type or relation outside the app's own namespace is refused `403 not_schema_owner`; a namespace another app registered first is refused `namespace_taken`.
15
+ - **Typed documents.** `docs.write` takes `schema_type` (the app type the document is an instance of) and `relations` (facts written in the same transaction), and `owner: 'user'` writes under the person the call token names. `docs.get` returns `extensions` and `schema_type`. `docs.delete(ref)`, `docs.list(params)` and `docs.search(params)` are new; `list` and `search` filter by `schema_type` and by `extensions` inside the permission-filtered query, before the page limit. Document history entries carry `acting_app` and `acting_for`.
16
+ - **`friends` is removed.** Privacy is `public` or `private`. A write naming `friends` is refused `400 invalid_request`. Existing `friends` documents became `private`; a `friends` value that arrives from an older source (a peer on an older release, a plugin package, a legacy canvas) is read as `private`.
17
+ - **Nodes are owned by their profile.** A node started under a profile now has that profile object as its `owner`, where it used to have the app: `owner` on list, search, read and event payloads names the profile, and listing with `owner=<app>&type=node` no longer returns those nodes; list them with `owner=<profile>`. Events carry the node's app as `app`. A node with no profile stays under its app.
18
+ - **A fields-only edit records a revision.** `docs.edit` with only fields (preview, summary, privacy, rules, …) now records a revision with the body unchanged, attributed to the editor with the rationale: the returned `revision` advances and `docs.history` lists it. Before, it changed the fields and left the revision alone.
19
+ - **FakeCloud** serves the new routes in memory: it parses and validates a registered schema source, refuses facts the schema does not declare, and evaluates `check`, `list` and `search` against the schema the way the runtime does. Deleting a typed document removes the facts that name it.
20
+
10
21
  ## 0.3.548
11
22
 
12
23
  `canvas.watch` with a `watcher` that is a node of your own app now works under `crtr:objects:link:node`. It answered `404 not_found` (`watcher not found`) before. The node must be reachable from the caller under run confinement and must itself be able to read the object. A watch on a node of another machine now forwards every event level, and that node's own listening config decides how each is delivered, where an event below level 3 was dropped before it left the object's machine.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.548",
3
+ "version": "0.3.550",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -140,7 +140,7 @@
140
140
  },
141
141
  "license": "UNLICENSED",
142
142
  "dependencies": {
143
- "@north-light/identity": "0.3.548",
143
+ "@north-light/identity": "0.3.550",
144
144
  "@earendil-works/pi-agent-core": "1.1.0",
145
145
  "@earendil-works/pi-ai": "1.1.0",
146
146
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -14,14 +14,27 @@ function validPath(path, directoryOnly = false) {
14
14
  !path.split('/').some((part, index, parts) => part === '.' || (part === '' && index !== parts.length - 1)) &&
15
15
  (!directoryOnly || !path.endsWith('/'));
16
16
  }
17
+ // `covers` parses both sides on every call, and a grant can hold thousands of scopes: parse each string once. A parse is pure; a throw is not cached.
18
+ const selectorCache = new Map();
19
+ const SELECTOR_CACHE_MAX = 20_000;
17
20
  function selector(value) {
21
+ let s = selectorCache.get(value);
22
+ if (s === undefined) {
23
+ s = parseSelector(value);
24
+ if (selectorCache.size >= SELECTOR_CACHE_MAX)
25
+ selectorCache.clear();
26
+ selectorCache.set(value, s);
27
+ }
28
+ return s;
29
+ }
30
+ function parseSelector(value) {
18
31
  if (value === 'crtr:llm' || value === 'crtr:act' || value === 'crtr:schedule')
19
32
  return { kind: value.slice(5), value };
20
33
  if (value === 'crtr:files:share')
21
34
  return { kind: 'share', value };
22
35
  if (value === 'crtr:memory:manage:user')
23
36
  return { kind: 'memory', access: 'manage', holder: 'user' };
24
- // Read-only access to the person's `public` and `private` memory (never `friends`). It names no document path.
37
+ // Read-only access to the person's `public` and `private` memory. It names no document path.
25
38
  if (value === 'crtr:memory:read_private:user')
26
39
  return { kind: 'memory', access: 'read_private', holder: 'user' };
27
40
  let match = /^crtr:memory:(read|rw):user(?::(.+))?$/.exec(value);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.548",
3
+ "version": "0.3.550",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.548",
3
+ "version": "0.3.550",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.548",
9
+ "version": "0.3.550",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -24,7 +24,7 @@
24
24
  "@milkdown/preset-gfm": "^7.22.3",
25
25
  "@milkdown/prose": "^7.22.3",
26
26
  "@milkdown/utils": "^7.22.3",
27
- "@north-light/identity": "0.3.548",
27
+ "@north-light/identity": "0.3.550",
28
28
  "cron-parser": "^5.6.0",
29
29
  "esbuild": "^0.27.7",
30
30
  "jose": "^6.2.12",
@@ -12455,17 +12455,17 @@
12455
12455
  },
12456
12456
  "packages/crouter-api": {
12457
12457
  "name": "@north-light/api",
12458
- "version": "0.3.548",
12458
+ "version": "0.3.550",
12459
12459
  "license": "UNLICENSED"
12460
12460
  },
12461
12461
  "packages/crouter-env-docker": {
12462
12462
  "name": "@north-light/env-docker",
12463
- "version": "0.3.548",
12463
+ "version": "0.3.550",
12464
12464
  "license": "UNLICENSED"
12465
12465
  },
12466
12466
  "packages/crouter-identity": {
12467
12467
  "name": "@north-light/identity",
12468
- "version": "0.3.548",
12468
+ "version": "0.3.550",
12469
12469
  "license": "UNLICENSED",
12470
12470
  "dependencies": {
12471
12471
  "jose": "^6.2.1"
@@ -12473,21 +12473,21 @@
12473
12473
  },
12474
12474
  "packages/crouter-plugin": {
12475
12475
  "name": "@north-light/plugin",
12476
- "version": "0.3.548",
12476
+ "version": "0.3.550",
12477
12477
  "license": "UNLICENSED",
12478
12478
  "dependencies": {
12479
- "@north-light/api": "0.3.548",
12480
- "@north-light/identity": "0.3.548"
12479
+ "@north-light/api": "0.3.550",
12480
+ "@north-light/identity": "0.3.550"
12481
12481
  }
12482
12482
  },
12483
12483
  "packages/crouter-sdk": {
12484
12484
  "name": "@north-light/sdk",
12485
- "version": "0.3.548",
12485
+ "version": "0.3.550",
12486
12486
  "license": "UNLICENSED",
12487
12487
  "dependencies": {
12488
- "@north-light/api": "0.3.548",
12489
- "@north-light/identity": "0.3.548",
12490
- "@north-light/plugin": "0.3.548",
12488
+ "@north-light/api": "0.3.550",
12489
+ "@north-light/identity": "0.3.550",
12490
+ "@north-light/plugin": "0.3.550",
12491
12491
  "jose": "^6.2.1"
12492
12492
  },
12493
12493
  "bin": {
@@ -1,3 +0,0 @@
1
- import type { Space } from './index.js';
2
- /** An app: its nodes (with their documents and jobs), its profiles and its app documents. */
3
- export declare const appSpace: Space;
@@ -1 +0,0 @@
1
- var S=Object.defineProperty;var l=(i,n)=>S(i,"name",{value:n,configurable:!0});import{covers as u}from"@north-light/identity";import{identityOf as a}from"./index.js";import{memoryScope as r,missingOwnMemoryScope as p}from"./own-memory.js";import{objectPlace as x,runPlace as f,runsSeeEachOther as O}from"../../runs/confinement.js";const M={sync:"runtime",async canRead(i,n,e,t,o){if(n.class==="person"||t.length===0)return!0;if(n.app.id===e.id)return await w(i,n,t)&&await p(i,n,e,t,o,"read")===null;const s=(await a(i,e)).external_id,c=l(y=>n.scopes!==null&&n.scopes.some(g=>u(g,y)),"held");return t[0].type==="node"?c(`crtr:objects:read:${s}`)||o.type==="document"&&o.kind==="report"&&c(`crtr:conversations:read:${s}`):c(await r(i,s,"read",t))},async canChange(i,n,e,t,o){if(n.class==="person")return!0;if(n.app.id===e.id)return t.length===0||await w(i,n,t)&&await p(i,n,e,t,o,"rw")===null;if(t.length===0||t[0].type==="node")return!1;const s=await r(i,(await a(i,e)).external_id,"rw",t);return n.scopes!==null&&n.scopes.some(c=>u(c,s))}},m=new WeakMap;async function w(i,n,e){if(n.class==="person"||e.length===0||e[0].type!=="node"||n.class==="app"&&n.place===void 0)return!0;let t=m.get(n);if(t===void 0&&(t=n.class==="app"?n.place:n.class==="node"?await f(n.node.id,i):n.place??await x(n.object.id,i),m.set(n,t)),t===null)return!0;const o=await f(e[0].id,i);return o===null?!t.isolated:O(t,o)}l(w,"runConfined");export{M as appSpace};
@@ -1,18 +0,0 @@
1
- import type { ObjectRow, Reader } from '../types.js';
2
- import type { CanvasDb } from '../../canvas/db.js';
3
- export interface IdentityRow {
4
- object: string;
5
- scheme: string;
6
- external_id: string;
7
- }
8
- export type SpaceType = 'person' | 'app' | 'repo';
9
- /** The top of an owner chain. Only a space decides access and sync for what it owns.
10
- * `path` is the owner chain below the space, top first, ending at the object
11
- * (e.g. `[node, document]`); it is empty when the object is the space itself. */
12
- export interface Space {
13
- sync: 'runtime' | 'repo-ref';
14
- canRead(db: CanvasDb, reader: Reader, space: ObjectRow, path: ObjectRow[], object: ObjectRow): Promise<boolean>;
15
- canChange(db: CanvasDb, reader: Reader, space: ObjectRow, path: ObjectRow[], object: ObjectRow): Promise<boolean>;
16
- }
17
- export declare const SPACES: Record<SpaceType, Space>;
18
- export declare function identityOf(db: CanvasDb, object: ObjectRow): Promise<IdentityRow>;
@@ -1 +0,0 @@
1
- var p=Object.defineProperty;var o=(r,e)=>p(r,"name",{value:e,configurable:!0});import{appSpace as i}from"./app.js";import{personSpace as n}from"./person.js";import{repoSpace as a}from"./repo.js";const f={person:n,app:i,repo:a};async function E(r,e){const t=await r.prepare("SELECT object, scheme, external_id FROM identities WHERE object = ?").get(e.id);if(!t)throw new Error(`${e.type} ${e.id} has no identity`);return t}o(E,"identityOf");export{f as SPACES,E as identityOf};
@@ -1,18 +0,0 @@
1
- import type { ObjectRow, Reader } from '../types.js';
2
- import type { CanvasDb } from '../../canvas/db.js';
3
- type Path = ObjectRow[];
4
- /** The scope a run launched with a `scopes` list lacks to read (`read`) or change (`rw`) one of its own app's documents, or null.
5
- * Own-app memory needs no grant scope, but a launched list narrows it (identity MEM-2): reading needs `crtr:memory:read:app:<A>`,
6
- * writing `crtr:memory:rw:app:<A>` (profile forms for a profile's documents). Only documents are gated — never a node, job or
7
- * lifecycle object — and a run with no list, an app's server and the person keep full access. A report is readable inside its
8
- * own run (a run hears its children through them); writing one is the runtime's own act (see `asRuntimeWriter`). */
9
- export declare function missingOwnMemoryScope(db: CanvasDb, reader: Reader, space: ObjectRow, path: Path, object: {
10
- type: string;
11
- kind: string | null;
12
- } | null, access: 'read' | 'rw'): Promise<string | null>;
13
- /** The same reader with its launched list lifted, for the runtime's own writes inside a narrowed run: a `crtr push` report and the
14
- * scaffolded roadmap of a promoted node. Wrap only the one call that creates the document the runtime names. */
15
- export declare function asRuntimeWriter<R extends Reader>(reader: R): R;
16
- /** `crtr:memory:<access>:app:<B>` for an app document, or its profile form for a profile and what it owns. */
17
- export declare function memoryScope(db: CanvasDb, app: string, access: 'read' | 'rw', path: Path): Promise<string>;
18
- export {};
@@ -1 +0,0 @@
1
- var m=Object.defineProperty;var o=(n,t)=>m(n,"name",{value:t,configurable:!0});import{covers as f}from"@north-light/identity";import{runPlace as s}from"../../runs/confinement.js";const a=o(async(n,t)=>(await n.prepare("SELECT external_id FROM identities WHERE object = ?").get(t.id)).external_id,"externalId");async function $(n,t,l,e,r,u){if(t.class==="person"||e.length===0||r!==null&&r.type!=="document")return null;const i=t.launched;if(i==null||u==="read"&&r?.kind==="report"&&e[0].type==="node"&&await y(n,t,e[0].id))return null;const c=await d(n,await a(n,l),u,e);return i.some(p=>f(p,c))?null:c}o($,"missingOwnMemoryScope");async function y(n,t,l){const e=t.class==="node"?await s(t.node.id,n):t.class==="person"?null:t.place??null,r=await s(l,n);return e!==null&&r!==null&&e.run===r.run}o(y,"inReadersRun");function g(n){return n.class==="person"?n:{...n,launched:null}}o(g,"asRuntimeWriter");async function d(n,t,l,e){const r=e[0];return r.type!=="profile"?`crtr:memory:${l}:${t}`:`crtr:memory:${l}:${t}:profile:${await a(n,r)}`}o(d,"memoryScope");export{g as asRuntimeWriter,d as memoryScope,$ as missingOwnMemoryScope};
@@ -1,5 +0,0 @@
1
- import type { Space } from './index.js';
2
- /** You: your documents, and nodes started with your own authority. Reads and
3
- * changes use the runtime-spaces memory permission strings; a change also
4
- * requires the document's grantee — the app of the node that wrote its first revision. */
5
- export declare const personSpace: Space;
@@ -1,3 +0,0 @@
1
- import{covers as t}from"@north-light/identity";const f={sync:"runtime",async canRead(a,e,n,s,i){return e.class==="person"||e.class==="object"&&e.owner.id===n.id?!0:e.scopes===null?!1:e.app.id===n.id||s.length===0?!0:s[0].type!=="document"?!1:e.scopes.some(o=>t(o,"crtr:memory:manage:user"))||i.privacy==="public"?!0:i.privacy==="private"&&e.scopes.some(o=>t(o,"crtr:memory:read_private:user"))},async canChange(a,e,n,s,i){if(e.class==="person"||e.class==="object"&&e.owner.id===n.id||e.app.id===n.id||e.scopes?.some(r=>t(r,"crtr:memory:manage:user")))return!0;if(s.length===0)return e.scopes?.some(r=>t(r,"crtr:memory:rw:user"))??!1;if(s[0].type!=="document")return!1;const o=`crtr:memory:rw:user:${i.name}`;if(e.scopes===null||!e.scopes.some(r=>t(r,o)))return!1;const u=await a.prepare(`SELECT author.type, author.owner AS app FROM revisions r JOIN objects author ON author.id = r.author
2
- WHERE r.document = ? ORDER BY r.number, r.created_at LIMIT 1`).get(s[0].id);return u?u.type==="person"||u.app===e.app.id?!0:(await a.prepare(`SELECT g.resolved_scopes_json FROM grants g JOIN identities i ON i.external_id = g.grantee
3
- WHERE i.object = ? AND i.scheme = 'app'`).all(u.app)).some(({resolved_scopes_json:r})=>JSON.parse(r).some(({scope:c,mode:p})=>p==="always"&&t(c,"crtr:memory:manage:user"))):!1}};export{f as personSpace};
@@ -1,14 +0,0 @@
1
- import type { Reader } from '../types.js';
2
- import type { Space } from './index.js';
3
- /** Whether a node has a checkout of `repo` that its file permissions reach: read to read the
4
- * repo's documents, rw to change them. A checkout is one enclosing the node's cwd or one of its
5
- * profile's project paths; the cwd alone never lets a run in, since a node may be started in any
6
- * directory. A repo's documents change iff its files do. A repo-owned custom object is inside its
7
- * own repo. A Mac terminal node reaches every path. */
8
- export declare function insideRepo(db: Parameters<Space['canRead']>[0], reader: Reader, repo: {
9
- id: string;
10
- }, access: 'read' | 'rw'): Promise<boolean>;
11
- /** A repo: read and changed by a run with a checkout of it (enclosing its cwd or one of its
12
- * profile's project paths) that its file permissions reach (see `insideRepo`). It owns only public documents, so a
13
- * non-public one is never changed. */
14
- export declare const repoSpace: Space;
@@ -1 +0,0 @@
1
- var p=Object.defineProperty;var i=(e,t)=>p(e,"name",{value:t,configurable:!0});import{fileRoot as l}from"../../spaces/file-root.js";import{identityOf as u}from"./index.js";async function r(e,t,n,s){if(t.class==="object")return t.repos.some(o=>o.id===n.id);if(t.class!=="node")return!1;const c=[...t.checkouts,...t.projectCheckouts].filter(o=>o.repo.id===n.id);if(c.length===0)return!1;const a={app:(await u(e,t.app)).external_id,resolved:t.scopes??[],launched:null};return c.some(o=>"root"in l(a,o.root,s))}i(r,"insideRepo");const y={sync:"repo-ref",async canRead(e,t,n,s){return t.class==="person"||s.length===0?!0:await r(e,t,n,"read")},async canChange(e,t,n,s,c){return c.privacy!=="public"?!1:t.class==="person"?!0:await r(e,t,n,"rw")}};export{r as insideRepo,y as repoSpace};
@@ -1,25 +0,0 @@
1
- import { type CanvasDb } from '../canvas/db.js';
2
- /** A node's run and whether that run is isolated (the node's own flag or its root's). */
3
- export interface RunPlace {
4
- run: string;
5
- isolated: boolean;
6
- }
7
- /** The run a node belongs to: its `run_id`, or the node itself when it has none.
8
- * A deleted node of an isolated run keeps its run through `deleted_isolated_nodes`,
9
- * so what it leaves behind stays confined; any other node without a row is null. */
10
- export declare function runPlace(nodeId: string, db?: CanvasDb): Promise<RunPlace | null>;
11
- /** Record, before a node's row is deleted, the run of a node of an isolated run. */
12
- export declare function rememberDeletedIsolated(nodeId: string, db?: CanvasDb): Promise<void>;
13
- /** The place of the node that registered a custom object, which is where that object
14
- * reads from; null when the person or the app's server registered it. */
15
- export declare function objectPlace(objectId: string, db?: CanvasDb): Promise<RunPlace | null>;
16
- /** The confinement predicate: two places see each other when they are the same
17
- * run, or when neither run is isolated. */
18
- export declare function runsSeeEachOther(a: RunPlace, b: RunPlace): boolean;
19
- /** Whether a node caller of `app` may reach `target` (a node id) under run confinement.
20
- * Confinement applies only within one app; cross-app reach stays with the scope rules. */
21
- export declare function nodeMayReach(callerNode: string, callerApp: string, targetNode: string, targetApp: string | null, db?: CanvasDb): Promise<boolean>;
22
- /** The same question for a caller that has a place but no node (a cron command: its origin run). */
23
- export declare function placeMayReach(caller: RunPlace, callerApp: string, targetNode: string, targetApp: string | null, db?: CanvasDb): Promise<boolean>;
24
- /** The node ids of one run (its root and every node carrying its `run_id`). */
25
- export declare function runNodeIds(run: string, db?: CanvasDb): Promise<string[]>;
@@ -1,2 +0,0 @@
1
- var s=Object.defineProperty;var n=(t,e)=>s(t,"name",{value:e,configurable:!0});import{openDb as o}from"../canvas/db.js";async function u(t,e){e??=await o();const r=await e.prepare(`SELECT n.run_id, n.isolated, r.isolated AS root_isolated FROM nodes n
2
- LEFT JOIN nodes r ON r.node_id = n.run_id WHERE n.node_id = ?`).get(t);if(!r){const a=await e.prepare("SELECT run_id FROM deleted_isolated_nodes WHERE node_id = ?").get(t);return a?{run:a.run_id,isolated:!0}:null}return{run:r.run_id??t,isolated:r.isolated===1||r.root_isolated===1}}n(u,"runPlace");async function E(t,e){e??=await o();const r=await u(t,e);r?.isolated&&await e.prepare("INSERT INTO deleted_isolated_nodes (node_id, run_id) VALUES (?, ?) ON CONFLICT (node_id) DO UPDATE SET run_id = excluded.run_id").run(t,r.run)}n(E,"rememberDeletedIsolated");async function w(t,e){e??=await o();const r=await e.prepare("SELECT registered_by FROM custom_objects WHERE object = ?").get(t);return r?.registered_by?await u(r.registered_by,e)??{run:r.registered_by,isolated:!1}:null}n(w,"objectPlace");function l(t,e){return t.run===e.run||!t.isolated&&!e.isolated}n(l,"runsSeeEachOther");async function f(t,e,r,a,i){i??=await o();const d=await u(t,i);return d===null?!0:await c(d,e,r,a,i)}n(f,"nodeMayReach");async function c(t,e,r,a,i){if(i??=await o(),(a??"app:terminal")!==e)return!0;const d=await u(r,i);return d===null?!t.isolated:l(t,d)}n(c,"placeMayReach");async function y(t,e){return e??=await o(),(await e.prepare("SELECT node_id FROM nodes WHERE run_id = ? OR node_id = ?").all(t,t)).map(r=>r.node_id)}n(y,"runNodeIds");export{f as nodeMayReach,w as objectPlace,c as placeMayReach,E as rememberDeletedIsolated,y as runNodeIds,u as runPlace,l as runsSeeEachOther};