@immediately-run/preauth-core 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities.d.ts +14 -9
- package/dist/capabilities.js +29 -14
- package/dist/docLayout.d.ts +10 -2
- package/dist/docLayout.js +15 -7
- package/dist/m1PreAuth.js +6 -0
- package/dist/port.d.ts +2 -2
- package/package.json +1 -1
package/dist/capabilities.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type CapabilityKind = 'read' | 'action';
|
|
2
2
|
export type CapabilityTier = 'baseline' | 'elevated' | 'first-party-only';
|
|
3
|
-
export type Capability = 'theme:read' | 'theme:set' | 'auth:status' | 'auth:identity' | 'route:read' | 'formFactor:read' | 'mounts:read' | 'spaces:app' | 'spaces:user' | 'spaces:admin' | 'settings:app' | 'settings:fork' | 'settings:all' | 'contribute:self' | 'contribute:any' | 'contribute:direct' | 'editor:read' | 'editor:open' | 'editor:write' | 'editor:document' | 'editor:requestEdit' | 'vcs:read' | 'vcs:reset' | 'dnd:source' | 'catalog:read' | 'commands:read' | 'commands:run' | 'ipc' | 'task:invoke' | 'net:fetch' | 'secrets:add' | 'secrets:list' | 'secrets:revoke' | 'agent:session' | 'diagnostics:read' | 'llm:chat';
|
|
3
|
+
export type Capability = 'theme:read' | 'theme:set' | 'auth:status' | 'auth:identity' | 'route:read' | 'formFactor:read' | 'mounts:read' | 'spaces:app' | 'spaces:user' | 'spaces:admin' | 'settings:app' | 'settings:fork' | 'settings:all' | 'contribute:self' | 'contribute:any' | 'contribute:direct' | 'editor:read' | 'editor:open' | 'editor:write' | 'editor:document' | 'editor:requestEdit' | 'vcs:read' | 'vcs:reset' | 'dnd:source' | 'catalog:read' | 'commands:read' | 'commands:run' | 'ipc' | 'task:invoke' | 'net:fetch' | 'secrets:add' | 'secrets:list' | 'secrets:revoke' | 'agent:session' | 'diagnostics:read' | 'llm:chat' | 'authoring:run';
|
|
4
4
|
export interface CapabilityDef {
|
|
5
5
|
kind: CapabilityKind;
|
|
6
6
|
tier: CapabilityTier;
|
|
@@ -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).
|
|
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,16 +25,18 @@ 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
|
|
26
|
-
*
|
|
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>;
|
|
30
|
-
/** The current registry/vocabulary version (§5.11). Bumped to 1.
|
|
31
|
-
*
|
|
32
|
-
* capabilities.json. (1.
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
/** The current registry/vocabulary version (§5.11). Bumped to 1.4.0 with the
|
|
35
|
+
* `authoring:run` capability (the kernel authoring services — CLIENT_SERVICES §6,
|
|
36
|
+
* R3-107), mirroring capabilities.json. (1.3.0 added the provider-agnostic
|
|
37
|
+
* `llm:chat` slot; 1.2.0 added the per-user settings-space capabilities.) */
|
|
38
|
+
export declare const REGISTRY_VERSION = "1.4.0";
|
|
39
|
+
/** Is `cap` a known host-core capability? (Closed vocabulary — §5.12.) */
|
|
35
40
|
export declare function isKnownCapability(cap: string): cap is Capability;
|
|
36
41
|
export declare function tierOf(cap: Capability): CapabilityTier;
|
|
37
42
|
/** Baseline = what the previewed app and any unconsented binding may hold. */
|
package/dist/capabilities.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// The capability-definition registry — the
|
|
3
|
-
// (UI_AS_APPS_SPEC §5.11 / §8.2).
|
|
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
|
|
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 (
|
|
132
|
-
// as `
|
|
133
|
-
//
|
|
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
|
|
158
|
-
//
|
|
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.
|
|
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
|
|
@@ -179,12 +186,20 @@ exports.CAPABILITIES = {
|
|
|
179
186
|
// Elevated + app-scoped: a fork/previewed app EARNS it via lazy/manifest consent
|
|
180
187
|
// (the fork-needs-more-caps story), recorded as a per-(user,appKey) §8.15 grant.
|
|
181
188
|
'llm:chat': { kind: 'action', tier: 'elevated', since: '1.3.0', appScoped: true },
|
|
189
|
+
// Authoring services (CLIENT_SERVICES_SPEC §6, R3-107): typecheck/lint/format
|
|
190
|
+
// source via a kernel-owned same-origin worker (the in-browser coding agent's
|
|
191
|
+
// quality tools, LLM_AND_AGENTS §3.3). Baseline action — the worker only
|
|
192
|
+
// transforms data the app already holds and returns diagnostics, runs under host
|
|
193
|
+
// authority with nothing to confine (§3a), and is bounded per call (timeout +
|
|
194
|
+
// input-size). Not app-scoped: it confers no authority over other apps/mounts.
|
|
195
|
+
'authoring:run': { kind: 'action', tier: 'baseline', since: '1.4.0' },
|
|
182
196
|
};
|
|
183
|
-
/** The current registry/vocabulary version (§5.11). Bumped to 1.
|
|
184
|
-
*
|
|
185
|
-
* capabilities.json. (1.
|
|
186
|
-
|
|
187
|
-
|
|
197
|
+
/** The current registry/vocabulary version (§5.11). Bumped to 1.4.0 with the
|
|
198
|
+
* `authoring:run` capability (the kernel authoring services — CLIENT_SERVICES §6,
|
|
199
|
+
* R3-107), mirroring capabilities.json. (1.3.0 added the provider-agnostic
|
|
200
|
+
* `llm:chat` slot; 1.2.0 added the per-user settings-space capabilities.) */
|
|
201
|
+
exports.REGISTRY_VERSION = '1.4.0';
|
|
202
|
+
/** Is `cap` a known host-core capability? (Closed vocabulary — §5.12.) */
|
|
188
203
|
function isKnownCapability(cap) {
|
|
189
204
|
return Object.prototype.hasOwnProperty.call(exports.CAPABILITIES, cap);
|
|
190
205
|
}
|
package/dist/docLayout.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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,
|
|
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
|
-
/**
|
|
30
|
-
|
|
31
|
-
|
|
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,
|
|
48
|
+
const memberPath = (spaceId, grantee) => [
|
|
41
49
|
'spaces',
|
|
42
50
|
spaceId,
|
|
43
51
|
'members',
|
|
44
|
-
|
|
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
|
-
//
|
|
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
|
|
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
|
-
/**
|
|
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.
|
|
3
|
+
"version": "0.1.4",
|
|
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": {
|