permdock 0.14.0 → 0.16.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.
- package/dist/{adoption-scan-BGtwGfoH.js → adoption-scan-C2BCiUEG.js} +1 -1
- package/dist/{arazzo-Bol9OgF-.js → arazzo-CHoYnQXO.js} +1 -1
- package/dist/{arazzo-9uhbmKf5.js → arazzo-ClYz2Z0W.js} +1 -1
- package/dist/better-supabase/index.d.ts +6 -2
- package/dist/{better-supabase-83Gsetrv.js → better-supabase-Dirf_8Ec.js} +20 -4
- package/dist/{casbin-CBXD5rFx.js → casbin-C9EvElBb.js} +1 -1
- package/dist/{casbin-1PVgMHOR.js → casbin-D_rVQ31U.js} +1 -1
- package/dist/cli/bin.js +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/{cloud-BfJVKpcN.js → cloud-DdaJ7ILM.js} +1 -1
- package/dist/{codemod-DWfH-KHk.js → codemod-B1USJS7a.js} +2 -2
- package/dist/{codemod-BXLd4K3j.js → codemod-ammy6wv4.js} +1 -1
- package/dist/{collect-lZgCKMe_.js → collect-DnXL4B8c.js} +1 -1
- package/dist/{completion-fJ19i8Jk.js → completion--Y4YItFZ.js} +1 -1
- package/dist/{config-BYSk3iKV.js → config-BQ77xMZk.js} +1 -1
- package/dist/{config-ZZdtyQZy.js → config-CcLlvEYW.js} +2 -2
- package/dist/{config-report-BpztJ3HP.js → config-report-DVMOLJ7F.js} +1 -1
- package/dist/{doctor-NxCr_hba.js → doctor-CwYc2lJb.js} +2 -2
- package/dist/{doctor-eNc7A_7I.js → doctor-D1Xnmy6u.js} +12 -11
- package/dist/{import-efm6qPgx.js → import-Dfe2unKO.js} +1 -1
- package/dist/{init-D6rpLPwM.js → init-BUo2G-FI.js} +1 -1
- package/dist/{init-BtWY1L0J.js → init-C6cWP3xW.js} +3 -3
- package/dist/{login-cLflB63Z.js → login-D1MHOomI.js} +1 -1
- package/dist/{login-B8s6VI8Z.js → login-DCKE5pVy.js} +3 -3
- package/dist/{manifest-BWIR_EEB.js → manifest-Cft51TLK.js} +30 -30
- package/dist/mcp/index.d.ts +15 -6
- package/dist/mcp/index.js +43 -16
- package/dist/next/plugin.js +1 -1
- package/dist/{openapi-CT55v3WD.js → openapi-BwWkHxvW.js} +2 -2
- package/dist/{openapi-DDENzRbG.js → openapi-DSzQN7Zu.js} +1 -1
- package/dist/{output-3iB3_Hfg.js → output-DlICTjBh.js} +1 -1
- package/dist/powersync-0QVP_DuR.js +1 -0
- package/dist/{powersync-DVbskWD9.js → powersync-CBhTBhG2.js} +1 -1
- package/dist/{powersync-COjQTHRD.js → powersync-DAfo0EL5.js} +2 -2
- package/dist/pull-CCAChKuy.js +1 -0
- package/dist/{pull-Er4aBHlL.js → pull-CQCGy1gv.js} +1 -1
- package/dist/react-native/index.d.ts +14 -1
- package/dist/react-native/index.js +46 -1
- package/dist/{rls-DjjOHlKE.js → rls-C5ZGzR_B.js} +1 -1
- package/dist/{rls-DY3Fc18U.js → rls-tHu7N_Pe.js} +4 -4
- package/dist/run-C5P3x1EI.js +1 -0
- package/dist/{run-BlxXmaDS.js → run-DUq1xU4K.js} +3 -3
- package/dist/{scan-CR_xm71k.js → scan-C3HRH9Fs.js} +1 -1
- package/dist/{schema-CnrIP94n.js → schema-DvXvxPhQ.js} +1 -1
- package/dist/{skills-uzsVqEi9.js → skills-B2qTbaQa.js} +1 -1
- package/dist/{skills-CY-MY_Oj.js → skills-Celu2W6v.js} +1 -1
- package/dist/{supautils-DZ95xxW-.js → supautils-SwE642N1.js} +22 -9
- package/dist/unplugin/index.js +1 -1
- package/dist/{usage-WYRc7Kqg.js → usage-CPXeuAdT.js} +2 -2
- package/dist/{usage-Dm2hn0pS.js → usage-CfZCQd0F.js} +1 -1
- package/dist/usage-DmmO_xjJ.js +1 -0
- package/dist/{verify-CHQgLrtS.js → verify-DfT0QYNh.js} +1 -1
- package/dist/watch-CuPz0D2M.js +1 -0
- package/dist/{watch-CTfSlIGD.js → watch-DAkjm75Y.js} +1 -1
- package/package.json +1 -1
- package/skills/permdock-data/references/queries-and-rls.md +1 -1
- package/dist/powersync-k8lUeC37.js +0 -1
- package/dist/pull-BY1METGf.js +0 -1
- package/dist/run-DGSLvGty.js +0 -1
- package/dist/usage-CH7oISI6.js +0 -1
- package/dist/watch-C44FtM79.js +0 -1
package/dist/mcp/index.d.ts
CHANGED
|
@@ -112,15 +112,24 @@ type McpProcedureEnforcement = {
|
|
|
112
112
|
readonly permissionFor: (name: string) => Permission | undefined;
|
|
113
113
|
readonly oauthScopesFor?: (name: string) => readonly string[] | undefined;
|
|
114
114
|
};
|
|
115
|
+
/** What an `onError` sink receives next to the thrown error. */
|
|
116
|
+
type McpErrorContext = {
|
|
117
|
+
/** The key of the permission being checked. */
|
|
118
|
+
readonly permission: string | null;
|
|
119
|
+
/** The tool, resource or prompt name. */
|
|
120
|
+
readonly name: string;
|
|
121
|
+
/**
|
|
122
|
+
* The tenant the `tenant` option resolves for the call, or `null` when it
|
|
123
|
+
* resolves none or throws.
|
|
124
|
+
*/
|
|
125
|
+
readonly tenant: string | null;
|
|
126
|
+
};
|
|
115
127
|
/**
|
|
116
128
|
* Receives an error a check threw: a loader, `decide`, an approval input or a
|
|
117
129
|
* subject a list cannot build. The call still refuses; a sink that throws is
|
|
118
|
-
* ignored.
|
|
130
|
+
* ignored. A `BetterSupabaseOnError` from `permdock/better-supabase` fits.
|
|
119
131
|
*/
|
|
120
|
-
type McpOnError = (error: unknown, context:
|
|
121
|
-
readonly permission: string | null;
|
|
122
|
-
readonly name: string;
|
|
123
|
-
}) => void;
|
|
132
|
+
type McpOnError = (error: unknown, context: McpErrorContext) => void;
|
|
124
133
|
type McpPermDockOptions<TUser = unknown> = InstanceOptions & {
|
|
125
134
|
/**
|
|
126
135
|
* Receives the verified auth info, or `{}` on a transport without one
|
|
@@ -299,4 +308,4 @@ type McpSubjectOptions = Pick<JwtSubjectOptions, "claims" | "groupRoles" | "sche
|
|
|
299
308
|
*/
|
|
300
309
|
export declare function subjectFromMcp(authInfo: McpAuthInfo | undefined, options?: McpSubjectOptions): Subject<McpPrincipal>;
|
|
301
310
|
//#endregion
|
|
302
|
-
export type { DeniedText, DeniedTextEvent, GuardedMcpServer, McpAuthInfo, McpOnError, McpPermDock, McpPermDockOptions, McpPrincipal, McpProcedureEnforcement, McpProcedureToolConfig, McpPromptConfig, McpResourceConfig, McpResourceGuardOptions, McpResourceGuardResult, McpSubjectOptions, McpToolConfig, McpUiResourceConfig, ProcedureMcpServer, ProtectedResourceMetadataOptions };
|
|
311
|
+
export type { DeniedText, DeniedTextEvent, GuardedMcpServer, McpAuthInfo, McpErrorContext, McpOnError, McpPermDock, McpPermDockOptions, McpPrincipal, McpProcedureEnforcement, McpProcedureToolConfig, McpPromptConfig, McpResourceConfig, McpResourceGuardOptions, McpResourceGuardResult, McpSubjectOptions, McpToolConfig, McpUiResourceConfig, ProcedureMcpServer, ProtectedResourceMetadataOptions };
|
package/dist/mcp/index.js
CHANGED
|
@@ -222,6 +222,15 @@ function report(sink, error, context) {
|
|
|
222
222
|
sink(error, context);
|
|
223
223
|
} catch {}
|
|
224
224
|
}
|
|
225
|
+
/** The call's tenant for an error report; `null` when it has none or throws. */
|
|
226
|
+
async function reportedTenant(tenant, authInfo) {
|
|
227
|
+
if (typeof tenant !== "function") return tenant ?? null;
|
|
228
|
+
try {
|
|
229
|
+
return await tenant(authInfo ?? {}) ?? null;
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
225
234
|
//#endregion
|
|
226
235
|
//#region src/mcp/call-check.ts
|
|
227
236
|
function reachOf(policy, permission, declared) {
|
|
@@ -264,16 +273,11 @@ function credentialRefusal(checks, permission, reach, authInfo) {
|
|
|
264
273
|
* The completion re-check of a long-running tool: the call must still be
|
|
265
274
|
* allowed, or approved with the same token.
|
|
266
275
|
*/
|
|
267
|
-
async function recheck(checks, binding, args, call, permission, approved, tool,
|
|
276
|
+
async function recheck(checks, binding, args, call, permission, approved, tool, onError) {
|
|
268
277
|
const rechecked = await checks.kernel.check(binding, args, call, compact({
|
|
269
278
|
simulate: true,
|
|
270
279
|
tool,
|
|
271
|
-
onError
|
|
272
|
-
report(checks.onError, error, {
|
|
273
|
-
permission: permission.key,
|
|
274
|
-
name
|
|
275
|
-
});
|
|
276
|
-
}
|
|
280
|
+
onError
|
|
277
281
|
}));
|
|
278
282
|
if (!rechecked.ok) return {
|
|
279
283
|
ok: false,
|
|
@@ -289,14 +293,33 @@ async function recheck(checks, binding, args, call, permission, approved, tool,
|
|
|
289
293
|
} : plainRefusal(permission, `Denied: ${permission.key} was revoked before the call completed.`, {})
|
|
290
294
|
};
|
|
291
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Sends the errors a check collected to the `onError` sink, after the check, so
|
|
298
|
+
* the tenant resolves only when there is something to report.
|
|
299
|
+
*/
|
|
300
|
+
async function flush(checks, authInfo, errors, permission, name) {
|
|
301
|
+
if (errors.length === 0 || checks.onError === void 0) return;
|
|
302
|
+
const tenant = await reportedTenant(checks.options.tenant, authInfo);
|
|
303
|
+
for (const error of errors) report(checks.onError, error, {
|
|
304
|
+
permission,
|
|
305
|
+
name,
|
|
306
|
+
tenant
|
|
307
|
+
});
|
|
308
|
+
}
|
|
292
309
|
async function decideCall(checks, permission, reach, args, load, context, handlerContext, capabilities, completion, tool, name = tool ?? permission.key) {
|
|
293
310
|
const authInfo = context.http?.authInfo;
|
|
311
|
+
const errors = [];
|
|
294
312
|
const onError = (error) => {
|
|
295
|
-
|
|
296
|
-
permission: permission.key,
|
|
297
|
-
name
|
|
298
|
-
});
|
|
313
|
+
errors.push(error);
|
|
299
314
|
};
|
|
315
|
+
try {
|
|
316
|
+
return await decided(checks, permission, reach, args, load, context, handlerContext, capabilities, completion, tool, onError);
|
|
317
|
+
} finally {
|
|
318
|
+
await flush(checks, authInfo, errors, permission.key, name);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async function decided(checks, permission, reach, args, load, context, handlerContext, capabilities, completion, tool, onError) {
|
|
322
|
+
const authInfo = context.http?.authInfo;
|
|
300
323
|
const refused = credentialRefusal(checks, permission, reach, authInfo);
|
|
301
324
|
if (refused !== void 0) return {
|
|
302
325
|
ok: false,
|
|
@@ -307,7 +330,7 @@ async function decideCall(checks, permission, reach, args, load, context, handle
|
|
|
307
330
|
data: load === void 0 ? void 0 : () => load()
|
|
308
331
|
});
|
|
309
332
|
const call = compact({ authInfo });
|
|
310
|
-
if (completion !== void 0) return recheck(checks, binding, args, call, permission, completion.approved, tool,
|
|
333
|
+
if (completion !== void 0) return recheck(checks, binding, args, call, permission, completion.approved, tool, onError);
|
|
311
334
|
const checked = await checks.kernel.check(binding, args, call, compact({
|
|
312
335
|
resumeToken: approvalTokenOf(context),
|
|
313
336
|
tool,
|
|
@@ -393,10 +416,14 @@ async function visible(checks, context, permissionOf, keys, declaredOf = () => v
|
|
|
393
416
|
try {
|
|
394
417
|
permdock = await checks.kernel.instance(compact({ authInfo }));
|
|
395
418
|
} catch (error) {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
419
|
+
if (checks.onError !== void 0) {
|
|
420
|
+
const tenant = await reportedTenant(checks.options.tenant, authInfo);
|
|
421
|
+
for (const entry of guarded) report(checks.onError, error, {
|
|
422
|
+
permission: entry.permission.key,
|
|
423
|
+
name: entry.key,
|
|
424
|
+
tenant
|
|
425
|
+
});
|
|
426
|
+
}
|
|
400
427
|
return shown;
|
|
401
428
|
}
|
|
402
429
|
for (const entry of guarded) if ((!tools || actorMayCallTool(permdock.subject.actor, entry.key)) && permdock.mayUse(entry.permission)) shown.add(entry.key);
|
package/dist/next/plugin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as describeError } from "../errors-Vpu6rKHl.js";
|
|
2
|
-
import { n as createCollectScheduler, r as report, t as collectOnce } from "../watch-
|
|
2
|
+
import { n as createCollectScheduler, r as report, t as collectOnce } from "../watch-DAkjm75Y.js";
|
|
3
3
|
//#region src/cli/plugin.ts
|
|
4
4
|
const PHASE_BUILD = "phase-production-build";
|
|
5
5
|
const PHASE_DEV = "phase-development-server";
|
|
@@ -80,7 +80,7 @@ const emit = defineLeaf({
|
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
async run(ctx, { flags }) {
|
|
83
|
-
return (await import("./openapi-
|
|
83
|
+
return (await import("./openapi-DSzQN7Zu.js")).runOpenapi({
|
|
84
84
|
cwd: ctx.cwd,
|
|
85
85
|
config: ctx.config,
|
|
86
86
|
rest: ["emit"],
|
|
@@ -122,7 +122,7 @@ const importDocument = defineLeaf({
|
|
|
122
122
|
async run(ctx, { flags }) {
|
|
123
123
|
const doc = given(flags.doc);
|
|
124
124
|
if (doc === void 0) throw missingInput("openapi import", ["--doc"], "the OpenAPI document to import");
|
|
125
|
-
return (await import("./import-
|
|
125
|
+
return (await import("./import-Dfe2unKO.js")).runOpenapiImport({
|
|
126
126
|
cwd: ctx.cwd,
|
|
127
127
|
doc,
|
|
128
128
|
out: fileOut("openapi import", flags.out),
|
|
@@ -7,7 +7,7 @@ import { a as loadModule, n as asPolicy, s as pickNamed, t as asPermissionTree }
|
|
|
7
7
|
import { t as shortDiff } from "./text-diff-BtfSmdUo.js";
|
|
8
8
|
import { c as openapiVersion, o as createPermDock } from "./openapi-BOsx0xn9.js";
|
|
9
9
|
import { i as fileDrift } from "./output-files-BIQ_9pIs.js";
|
|
10
|
-
import { n as validateOverlay, t as validateOpenapi } from "./schema-
|
|
10
|
+
import { n as validateOverlay, t as validateOpenapi } from "./schema-DvXvxPhQ.js";
|
|
11
11
|
import { existsSync } from "node:fs";
|
|
12
12
|
import { resolve } from "node:path";
|
|
13
13
|
//#region src/cli/openapi/openapi.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { s as cliVersion } from "./version-DMQ0dnN5.js";
|
|
2
|
-
import { t as DOCS_BASE } from "./manifest-
|
|
2
|
+
import { t as DOCS_BASE } from "./manifest-Cft51TLK.js";
|
|
3
3
|
//#region src/cli/core/output.ts
|
|
4
4
|
const CLI_RESULT_SCHEMA = "https://permdock.com/schemas/cli-result-v1.json";
|
|
5
5
|
function envelope(input) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { n as runPowerSync } from "./powersync-CBhTBhG2.js";
|
|
@@ -19,7 +19,7 @@ import { n as tableNameOf, r as tableNames } from "./tables-DimBcVWY.js";
|
|
|
19
19
|
import { d as andConditions, l as collectGrants, o as assignableRoles, p as contextRefs, t as ownershipRules, u as roleNames } from "./ownership-qqBuGJXr.js";
|
|
20
20
|
import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
|
|
21
21
|
import { n as pgConnector } from "./pg-DQTqRrou.js";
|
|
22
|
-
import { m as tableFor, t as canFixture } from "./verify-
|
|
22
|
+
import { m as tableFor, t as canFixture } from "./verify-DfT0QYNh.js";
|
|
23
23
|
import { resolve } from "node:path";
|
|
24
24
|
//#region src/cli/powersync/names.ts
|
|
25
25
|
function ident(name) {
|
|
@@ -14,7 +14,7 @@ const generate = defineLeaf({
|
|
|
14
14
|
async run(ctx, { flags }) {
|
|
15
15
|
const out = fileOut("powersync", flags.out);
|
|
16
16
|
const from = given(flags.policy);
|
|
17
|
-
const { runPowerSync } = await import("./powersync-
|
|
17
|
+
const { runPowerSync } = await import("./powersync-0QVP_DuR.js");
|
|
18
18
|
return runPowerSync({
|
|
19
19
|
cwd: ctx.cwd,
|
|
20
20
|
config: ctx.config,
|
|
@@ -45,7 +45,7 @@ const verify = defineLeaf({
|
|
|
45
45
|
const db = await dbUrl(ctx, flags, { required: true });
|
|
46
46
|
const fixtures = given(flags.fixtures);
|
|
47
47
|
const from = given(flags.policy);
|
|
48
|
-
const { runPowerSync } = await import("./powersync-
|
|
48
|
+
const { runPowerSync } = await import("./powersync-0QVP_DuR.js");
|
|
49
49
|
return runPowerSync({
|
|
50
50
|
cwd: ctx.cwd,
|
|
51
51
|
config: ctx.config,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { n as runCloudPull } from "./pull-CQCGy1gv.js";
|
|
@@ -7,7 +7,7 @@ import { o as formatCatalogJson } from "./catalog-doc-DjMKzJp9.js";
|
|
|
7
7
|
import { t as catalogPath } from "./catalog-path-CnI0XTFK.js";
|
|
8
8
|
import { n as parseSupabaseManifest } from "./manifest-BXTbHNIV.js";
|
|
9
9
|
import { t as parseCatalog } from "./parse-1_ZheTW5.js";
|
|
10
|
-
import { a as nonEmptyOr } from "./output-
|
|
10
|
+
import { a as nonEmptyOr } from "./output-DlICTjBh.js";
|
|
11
11
|
import { t as POLICY_NOT_PUBLISHED } from "./problem-types-DSsRfONQ.js";
|
|
12
12
|
import { n as httpRequest, t as authFailure } from "./http-DOL33cO0.js";
|
|
13
13
|
import { l as cloudUrl, n as cliRuntime, o as readAuth } from "./auth--yPyZNgr.js";
|
|
@@ -124,6 +124,19 @@ type PowerSyncSourceOptions<Q extends string> = {
|
|
|
124
124
|
* as an argument; `permdock/react-native` never imports `@powersync/*`.
|
|
125
125
|
*/
|
|
126
126
|
export declare function powerSyncSource<Q extends string>(db: PowerSyncWatchable, options: PowerSyncSourceOptions<Q>): SnapshotSource;
|
|
127
|
+
/** `powerSyncSource` over one database, memoised per manifest and options. */
|
|
128
|
+
type PowerSyncSourceCache = {
|
|
129
|
+
readonly source: <Q extends string>(options: PowerSyncSourceOptions<Q>) => SnapshotSource;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* A cache of `powerSyncSource` sources over `db`. `source` answers the same
|
|
133
|
+
* source for the same `manifest` object and, with `user`, the same `user`,
|
|
134
|
+
* `tenant` and `attributes` content, or, with `queries`, the same `queries` and
|
|
135
|
+
* `read` objects. A render that rebuilds its options then keeps the source, so
|
|
136
|
+
* `PermDockProvider` neither resubscribes nor rereads. Entries live as long as
|
|
137
|
+
* their manifest; create one cache per database, outside render.
|
|
138
|
+
*/
|
|
139
|
+
export declare function powerSyncSourceCache(db: PowerSyncWatchable): PowerSyncSourceCache;
|
|
127
140
|
//#endregion
|
|
128
141
|
//#region src/react-native/provider.d.ts
|
|
129
142
|
export declare function PermDockProvider(props: ReactNativePermDockProviderProps): ReactElement;
|
|
@@ -209,4 +222,4 @@ type NativeStoreOptions = Omit<ReactNativePermDockProviderProps, "children" | "h
|
|
|
209
222
|
export declare function connectSource(store: ClientStore, source: SnapshotSource, subscribeForeground?: SubscribeForeground): () => void;
|
|
210
223
|
export declare function nativeStore(options: NativeStoreOptions): ClientStore;
|
|
211
224
|
//#endregion
|
|
212
|
-
export { type ActionResult, type AppStateModule, type ApprovalHandle, type ApprovalState, type ClientPermDock, type ClientStatus, type EventSourceRefreshOptions, type FilterResult, type GateMode, type GateView, type LocalMembershipRows, type LocalRowColumn, type LocalRowValue, type LocalSnapshotData, type LocalSnapshotManifest, type LocalSnapshotOptions, type LocalSnapshotRows, type MmkvInstance, type NativeRevalidate, type NetInfoModule, type PermDockDefaults, type PermissionSet, type PermissionState, type PowerSyncQuery, type PowerSyncSourceOptions, type PowerSyncWatchable, Protected, type ProtectedAction, type ProtectedActionHandle, type ProtectedActionView, type ProtectedProps, type ReactNativePermDockProviderProps, type RefreshTrigger, type RolesOptions, type SecureStoreModule, type SnapshotSource, type SnapshotStorage, type SubjectView, type SubscribeForeground, type SubscribeOnline, type TenantView, approvalHeaders, describe, eventSourceRefresh, parseLocalSnapshotManifest, requiredPlans, useApproval, useAssignablePermissions, useAssignableRoles, useDescribe, useFilter, useGate, useMemberships, usePermDock, usePermission, usePermissions, useProtectedAction, useRoles, useSubject, useTenant };
|
|
225
|
+
export { type ActionResult, type AppStateModule, type ApprovalHandle, type ApprovalState, type ClientPermDock, type ClientStatus, type EventSourceRefreshOptions, type FilterResult, type GateMode, type GateView, type LocalMembershipRows, type LocalRowColumn, type LocalRowValue, type LocalSnapshotData, type LocalSnapshotManifest, type LocalSnapshotOptions, type LocalSnapshotRows, type MmkvInstance, type NativeRevalidate, type NetInfoModule, type PermDockDefaults, type PermissionSet, type PermissionState, type PowerSyncQuery, type PowerSyncSourceCache, type PowerSyncSourceOptions, type PowerSyncWatchable, Protected, type ProtectedAction, type ProtectedActionHandle, type ProtectedActionView, type ProtectedProps, type ReactNativePermDockProviderProps, type RefreshTrigger, type RolesOptions, type SecureStoreModule, type SnapshotSource, type SnapshotStorage, type SubjectView, type SubscribeForeground, type SubscribeOnline, type TenantView, approvalHeaders, describe, eventSourceRefresh, parseLocalSnapshotManifest, requiredPlans, useApproval, useAssignablePermissions, useAssignableRoles, useDescribe, useFilter, useGate, useMemberships, usePermDock, usePermission, usePermissions, useProtectedAction, useRoles, useSubject, useTenant };
|
|
@@ -603,6 +603,51 @@ function powerSyncSource(db, options) {
|
|
|
603
603
|
}
|
|
604
604
|
};
|
|
605
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* A cache of `powerSyncSource` sources over `db`. `source` answers the same
|
|
608
|
+
* source for the same `manifest` object and, with `user`, the same `user`,
|
|
609
|
+
* `tenant` and `attributes` content, or, with `queries`, the same `queries` and
|
|
610
|
+
* `read` objects. A render that rebuilds its options then keeps the source, so
|
|
611
|
+
* `PermDockProvider` neither resubscribes nor rereads. Entries live as long as
|
|
612
|
+
* their manifest; create one cache per database, outside render.
|
|
613
|
+
*/
|
|
614
|
+
function powerSyncSourceCache(db) {
|
|
615
|
+
const byManifest = /* @__PURE__ */ new WeakMap();
|
|
616
|
+
return Object.freeze({ source: (options) => {
|
|
617
|
+
let entries = byManifest.get(options.manifest);
|
|
618
|
+
if (entries === void 0) {
|
|
619
|
+
entries = {
|
|
620
|
+
rows: /* @__PURE__ */ new Map(),
|
|
621
|
+
custom: /* @__PURE__ */ new WeakMap()
|
|
622
|
+
};
|
|
623
|
+
byManifest.set(options.manifest, entries);
|
|
624
|
+
}
|
|
625
|
+
if ("user" in options) {
|
|
626
|
+
const key = JSON.stringify([
|
|
627
|
+
options.user,
|
|
628
|
+
options.tenant ?? null,
|
|
629
|
+
options.attributes ?? null
|
|
630
|
+
]);
|
|
631
|
+
let source = entries.rows.get(key);
|
|
632
|
+
if (source === void 0) {
|
|
633
|
+
source = powerSyncSource(db, options);
|
|
634
|
+
entries.rows.set(key, source);
|
|
635
|
+
}
|
|
636
|
+
return source;
|
|
637
|
+
}
|
|
638
|
+
let byRead = entries.custom.get(options.queries);
|
|
639
|
+
if (byRead === void 0) {
|
|
640
|
+
byRead = /* @__PURE__ */ new WeakMap();
|
|
641
|
+
entries.custom.set(options.queries, byRead);
|
|
642
|
+
}
|
|
643
|
+
let source = byRead.get(options.read);
|
|
644
|
+
if (source === void 0) {
|
|
645
|
+
source = powerSyncSource(db, options);
|
|
646
|
+
byRead.set(options.read, source);
|
|
647
|
+
}
|
|
648
|
+
return source;
|
|
649
|
+
} });
|
|
650
|
+
}
|
|
606
651
|
//#endregion
|
|
607
652
|
//#region src/react-native/storage.ts
|
|
608
653
|
const SNAPSHOT_KEY = "permdock.snapshot";
|
|
@@ -1081,4 +1126,4 @@ function netInfoOnline(netInfo) {
|
|
|
1081
1126
|
});
|
|
1082
1127
|
}
|
|
1083
1128
|
//#endregion
|
|
1084
|
-
export { PermDockProvider, Protected, appStateForeground, approvalHeaders, buildLocalSnapshot, connectSource, describe, eventSourceRefresh, localSnapshot, memorySnapshotStorage, mmkvStorage, nativeStore, netInfoOnline, parseLocalSnapshotManifest, powerSyncSource, requiredPlans, secureStoreStorage, useApproval, useAssignablePermissions, useAssignableRoles, useDescribe, useFilter, useGate, useMemberships, usePermDock, usePermission, usePermissionGuard, usePermissions, useProtectedAction, useRoles, useSnapshotReady, useSubject, useTenant };
|
|
1129
|
+
export { PermDockProvider, Protected, appStateForeground, approvalHeaders, buildLocalSnapshot, connectSource, describe, eventSourceRefresh, localSnapshot, memorySnapshotStorage, mmkvStorage, nativeStore, netInfoOnline, parseLocalSnapshotManifest, powerSyncSource, powerSyncSourceCache, requiredPlans, secureStoreStorage, useApproval, useAssignablePermissions, useAssignableRoles, useDescribe, useFilter, useGate, useMemberships, usePermDock, usePermission, usePermissionGuard, usePermissions, useProtectedAction, useRoles, useSnapshotReady, useSubject, useTenant };
|
|
@@ -192,7 +192,7 @@ async function rlsInput(ctx, verb, shape, options) {
|
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
async function runRls(input) {
|
|
195
|
-
return (await import("./rls-
|
|
195
|
+
return (await import("./rls-tHu7N_Pe.js")).runRls(input);
|
|
196
196
|
}
|
|
197
197
|
const generate = defineLeaf({
|
|
198
198
|
flags: {
|
|
@@ -11,10 +11,10 @@ import "./sources-C4vkzZJV.js";
|
|
|
11
11
|
import { t as policyFromCatalog } from "./policy-from-catalog-CU3An8uP.js";
|
|
12
12
|
import { t as beforeFirst } from "./text-BMFRfBqc.js";
|
|
13
13
|
import { i as INDEXES_MARKER, n as GRANTS_MARKER, o as SEEDS_MARKER, t as BACKFILL_MARKER } from "./markers-BeHZ4x9Q.js";
|
|
14
|
-
import { a as nonEmptyOr } from "./output-
|
|
14
|
+
import { a as nonEmptyOr } from "./output-DlICTjBh.js";
|
|
15
15
|
import { i as requirePeer, n as packageManagerOf, t as addLine } from "./peer-Q0fuZ6hx.js";
|
|
16
16
|
import { t as POLICY_NOT_PUBLISHED } from "./problem-types-DSsRfONQ.js";
|
|
17
|
-
import { t as fetchProjectPolicy } from "./pull-
|
|
17
|
+
import { t as fetchProjectPolicy } from "./pull-CQCGy1gv.js";
|
|
18
18
|
import { n as MIGRATION_DIRS } from "./constants-DcJABbLW.js";
|
|
19
19
|
import { a as isSeedsDirectory, c as parseSplit, d as seedsMigration, f as writeOutputFiles, l as partPath, n as dataMigrationFile, r as driftOf, u as pgDeltaPath } from "./output-files-BIQ_9pIs.js";
|
|
20
20
|
import { b as rbacScaffold, d as resolveSchemas, f as schemasRefusal, o as supabaseHookSql, p as declarativeSql, s as approvalsSql, t as grantsLabel, u as isSupabaseSchemas, y as parseRbacAuthorize } from "./supabase-hook-HPgwYb9V.js";
|
|
@@ -25,8 +25,8 @@ import { a as splitUndiffed } from "./deciding-columns-NB4wcyBf.js";
|
|
|
25
25
|
import { t as connectPgPool } from "./pg-DQTqRrou.js";
|
|
26
26
|
import { a as fieldViewsSql, c as ACTOR_MAY_WRITE, f as readOnlyActorKinds, i as fieldViews, l as actorMayWriteSql, n as columnGrantSql, o as rowBranches, p as readOnlyActorPolicies, r as columnRevokeSql, u as assemblePolicies } from "./fields-DI8s3cPl.js";
|
|
27
27
|
import { n as permissionHoldersSql } from "./resolve-names-Y1Cb22cp.js";
|
|
28
|
-
import { _ as indexTargets, a as verifyResult, b as readTableIndexFacts, c as callsHelper, g as INDEX_COLUMNS_SQL, h as COLUMNS_SQL, i as verifyIgnores, l as helperCallKeys, m as tableFor, n as runRlsVerify, o as HELPER_TABLES, p as compileGrants, r as rlsFinding, v as indexesSql, y as pruneIndexTargets } from "./verify-
|
|
29
|
-
import { a as buildContext, c as levelKeys, d as rebuildPlan, i as splitsPart, l as rowHelpersSql, n as generateOptions, o as CANDIDATES, r as isRefusal, s as inheritTargets, t as supautilsRejections, u as DROPPED_LIST } from "./supautils-
|
|
28
|
+
import { _ as indexTargets, a as verifyResult, b as readTableIndexFacts, c as callsHelper, g as INDEX_COLUMNS_SQL, h as COLUMNS_SQL, i as verifyIgnores, l as helperCallKeys, m as tableFor, n as runRlsVerify, o as HELPER_TABLES, p as compileGrants, r as rlsFinding, v as indexesSql, y as pruneIndexTargets } from "./verify-DfT0QYNh.js";
|
|
29
|
+
import { a as buildContext, c as levelKeys, d as rebuildPlan, i as splitsPart, l as rowHelpersSql, n as generateOptions, o as CANDIDATES, r as isRefusal, s as inheritTargets, t as supautilsRejections, u as DROPPED_LIST } from "./supautils-SwE642N1.js";
|
|
30
30
|
import { readFileSync } from "node:fs";
|
|
31
31
|
import { basename, delimiter, join } from "node:path";
|
|
32
32
|
import { spawn } from "node:child_process";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { t as run } from "./run-DUq1xU4K.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { i as dateAt } from "./time-nR1JesoH.js";
|
|
2
2
|
import { a as describeError, l as problemOf, n as CliError, r as cliProblem, s as kindOfCode } from "./errors-Vpu6rKHl.js";
|
|
3
3
|
import { s as cliVersion } from "./version-DMQ0dnN5.js";
|
|
4
|
-
import { a as resolveCwd, i as readConfig } from "./config-
|
|
4
|
+
import { a as resolveCwd, i as readConfig } from "./config-CcLlvEYW.js";
|
|
5
5
|
import { t as beforeFirst } from "./text-BMFRfBqc.js";
|
|
6
6
|
import { a as suggestion, i as parseLeaf, n as flagSpellings, o as GLOBAL_FLAGS, r as parseFlags } from "./args-0FrVs5EH.js";
|
|
7
7
|
import { r as progressReporter, t as redact } from "./credentials-CdDxp7jN.js";
|
|
8
|
-
import { a as resolve, i as leaves, n as ROOT, r as SECTIONS, t as DOCS_BASE } from "./manifest-
|
|
8
|
+
import { a as resolve, i as leaves, n as ROOT, r as SECTIONS, t as DOCS_BASE } from "./manifest-Cft51TLK.js";
|
|
9
9
|
import { t as createStyle } from "./style-Ds11Hmk4.js";
|
|
10
|
-
import { i as githubAnnotations, n as envelope, o as sarifLog, t as dataOf } from "./output-
|
|
10
|
+
import { i as githubAnnotations, n as envelope, o as sarifLog, t as dataOf } from "./output-DlICTjBh.js";
|
|
11
11
|
import { i as renameMessage, r as flagRename, t as COMMAND_MOVES } from "./renames-CGj7YwcQ.js";
|
|
12
12
|
import { stripVTControlCharacters } from "node:util";
|
|
13
13
|
import { existsSync, statSync } from "node:fs";
|
|
@@ -16,7 +16,7 @@ const scan = defineLeaf({
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
async run(ctx, { flags }) {
|
|
19
|
-
const { runAdoptionScan } = await import("./adoption-scan-
|
|
19
|
+
const { runAdoptionScan } = await import("./adoption-scan-C2BCiUEG.js");
|
|
20
20
|
return runAdoptionScan({
|
|
21
21
|
cwd: ctx.cwd,
|
|
22
22
|
srcPath: flags.src.length > 0 ? flags.src : ctx.config.collect?.srcPath ?? ["src"],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as isRecord } from "./compact-CAf557ZB.js";
|
|
2
2
|
import { l as packageRoot } from "./version-DMQ0dnN5.js";
|
|
3
3
|
import { t as DRAFT_PINS } from "./pins-nqarl3oE.js";
|
|
4
|
-
import { a as nonEmptyOr } from "./output-
|
|
4
|
+
import { a as nonEmptyOr } from "./output-DlICTjBh.js";
|
|
5
5
|
import { t as require__2020 } from "./2020-CJbO8Bvz.js";
|
|
6
6
|
import { readFileSync } from "node:fs";
|
|
7
7
|
import { join } from "node:path";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as defineLeaf } from "./command-L8EstFNm.js";
|
|
2
2
|
import { t as checkFlag } from "./flags-DXjoTVbS.js";
|
|
3
3
|
import { r as pick, t as CANCELLED } from "./prompt-BYc6drYW.js";
|
|
4
|
-
import { n as detectedAgents, r as runSkills, t as SKILL_AGENTS } from "./skills-
|
|
4
|
+
import { n as detectedAgents, r as runSkills, t as SKILL_AGENTS } from "./skills-Celu2W6v.js";
|
|
5
5
|
//#region src/cli/commands/skills.ts
|
|
6
6
|
const forFlag = { for: {
|
|
7
7
|
type: "string",
|
|
@@ -2,7 +2,7 @@ import { t as byCodePoint } from "./compare-DTfyUunF.js";
|
|
|
2
2
|
import { i as readJsonFile } from "./files-BSjrtIHw.js";
|
|
3
3
|
import { l as packageRoot } from "./version-DMQ0dnN5.js";
|
|
4
4
|
import { t as didYouMean } from "./args-0FrVs5EH.js";
|
|
5
|
-
import { a as nonEmptyOr } from "./output-
|
|
5
|
+
import { a as nonEmptyOr } from "./output-DlICTjBh.js";
|
|
6
6
|
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
@@ -16,7 +16,7 @@ import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
|
|
|
16
16
|
import { i as group, o as sqlStatements } from "./deciding-columns-NB4wcyBf.js";
|
|
17
17
|
import { d as orSql, h as branchClauses } from "./fields-DI8s3cPl.js";
|
|
18
18
|
import { t as resolveNames } from "./resolve-names-Y1Cb22cp.js";
|
|
19
|
-
import { m as tableFor } from "./verify-
|
|
19
|
+
import { m as tableFor } from "./verify-DfT0QYNh.js";
|
|
20
20
|
//#region src/cli/rls/custom-role-rebuild.ts
|
|
21
21
|
const PREFIX = "PermDock CLI";
|
|
22
22
|
/** A column of the roles-table row `r`. */
|
|
@@ -199,8 +199,8 @@ const DROPPED_LIST = `(select string_agg(g.role || ': ' || g.items, '; ' order b
|
|
|
199
199
|
* shared role holds is skipped with a warning (`name-taken`). Before-row
|
|
200
200
|
* triggers hold a signed-in caller at trigger depth 1 to the checks of
|
|
201
201
|
* `permdock_replace_custom_role_grants`: `permdock_custom_role_guard` on each
|
|
202
|
-
* role the row names,
|
|
203
|
-
* a refusal aborts the write.
|
|
202
|
+
* role the row names, the entry it adds against the ceiling, then
|
|
203
|
+
* `permdock_custom_role_beyond` on that entry; a refusal aborts the write.
|
|
204
204
|
*/
|
|
205
205
|
function customRoleSyncSql(ctx, from, migrate) {
|
|
206
206
|
const plan = rebuildPlan(ctx, from, migrate);
|
|
@@ -305,6 +305,17 @@ begin
|
|
|
305
305
|
end if;
|
|
306
306
|
v_dropped := '{}'::text[];
|
|
307
307
|
${plan.collectNew[name]}
|
|
308
|
+
if cardinality(v_dropped) > 0 then
|
|
309
|
+
raise exception using
|
|
310
|
+
errcode = '22023',
|
|
311
|
+
message = 'permdock: ' || v_dropped[1],
|
|
312
|
+
hint = case
|
|
313
|
+
when v_dropped[1] like '%outside the ceiling of %' then 'outside-ceiling'
|
|
314
|
+
when v_dropped[1] like '%, level % is not declared' then 'unknown-level'
|
|
315
|
+
when v_dropped[1] like '%, not a declared role' then 'unknown-role'
|
|
316
|
+
else 'unknown-permission'
|
|
317
|
+
end;
|
|
318
|
+
end if;
|
|
308
319
|
select string_agg(b, ', ' order by b) into v_beyond
|
|
309
320
|
from ${beyond}(v.tenant_id, v.scope, v.scope_id, v_allow, v_deny, v_include) b;
|
|
310
321
|
if v_beyond is not null then
|
|
@@ -389,10 +400,11 @@ function permissionCase(key, branches) {
|
|
|
389
400
|
const granted = `coalesce((${allow}), false)`;
|
|
390
401
|
return ` when ${quoteLiteral(key)} then ${deny === void 0 ? granted : `${granted} and (${deny}) is not true`}`;
|
|
391
402
|
}
|
|
392
|
-
function forUserSql(ctx, fn, helper) {
|
|
403
|
+
function forUserSql(ctx, fn, helper, ids) {
|
|
393
404
|
const user = ctx.dialect === "supabase" ? "uuid" : "text";
|
|
394
|
-
const signature = `${user}, text, jsonb`;
|
|
395
|
-
const
|
|
405
|
+
const signature = `${user}, text, ${ids ? "text[], " : ""}jsonb`;
|
|
406
|
+
const call = `${helper}(p_permission${ids ? ", p_ids" : ""})`;
|
|
407
|
+
const head = `create or replace function ${fn}(p_user ${user}, p_permission text, ${ids ? "p_ids text[], " : ""}p_claims jsonb default '{}')
|
|
396
408
|
returns setof text
|
|
397
409
|
language plpgsql
|
|
398
410
|
volatile
|
|
@@ -409,7 +421,7 @@ begin
|
|
|
409
421
|
(coalesce(p_claims, '{}'::jsonb) || pg_catalog.jsonb_build_object('sub', p_user::text, 'role', 'authenticated'))::text,
|
|
410
422
|
true
|
|
411
423
|
);
|
|
412
|
-
return query select r.id from ${
|
|
424
|
+
return query select r.id from ${call} r(id);
|
|
413
425
|
perform pg_catalog.set_config('request.jwt.claims', coalesce(v_claims, ''), true);
|
|
414
426
|
end
|
|
415
427
|
$$;
|
|
@@ -429,7 +441,7 @@ begin
|
|
|
429
441
|
v_saved := v_saved || pg_catalog.jsonb_build_object(v_key, coalesce(pg_catalog.current_setting(${quoteLiteral(`${prefix}.`)} || v_key, true), ''));
|
|
430
442
|
perform pg_catalog.set_config(${quoteLiteral(`${prefix}.`)} || v_key, v_value, true);
|
|
431
443
|
end loop;
|
|
432
|
-
return query select r.id from ${
|
|
444
|
+
return query select r.id from ${call} r(id);
|
|
433
445
|
for v_key, v_value in select s.key, s.value from pg_catalog.jsonb_each_text(v_saved) s loop
|
|
434
446
|
perform pg_catalog.set_config(${quoteLiteral(`${prefix}.`)} || v_key, v_value, true);
|
|
435
447
|
end loop;
|
|
@@ -540,7 +552,8 @@ ${rowSql(ctx, name, table, near)}`;
|
|
|
540
552
|
if (ctx.dialect === "neon") return rows;
|
|
541
553
|
return `${rows}
|
|
542
554
|
-- the same rows for a user the caller names, with claims it supplies; no client role may execute it
|
|
543
|
-
${forUserSql(ctx, qualified(ctx, `${name}_for`), fn)}
|
|
555
|
+
${forUserSql(ctx, qualified(ctx, `${name}_for`), fn, false)}
|
|
556
|
+
${forUserSql(ctx, qualified(ctx, `${name}_for`), fn, true)}`;
|
|
544
557
|
}
|
|
545
558
|
/**
|
|
546
559
|
* `permitted_<resource>_rows(p_permission)` for each resource `select` names
|
package/dist/unplugin/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createCollectScheduler, r as report } from "../watch-
|
|
1
|
+
import { n as createCollectScheduler, r as report } from "../watch-DAkjm75Y.js";
|
|
2
2
|
import { r as peerHint } from "../peer-Q0fuZ6hx.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
//#region src/unplugin/index.ts
|
|
@@ -6,8 +6,8 @@ import { c as jsonSchemaOf } from "./catalog-doc-DjMKzJp9.js";
|
|
|
6
6
|
import { a as loadModule, n as asPolicy, s as pickNamed } from "./load-DjSU5KXO.js";
|
|
7
7
|
import { r as runCollect } from "./collect-WCl8cJQV.js";
|
|
8
8
|
import { t as beforeFirst } from "./text-BMFRfBqc.js";
|
|
9
|
-
import { t as DOCS_BASE } from "./manifest-
|
|
10
|
-
import { r as findingOf } from "./output-
|
|
9
|
+
import { t as DOCS_BASE } from "./manifest-Cft51TLK.js";
|
|
10
|
+
import { r as findingOf } from "./output-DlICTjBh.js";
|
|
11
11
|
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
12
12
|
import { dirname, resolve } from "node:path";
|
|
13
13
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { t as runUsage } from "./usage-CPXeuAdT.js";
|
|
@@ -22,7 +22,7 @@ import { i as qualifySqlTable, n as defaultSqlCommand, t as SQL_IDENT } from "./
|
|
|
22
22
|
import { a as scopeMembershipTable, i as scopeColumn } from "./compile-EzEMB-7v.js";
|
|
23
23
|
import "./sources-C4vkzZJV.js";
|
|
24
24
|
import { t as beforeFirst } from "./text-BMFRfBqc.js";
|
|
25
|
-
import { t as DOCS_BASE } from "./manifest-
|
|
25
|
+
import { t as DOCS_BASE } from "./manifest-Cft51TLK.js";
|
|
26
26
|
import { n as fixtureSubject, r as loadFixtures, t as fixtureRow } from "./fixtures-Bm4_K1ke.js";
|
|
27
27
|
import { A as quoteQualified, N as arrayColumnsOf, O as quoteIdent, P as columnTypesOf, _ as subjectClaimJsonSql, a as customRolesOn, j as quoteTable, k as quoteLiteral, r as HELPERS, v as subjectClaimSql } from "./shared-DrGLwM3s.js";
|
|
28
28
|
import { C as accessSql, D as tokenScopeAllowsCall, S as requiresSql, ht as scopeTable, k as capabilityAccessSql, n as tableNameOf, o as graphPlan, q as apiKeyAllowsCall, r as tableNames } from "./tables-DimBcVWY.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { i as watchCollect } from "./watch-DAkjm75Y.js";
|
|
@@ -2,7 +2,7 @@ import { i as dateAt } from "./time-nR1JesoH.js";
|
|
|
2
2
|
import { a as describeError } from "./errors-Vpu6rKHl.js";
|
|
3
3
|
import { t as defaultSrcPath } from "./files-BSjrtIHw.js";
|
|
4
4
|
import { r as runCollect } from "./collect-WCl8cJQV.js";
|
|
5
|
-
import { n as isConfigFile, r as loadConfig } from "./config-
|
|
5
|
+
import { n as isConfigFile, r as loadConfig } from "./config-CcLlvEYW.js";
|
|
6
6
|
import { watch } from "node:fs";
|
|
7
7
|
import { basename, dirname, relative, resolve, sep } from "node:path";
|
|
8
8
|
//#region src/cli/watch.ts
|
package/package.json
CHANGED
|
@@ -36,7 +36,7 @@ pnpm exec permdock rls verify --introspect
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
- List the scope instances a permission reaches in process with `permdock.permittedIds(permission, scope, { within })`, never a loop of `can` over memberships with a made-up row.
|
|
39
|
-
- Generated policies call `permdock_has('<key>')` and one `permitted_<scope>_ids('<key>')` per declared scope, which Postgres runs once per statement. Hand-written policies that only need membership (an organization switcher) call `member_<scope>_ids()` instead of inventing a permission key. A policy that passes a user id, such as better-supabase's team sharing, calls `member_team_ids_of(<user>)` on Supabase: it answers only when the id is the caller's. Trusted SQL that acts for a stored user (a job, a trigger, a deferred approval) calls `permdock_has_for(p_user, '<key>')` and `permitted_<scope>_ids_for(p_user, '<key>')` in `database` mode, or the generated `permitted_<resource>_rows_for
|
|
39
|
+
- Generated policies call `permdock_has('<key>')` and one `permitted_<scope>_ids('<key>')` per declared scope, which Postgres runs once per statement. Hand-written policies that only need membership (an organization switcher) call `member_<scope>_ids()` instead of inventing a permission key. A policy that passes a user id, such as better-supabase's team sharing, calls `member_team_ids_of(<user>)` on Supabase: it answers only when the id is the caller's. Trusted SQL that acts for a stored user (a job, a trigger, a deferred approval) calls `permdock_has_for(p_user, '<key>')` and `permitted_<scope>_ids_for(p_user, '<key>')` in `database` mode, or the generated `permitted_<resource>_rows_for` (`permitted_<resource>_rows_for(p_user, '<key>', <text[] of ids>)` for a known set of rows, such as a share link checked against its creator's access), never a hand-written function that rewrites `request.jwt.claims`. With `rls.rowHelpers`, a hand-written policy or function that needs the rows a permission reaches through the graph calls `permitted_<resource>_rows('<permission key>')` instead of restating closure walks, link hops and `includes`. A table's own `select` or `insert` policy calls the row-valued `permitted_<resource>_row(<table>, '<permission key>')` instead, so `insert ... returning` sees the new row. A function that checks a known set of rows (one tenant's, a page, a batch) calls `permitted_<resource>_rows('<permission key>', <text[] of ids>)`, which reads only those ids, instead of the one-argument form, which reads the whole table, or a `permitted_<resource>_row` call per row. Hand-written policies and functions that apply no row condition call `permitted_<scope>_ids_by_permission('<permission key>')` or `permdock_has_permission('<permission key>')` instead of spelling a positional `#n` grant key. A screen or RPC that checks many permissions on one organization calls `permitted_<scope>_permission_keys(<id>)` once (or `(<id>, array['<key>', ...])` for a few keys) instead of one helper call per key. A role editor or admin screen lists a role's keys with `permdock_role_permissions(p_role, p_scope, p_tenant, p_scope_id)` (declared roles, and custom roles of the caller's tenant in `database` mode) and the catalog with `permdock_permission_keys()` (`permdock_permission_keys('<scope>')` for the keys a role on that scope can hold), instead of joining `role_permissions` and the custom-role tables by hand; server code reads any tenant's roles with `permdock_trusted_role_permissions`, granted through `rls.trustedReaders`. Set `--tenant-type` (or `rls.scopeTypes`, keyed by scope name or `tenant` and `team`) to the scope columns' types.
|
|
40
40
|
- `--authorize database` (default) reads the membership tables per statement; map each under `rls.memberships.scopes.<scope>` with `columns` for its id and its ancestors', and `via` so roles with `for` apply: a column name, or `{ value: 'staff' }` when every row has that kind (never add a generated column for it). `--authorize jwt` reads token claims and stays stale until the token refreshes; keep the token lifetime at 3600 seconds or less (PD019).
|
|
41
41
|
- When the role column holds values that are not role keys, give the membership source `role: { column, map: { value: 'role' } }`; a value mapped to `null` grants nothing. `permdock rls explain` prints the tables, membership sources, custom roles table and triggers a generate run binds to, without writing a file. `rls.seeds: 'function'` writes the `role_permissions` rows as `<schema>.seed()` instead of inserts; run `select <schema>.seed();` after each deploy, and PD054 checks the function body.
|
|
42
42
|
- `rls verify --introspect` checks each `security definer` helper by its full signature, so every overload is checked on its own. A helper finding id names the signature (`helper-definer:permdock.permdock_has(text):helper`); write `rls.verify.ignore` entries with it.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { n as runPowerSync } from "./powersync-DVbskWD9.js";
|
package/dist/pull-BY1METGf.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { n as runCloudPull } from "./pull-Er4aBHlL.js";
|
package/dist/run-DGSLvGty.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { t as run } from "./run-BlxXmaDS.js";
|
package/dist/usage-CH7oISI6.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { t as runUsage } from "./usage-WYRc7Kqg.js";
|
package/dist/watch-C44FtM79.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { i as watchCollect } from "./watch-CTfSlIGD.js";
|