@immediately-run/preauth-core 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.
@@ -13,7 +13,10 @@ export interface CapabilityDef {
13
13
  * elevated capability can be EARNED by a URL-loaded/previewed app via lazy
14
14
  * first-use or manifest-`requests` consent and recorded as a per-`(user,
15
15
  * appKey)` grant; non-app-scoped elevated caps are never earnable that way
16
- * (region binding only). The app-scoped set is `net:fetch`, `task:invoke`,
16
+ * (region binding only). In core_concepts §5 terms the consent-path is the
17
+ * "above-the-floor, up-to-the-ceiling → first-use consent" band: an app-scoped
18
+ * elevated cap sits in that band for the stage principal, a non-app-scoped one
19
+ * is above the stage ceiling (granted only by a slot's elevated principal). The app-scoped set is `net:fetch`, `task:invoke`,
17
20
  * `contribute:self` (decision #1 — its baseline→elevated reclassification landed
18
21
  * in R3-33d), and `diagnostics:read` (R3-74 / P3-72, D4); the durable grant
19
22
  * participates in the §8.15 90-day expiry like any app-scoped grant. */
@@ -22,8 +25,9 @@ export interface CapabilityDef {
22
25
  * explicit** (scariest) styling, never bundled into a combined prompt
23
26
  * (decision #2). The most dangerous writes carry it: `contribute:direct`
24
27
  * (commit without review) and `editor:write` (mutate the working tree).
25
- * Independent of tier — it governs HOW the line is shown, not WHO may hold the
26
- * capability (a first-party-only cap is still refused to a fork regardless). */
28
+ * Independent of tier — it governs HOW the first-use consent line (core_concepts
29
+ * §5: the above-floor consent band) is shown, not WHO may hold the capability
30
+ * (a first-party-only cap is still refused to a fork regardless of styling). */
27
31
  maximallyExplicit?: boolean;
28
32
  }
29
33
  export declare const CAPABILITIES: Record<Capability, CapabilityDef>;
@@ -31,7 +35,7 @@ export declare const CAPABILITIES: Record<Capability, CapabilityDef>;
31
35
  * provider-agnostic `llm:chat` capability (the `llm.chat@1` slot), mirroring
32
36
  * capabilities.json. (1.2.0 added the per-user settings-space capabilities.) */
33
37
  export declare const REGISTRY_VERSION = "1.3.0";
34
- /** Is `cap` a known kernel capability? (Closed vocabulary — §5.12.) */
38
+ /** Is `cap` a known host-core capability? (Closed vocabulary — §5.12.) */
35
39
  export declare function isKnownCapability(cap: string): cap is Capability;
36
40
  export declare function tierOf(cap: Capability): CapabilityTier;
37
41
  /** Baseline = what the previewed app and any unconsented binding may hold. */
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
- // The capability-definition registry — the KERNEL source of truth
3
- // (UI_AS_APPS_SPEC §5.11 / §8.2). Capabilities are a CLOSED vocabulary: apps
2
+ // The capability-definition registry — the Host-core source of truth
3
+ // (UI_AS_APPS_SPEC §5.11 / §8.2). "Host-core capabilities are a closed,
4
+ // kernel-defined vocabulary an app cannot extend" (core_concepts §5): apps
4
5
  // cannot mint one, only be granted one. This module mirrors docs/capabilities.json
5
6
  // (the machine-readable companion); the host build is authoritative.
6
7
  //
@@ -61,7 +62,7 @@ exports.CAPABILITIES = {
61
62
  // Mutate the editor session's working tree — create/delete/rename/upload a file
62
63
  // (migrate-sidebars Phase 04, EDITOR_AS_APP_SPEC §5.2). A NARROW, per-path gated
63
64
  // action: the file explorer NAMES a path and the HOST performs the COW write
64
- // (and notifies Sandpack) — the COW/journal stays in the kernel (§2/§4). The
65
+ // (and notifies Sandpack) — the COW/journal stays in the Host (§2/§4). The
65
66
  // explorer holds no working-tree write PORT (that broad authority is the
66
67
  // editor app's `editor:document`); it must ask. **Elevated, not first-party-only**
67
68
  // (EDITOR_AS_APP_SPEC §5.1 forkability rule): mutating the user's OWN working copy
@@ -128,9 +129,12 @@ exports.CAPABILITIES = {
128
129
  // / third-party binding can NEVER initiate a cross-app drag, enforced by tier
129
130
  // (`buildConsent` refuses it to a non-first-party binding, never offering a
130
131
  // consent line, exactly like `vcs:reset`). Marked maximally-explicit so the one
131
- // first-party line that carries it renders with the scariest styling (same tier
132
- // as `editor:open`/`editor:write`/`vcs:reset`). Receiving a drop needs NO new
133
- // grant the previewed app opts in by subscribing (`onItemDrop`).
132
+ // first-party line that carries it renders with the scariest styling. (Tier is
133
+ // `first-party-only`, the SAME tier as `vcs:reset` NOT `editor:write`, which is
134
+ // elevated/consentable: S4 in spec-review-3.5 corrected the FILE_EXPLORER prose
135
+ // that wrongly equated this tier with `editor:write`. CAPABILITY_REFERENCE records
136
+ // `dnd:source` as first-party-only, which this dict matches.) Receiving a drop
137
+ // needs NO new grant — the previewed app opts in by subscribing (`onItemDrop`).
134
138
  'dnd:source': { kind: 'action', tier: 'first-party-only', since: '1.2.0', maximallyExplicit: true },
135
139
  // The §5.5 method catalog (the app's own filtered RPC surface) — baseline:
136
140
  // every app may discover what IT can call; the list is grant-filtered so it
@@ -154,8 +158,8 @@ exports.CAPABILITIES = {
154
158
  'secrets:list': { kind: 'read', tier: 'elevated', since: '1.1.0' },
155
159
  'secrets:revoke': { kind: 'action', tier: 'elevated', since: '1.1.0' },
156
160
  // R3-76 (P3-74, LLM_AND_AGENTS_SPEC §3.4/§4; LOCAL_DEV_AUTHED_SERVER_SPEC):
157
- // open and drive a user-local Claude Code via the bridge — the in-browser host
158
- // kernel connects OUT to the CLI's authenticated localhost server and runs each
161
+ // open and drive a user-local Claude Code via the bridge — the in-browser Host
162
+ // connects OUT to the CLI's authenticated localhost server and runs each
159
163
  // tool call through its §8.4-gated invoke(). Promoted from proposed/since:null
160
164
  // to a defined, gated, elevated capability landing in the current 1.2.0
161
165
  // registry — gated host-side by `protocol-agent` (site-main actionGate) and held
@@ -171,7 +175,10 @@ exports.CAPABILITIES = {
171
175
  // diagnostics (no cross-app bleed — enforced host-side by the channel projection).
172
176
  'diagnostics:read': { kind: 'action', tier: 'elevated', since: '1.2.0', appScoped: true },
173
177
  // SERVICE_PROVIDERS_SPEC `llm.chat@1` / LLM_AND_AGENTS_SPEC D5: invoke the shared,
174
- // provider-agnostic chat slot. The app calls ONE slot; the host resolves which
178
+ // provider-agnostic chat slot. ("provider" here = the Service-provider sense
179
+ // an App that provides a Service, core_concepts §6 — and "slot" here = a Service
180
+ // interface, not the UI Slot of core_concepts §3; the names mirror the
181
+ // SERVICE_PROVIDERS surface and are kept.) The app calls ONE slot; the host resolves which
175
182
  // vendor answers from the key the user holds (`SecretView.boundOrigin`) + their
176
183
  // `preferredImplementation` choice, injects the key host-side (§6, look-at-nothing
177
184
  // proxy), and streams normalized deltas back. The app never names a vendor, never
@@ -184,7 +191,7 @@ exports.CAPABILITIES = {
184
191
  * provider-agnostic `llm:chat` capability (the `llm.chat@1` slot), mirroring
185
192
  * capabilities.json. (1.2.0 added the per-user settings-space capabilities.) */
186
193
  exports.REGISTRY_VERSION = '1.3.0';
187
- /** Is `cap` a known kernel capability? (Closed vocabulary — §5.12.) */
194
+ /** Is `cap` a known host-core capability? (Closed vocabulary — §5.12.) */
188
195
  function isKnownCapability(cap) {
189
196
  return Object.prototype.hasOwnProperty.call(exports.CAPABILITIES, cap);
190
197
  }
@@ -17,14 +17,22 @@ export declare const grantKey: (appKey: string, spaceId: string) => string;
17
17
  * use after expiry re-prompts. Baseline needs no grant record, so this never
18
18
  * touches it. */
19
19
  export declare const GRANT_EXPIRY_MS: number;
20
- /** A principal that can be granted access to a space. */
20
+ /** The member doc-ID for a user who can be granted access to a space: `user:<uid>`.
21
+ * This is a **grantee** (a space member — the `uid`/`gid` of `setSpaceRole`), NOT the
22
+ * authority-context Principal (core_concepts §4 reserved-word; SPEC_CODE_DEBT §7.1
23
+ * RENAME-1). The stored Firestore path segment is a doc-ID, not a field literally
24
+ * named `principal`, so this rename is code-symbol-only — no data migration. */
25
+ export declare const granteeId: (uid: string) => string;
26
+ /** @deprecated use {@link granteeId}. Kept as an alias for the `userPrincipal →
27
+ * granteeId` migration (the SDK + site-main + backend RENAME-1 track); removed once
28
+ * consumers migrate. */
21
29
  export declare const userPrincipal: (uid: string) => string;
22
30
  /** Drop undefined values — Firestore rejects them. The two adapters historically
23
31
  * each had their own copy of this; sharing it keeps the "omit absent optionals"
24
32
  * rule identical on both sides. */
25
33
  export declare const defined: <T extends Record<string, unknown>>(obj: T) => T;
26
34
  export declare const spacePath: (spaceId: string) => DocPath;
27
- export declare const memberPath: (spaceId: string, principal: string) => DocPath;
35
+ export declare const memberPath: (spaceId: string, grantee: string) => DocPath;
28
36
  export declare const userSpacePath: (uid: string, spaceId: string) => DocPath;
29
37
  export declare const appKeyPath: (uid: string, appKey: string) => DocPath;
30
38
  export declare const appSpacePath: (uid: string, appKey: string, spaceId: string) => DocPath;
package/dist/docLayout.js CHANGED
@@ -16,7 +16,7 @@
16
16
  // `.set()`/`.update()` is the only thing each adapter does itself. Drift is then
17
17
  // impossible without editing a helper both consume.
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.netFetchGrantFields = exports.mergeNetFetchHosts = exports.appSpaceGrantFields = exports.appKeyTouchFields = exports.appCountFields = exports.userCountFields = exports.ownerUserSpaceFields = exports.ownerMemberFields = exports.spaceDocFields = exports.appCountPath = exports.userCountPath = exports.appSpacePath = exports.appKeyPath = exports.userSpacePath = exports.memberPath = exports.spacePath = exports.defined = exports.userPrincipal = exports.GRANT_EXPIRY_MS = exports.grantKey = void 0;
19
+ exports.netFetchGrantFields = exports.mergeNetFetchHosts = exports.appSpaceGrantFields = exports.appKeyTouchFields = exports.appCountFields = exports.userCountFields = exports.ownerUserSpaceFields = exports.ownerMemberFields = exports.spaceDocFields = exports.appCountPath = exports.userCountPath = exports.appSpacePath = exports.appKeyPath = exports.userSpacePath = exports.memberPath = exports.spacePath = exports.defined = exports.userPrincipal = exports.granteeId = exports.GRANT_EXPIRY_MS = exports.grantKey = void 0;
20
20
  /** Stable per-user identifier for a grant `(appKey, spaceId)`, used as the value
21
21
  * of a delegated grant's `parentGrantId`. `::` is delimiter-safe: `appKey` uses
22
22
  * `__` separators and a Firestore `spaceId` is alphanumeric. */
@@ -26,9 +26,17 @@ exports.grantKey = grantKey;
26
26
  * use after expiry re-prompts. Baseline needs no grant record, so this never
27
27
  * touches it. */
28
28
  exports.GRANT_EXPIRY_MS = 90 * 24 * 60 * 60 * 1000;
29
- /** A principal that can be granted access to a space. */
30
- const userPrincipal = (uid) => `user:${uid}`;
31
- exports.userPrincipal = userPrincipal;
29
+ /** The member doc-ID for a user who can be granted access to a space: `user:<uid>`.
30
+ * This is a **grantee** (a space member — the `uid`/`gid` of `setSpaceRole`), NOT the
31
+ * authority-context Principal (core_concepts §4 reserved-word; SPEC_CODE_DEBT §7.1
32
+ * RENAME-1). The stored Firestore path segment is a doc-ID, not a field literally
33
+ * named `principal`, so this rename is code-symbol-only — no data migration. */
34
+ const granteeId = (uid) => `user:${uid}`;
35
+ exports.granteeId = granteeId;
36
+ /** @deprecated use {@link granteeId}. Kept as an alias for the `userPrincipal →
37
+ * granteeId` migration (the SDK + site-main + backend RENAME-1 track); removed once
38
+ * consumers migrate. */
39
+ exports.userPrincipal = exports.granteeId;
32
40
  /** Drop undefined values — Firestore rejects them. The two adapters historically
33
41
  * each had their own copy of this; sharing it keeps the "omit absent optionals"
34
42
  * rule identical on both sides. */
@@ -37,11 +45,11 @@ exports.defined = defined;
37
45
  // --- document paths (pure, sentinel-free) -----------------------------------
38
46
  const spacePath = (spaceId) => ['spaces', spaceId];
39
47
  exports.spacePath = spacePath;
40
- const memberPath = (spaceId, principal) => [
48
+ const memberPath = (spaceId, grantee) => [
41
49
  'spaces',
42
50
  spaceId,
43
51
  'members',
44
- principal,
52
+ grantee,
45
53
  ];
46
54
  exports.memberPath = memberPath;
47
55
  const userSpacePath = (uid, spaceId) => [
@@ -119,7 +127,7 @@ const appSpaceGrantFields = (params, s) => (0, exports.defined)({
119
127
  grantedAt: s.serverTimestamp(),
120
128
  lastUsedAt: s.serverTimestamp(),
121
129
  name: params.name,
122
- // Plan 12 §8.7: `rules` is authoritative; `subtree`/`mode` are kept as the
130
+ // UI_AS_APPS_SPEC §8.7: `rules` is authoritative; `subtree`/`mode` are kept as the
123
131
  // deprecated `rules[0]` mirror for not-yet-migrated readers. When no rule-set
124
132
  // is given, derive a single-rule set from the legacy scope so the backend
125
133
  // single-scope mint path still emits `rules` (byte-identical with site-main).
package/dist/m1PreAuth.js CHANGED
@@ -7,6 +7,12 @@
7
7
  // so a headless/CI/cron/`immediately-run dev` run finds the grant already present
8
8
  // and boots with NO prompt. It is not a region-repointing registry layer (§3.3):
9
9
  // it only writes the §8.6/§8.7 grant set the gate already reads, so M1 minting
10
+ //
11
+ // ("region-binding-only" below = the UI half of a Slot (core_concepts §3): the
12
+ // Slot's principal confers such a capability as part of being bound, NOT via a
13
+ // consent path (slot occupancy is not a capability, core_concepts §3/§5) — which
14
+ // is exactly why a URL-loaded appKey, which CANNOT pick its slot, can never EARN a
15
+ // broad-elevated cap, only the app-scoped consent-path caps below.)
10
16
  // flows through the ONE existing mint path (`mintConsentedGrants`, stamped
11
17
  // `mintPath:'policy'`) and cannot drift from M3.
12
18
  //
package/dist/port.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /** The filesystem scope a grant confers (UI_AS_APPS_SPEC §8.7). Absent fields
2
2
  * mean whole-space, read-write. */
3
3
  export type GrantMode = 'ro' | 'rw';
4
- /** One granted scope within a mount (UI_AS_APPS_SPEC §8.7, plan 12): an absolute
4
+ /** One granted scope within a mount (UI_AS_APPS_SPEC §8.7): an absolute
5
5
  * `subtree` in the backing fs and the access `mode` there. A grant carries a SET
6
6
  * of these (`rules`); the most specific (longest-prefix) rule governs a path. The
7
7
  * wire shape, so both mint adapters write byte-identical `rules` arrays. */
@@ -47,7 +47,7 @@ export interface GrantSpaceParams {
47
47
  spaceId: string;
48
48
  subtree?: string;
49
49
  mode?: GrantMode;
50
- /** Plan 12 §8.7: the FULL rule-set to write (≥1). When given it is authoritative
50
+ /** UI_AS_APPS_SPEC §8.7: the FULL rule-set to write (≥1). When given it is authoritative
51
51
  * (site-main's read-modify-merge passes the merged set); when omitted the grant
52
52
  * doc derives a single-rule `[{ subtree ?? '/', mode ?? 'rw' }]` from the legacy
53
53
  * `subtree`/`mode` (the backend single-scope path), so both adapters emit `rules`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@immediately-run/preauth-core",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "The shared §8.9 pre-auth target check + the single grant-mint path (mintConsentedGrants) + the capability vocabulary + the byte-faithful grant/space/net-fetch document layout. Consumed by site-main (browser Firestore) and the backend (admin Firestore) so there is ONE gate, ONE mint path, ONE wire layout.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {