@immediately-run/preauth-core 0.1.8 → 0.1.9
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/docLayout.d.ts +32 -1
- package/dist/docLayout.js +43 -3
- package/package.json +1 -1
package/dist/docLayout.d.ts
CHANGED
|
@@ -37,6 +37,32 @@ export interface ParsedGrantKey {
|
|
|
37
37
|
* (first + last), so the cascade fails safe (child self-revokes) rather than
|
|
38
38
|
* crashing. */
|
|
39
39
|
export declare const parseGrantKey: (key: string) => ParsedGrantKey;
|
|
40
|
+
/** The doc-id delimiter between a qualifying principal and the spaceId. Safe: a
|
|
41
|
+
* named principal is lowercase-dotted/hyphenated (CA-3 reserves `~`) and a
|
|
42
|
+
* Firestore spaceId is alphanumeric, so `~` appears in NEITHER — a single,
|
|
43
|
+
* unambiguous split point. */
|
|
44
|
+
export declare const GRANT_DOCID_DELIM = "~";
|
|
45
|
+
/** Build a space-grant doc-id (design 05a §3.1 step 2). Pass the QUALIFYING named
|
|
46
|
+
* principal to get `${principal}~${spaceId}`; pass `undefined` (stage / legacy /
|
|
47
|
+
* no principal) for the bare `spaceId`. The caller resolves "does this principal
|
|
48
|
+
* qualify" (site-main maps stage/legacy → undefined) so this stays a pure string
|
|
49
|
+
* builder with no sentinel knowledge. */
|
|
50
|
+
export declare const grantDocId: (spaceId: string, qualifyingPrincipal?: string) => string;
|
|
51
|
+
/** A parsed grant doc-id — the §3.5 reader-parse discipline. `principal` is set
|
|
52
|
+
* only for a QUALIFIED (`${principal}~${spaceId}`) id; a bare id (a stage/legacy
|
|
53
|
+
* grant) yields `{ spaceId }` with `principal` undefined. */
|
|
54
|
+
export interface ParsedGrantDocId {
|
|
55
|
+
/** The qualifying principal, or undefined for a bare (stage/legacy) doc-id. */
|
|
56
|
+
principal?: string;
|
|
57
|
+
spaceId: string;
|
|
58
|
+
}
|
|
59
|
+
/** Parse a space-grant doc-id back into `{ principal?, spaceId }` — the §3.5
|
|
60
|
+
* reader-parse discipline every app-space-grant collection reader routes `d.id`
|
|
61
|
+
* through so it never mistakes `${principal}~${spaceId}` for a bare spaceId (which
|
|
62
|
+
* would corrupt the derived `mountId` and leak grants across principals). Splits
|
|
63
|
+
* on the FIRST delimiter; a named principal never contains `~`, so this recovers
|
|
64
|
+
* the exact principal + spaceId. A bare id (no delimiter) ⇒ `{ spaceId }`. */
|
|
65
|
+
export declare const parseGrantDocId: (docId: string) => ParsedGrantDocId;
|
|
40
66
|
/** Durable elevated/app-scoped grants expire after 90 days WITHOUT USE; first
|
|
41
67
|
* use after expiry re-prompts. Baseline needs no grant record, so this never
|
|
42
68
|
* touches it. */
|
|
@@ -55,7 +81,12 @@ export declare const spacePath: (spaceId: string) => DocPath;
|
|
|
55
81
|
export declare const memberPath: (spaceId: string, grantee: string) => DocPath;
|
|
56
82
|
export declare const userSpacePath: (uid: string, spaceId: string) => DocPath;
|
|
57
83
|
export declare const appKeyPath: (uid: string, appKey: string) => DocPath;
|
|
58
|
-
|
|
84
|
+
/** `user-app-spaces/{uid}/apps/{appKey}/spaces/{docId}` — the durable §8.7 grant
|
|
85
|
+
* doc. R3-98 S5: the doc-id is principal-qualified — pass the QUALIFYING named
|
|
86
|
+
* principal for `${principal}~${spaceId}`, or omit it (stage / legacy) for the
|
|
87
|
+
* bare `spaceId`. Backward-compatible: a 3-arg call (no principal) yields exactly
|
|
88
|
+
* the pre-S5 path, so the backend/CLI stage mint is byte-identical. */
|
|
89
|
+
export declare const appSpacePath: (uid: string, appKey: string, spaceId: string, qualifyingPrincipal?: string) => DocPath;
|
|
59
90
|
export declare const userCountPath: (uid: string) => DocPath;
|
|
60
91
|
export declare const appCountPath: (uid: string, appKey: string) => DocPath;
|
|
61
92
|
/** `spaces/{spaceId}` — the root doc (written WITHOUT merge). */
|
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.appCapabilitiesGrantFields = exports.mergeCapabilities = 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.granteeId = exports.GRANT_EXPIRY_MS = exports.parseGrantKey = exports.grantKeyWithPrincipal = exports.grantKey = void 0;
|
|
19
|
+
exports.appCapabilitiesGrantFields = exports.mergeCapabilities = 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.granteeId = exports.GRANT_EXPIRY_MS = exports.parseGrantDocId = exports.grantDocId = exports.GRANT_DOCID_DELIM = exports.parseGrantKey = exports.grantKeyWithPrincipal = 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. */
|
|
@@ -45,6 +45,41 @@ const parseGrantKey = (key) => {
|
|
|
45
45
|
return { appKey: parts[0], spaceId: parts[parts.length - 1] };
|
|
46
46
|
};
|
|
47
47
|
exports.parseGrantKey = parseGrantKey;
|
|
48
|
+
// --- R3-98 S5 — the principal-qualified space-grant doc-id (design 05a §3.1/§3.5) --
|
|
49
|
+
//
|
|
50
|
+
// A space grant's Firestore doc-id encodes the named principal it was minted
|
|
51
|
+
// under, so two principals granting the SAME space live at DIFFERENT docs and are
|
|
52
|
+
// invisible to each other (structural disjointness). The rule (design 05a §3.1
|
|
53
|
+
// step 2): a **qualifying** (real, named) principal → `${principal}~${spaceId}`;
|
|
54
|
+
// the **stage** principal, a **legacy** (no-principal) grant, or none → the bare
|
|
55
|
+
// `spaceId`, so no existing/stage doc ever moves. This module is GRAMMAR ONLY: the
|
|
56
|
+
// caller decides which principals qualify (site-main owns the stage/legacy
|
|
57
|
+
// sentinels — a principal it treats as non-qualifying is passed as `undefined`).
|
|
58
|
+
/** The doc-id delimiter between a qualifying principal and the spaceId. Safe: a
|
|
59
|
+
* named principal is lowercase-dotted/hyphenated (CA-3 reserves `~`) and a
|
|
60
|
+
* Firestore spaceId is alphanumeric, so `~` appears in NEITHER — a single,
|
|
61
|
+
* unambiguous split point. */
|
|
62
|
+
exports.GRANT_DOCID_DELIM = '~';
|
|
63
|
+
/** Build a space-grant doc-id (design 05a §3.1 step 2). Pass the QUALIFYING named
|
|
64
|
+
* principal to get `${principal}~${spaceId}`; pass `undefined` (stage / legacy /
|
|
65
|
+
* no principal) for the bare `spaceId`. The caller resolves "does this principal
|
|
66
|
+
* qualify" (site-main maps stage/legacy → undefined) so this stays a pure string
|
|
67
|
+
* builder with no sentinel knowledge. */
|
|
68
|
+
const grantDocId = (spaceId, qualifyingPrincipal) => qualifyingPrincipal ? `${qualifyingPrincipal}${exports.GRANT_DOCID_DELIM}${spaceId}` : spaceId;
|
|
69
|
+
exports.grantDocId = grantDocId;
|
|
70
|
+
/** Parse a space-grant doc-id back into `{ principal?, spaceId }` — the §3.5
|
|
71
|
+
* reader-parse discipline every app-space-grant collection reader routes `d.id`
|
|
72
|
+
* through so it never mistakes `${principal}~${spaceId}` for a bare spaceId (which
|
|
73
|
+
* would corrupt the derived `mountId` and leak grants across principals). Splits
|
|
74
|
+
* on the FIRST delimiter; a named principal never contains `~`, so this recovers
|
|
75
|
+
* the exact principal + spaceId. A bare id (no delimiter) ⇒ `{ spaceId }`. */
|
|
76
|
+
const parseGrantDocId = (docId) => {
|
|
77
|
+
const i = docId.indexOf(exports.GRANT_DOCID_DELIM);
|
|
78
|
+
return i === -1
|
|
79
|
+
? { spaceId: docId }
|
|
80
|
+
: { principal: docId.slice(0, i), spaceId: docId.slice(i + 1) };
|
|
81
|
+
};
|
|
82
|
+
exports.parseGrantDocId = parseGrantDocId;
|
|
48
83
|
/** Durable elevated/app-scoped grants expire after 90 days WITHOUT USE; first
|
|
49
84
|
* use after expiry re-prompts. Baseline needs no grant record, so this never
|
|
50
85
|
* touches it. */
|
|
@@ -85,13 +120,18 @@ const appKeyPath = (uid, appKey) => [
|
|
|
85
120
|
appKey,
|
|
86
121
|
];
|
|
87
122
|
exports.appKeyPath = appKeyPath;
|
|
88
|
-
|
|
123
|
+
/** `user-app-spaces/{uid}/apps/{appKey}/spaces/{docId}` — the durable §8.7 grant
|
|
124
|
+
* doc. R3-98 S5: the doc-id is principal-qualified — pass the QUALIFYING named
|
|
125
|
+
* principal for `${principal}~${spaceId}`, or omit it (stage / legacy) for the
|
|
126
|
+
* bare `spaceId`. Backward-compatible: a 3-arg call (no principal) yields exactly
|
|
127
|
+
* the pre-S5 path, so the backend/CLI stage mint is byte-identical. */
|
|
128
|
+
const appSpacePath = (uid, appKey, spaceId, qualifyingPrincipal) => [
|
|
89
129
|
'user-app-spaces',
|
|
90
130
|
uid,
|
|
91
131
|
'apps',
|
|
92
132
|
appKey,
|
|
93
133
|
'spaces',
|
|
94
|
-
spaceId,
|
|
134
|
+
(0, exports.grantDocId)(spaceId, qualifyingPrincipal),
|
|
95
135
|
];
|
|
96
136
|
exports.appSpacePath = appSpacePath;
|
|
97
137
|
const userCountPath = (uid) => ['space-counts', uid];
|
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.9",
|
|
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": {
|