permdock 0.0.0 → 0.1.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/README.md +268 -1
- package/dist/a2a/index.d.ts +178 -0
- package/dist/a2a/index.js +271 -0
- package/dist/ai-sdk/index.d.ts +74 -0
- package/dist/ai-sdk/index.js +137 -0
- package/dist/approval-required-TzNB9oQA.js +6 -0
- package/dist/approvals/index.d.ts +3 -0
- package/dist/approvals/index.js +4 -0
- package/dist/approvals-DaxY-Bdg.js +218 -0
- package/dist/approvers-aH0PJkmf.js +20 -0
- package/dist/arazzo-CTeVuXr5.js +70 -0
- package/dist/arazzo-aoTkqYsJ.js +54 -0
- package/dist/authzen/index.d.ts +48 -0
- package/dist/authzen/index.js +336 -0
- package/dist/better-auth/index.d.ts +92 -0
- package/dist/better-auth/index.js +324 -0
- package/dist/budget-JqcRqyhK.d.ts +11 -0
- package/dist/budget-NbEtbJC_.js +11 -0
- package/dist/capability-B68OFnZx.js +171 -0
- package/dist/capability-BDG_nkxt.d.ts +99 -0
- package/dist/catalog/index.d.ts +12 -0
- package/dist/catalog/index.js +2 -0
- package/dist/catalog-B0E6bggc.js +48 -0
- package/dist/catalog-H-vFGwWK.js +55 -0
- package/dist/catalog-doc-BSo_Q_-6.js +298 -0
- package/dist/catalog-idsHc0vo.js +2 -0
- package/dist/catalog-path-CnI0XTFK.js +12 -0
- package/dist/claude-agent/index.d.ts +81 -0
- package/dist/claude-agent/index.js +83 -0
- package/dist/clerk/index.d.ts +56 -0
- package/dist/clerk/index.js +280 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +20 -0
- package/dist/cli/index.d.ts +46 -0
- package/dist/cli/index.js +5 -0
- package/dist/cloud/index.d.ts +91 -0
- package/dist/cloud/index.js +390 -0
- package/dist/cloud-BNQTrmrr.js +50 -0
- package/dist/cloud-Cuxr6Czw.js +117 -0
- package/dist/collect-B7_TIfmg.js +49 -0
- package/dist/collect-O-tOtbnk.js +350 -0
- package/dist/collect-fRPAQIWb.js +2 -0
- package/dist/commands-BMh_Etm2.js +93 -0
- package/dist/compact-y6vfu2_f.js +19 -0
- package/dist/compare-pfyVnBjE.js +12 -0
- package/dist/compile-CQbvyIBr.d.ts +30 -0
- package/dist/compile-D22iwvuV.js +558 -0
- package/dist/config-BPYmjTOp.js +26 -0
- package/dist/connection-JvqwHODC.js +194 -0
- package/dist/context-CKEAabd7.js +73 -0
- package/dist/context-gtAwAILx.js +6 -0
- package/dist/convex/index.d.ts +40 -0
- package/dist/convex/index.js +55 -0
- package/dist/create-BKF3dgFk.d.ts +162 -0
- package/dist/create-CSkhDU9T.js +222 -0
- package/dist/credential-B_rkUNlY.js +326 -0
- package/dist/credentials-BgRX3WEg.js +268 -0
- package/dist/describe-Bt1YD5uS.js +99 -0
- package/dist/describe-DernyItf.d.ts +37 -0
- package/dist/diff-BUzf5Poi.js +48 -0
- package/dist/diff-x5Il8LVa.js +418 -0
- package/dist/digest-B3kc_PgQ.d.ts +19 -0
- package/dist/digest-BI-6aa6d.js +27 -0
- package/dist/doctor-BGle8Gqi.js +1314 -0
- package/dist/doctor-Bqo6FwUa.js +53 -0
- package/dist/drizzle/index.d.ts +72 -0
- package/dist/drizzle/index.js +160 -0
- package/dist/duration-xK2jGFVc.js +25 -0
- package/dist/elysia/index.d.ts +71 -0
- package/dist/elysia/index.js +103 -0
- package/dist/errors-DSMnAVNa.js +43 -0
- package/dist/errors-DbZ1YOnb.d.ts +138 -0
- package/dist/errors-Iy71s7Oj.js +177 -0
- package/dist/errors-m3u9TmDu.js +27 -0
- package/dist/evaluations-DsAU9ppl.js +479 -0
- package/dist/eve/index.d.ts +95 -0
- package/dist/eve/index.js +181 -0
- package/dist/express/index.d.ts +46 -0
- package/dist/express/index.js +108 -0
- package/dist/fastify/index.d.ts +56 -0
- package/dist/fastify/index.js +141 -0
- package/dist/files-B_wAGYmt.js +121 -0
- package/dist/fixtures-Cvaw0gDG.js +64 -0
- package/dist/freeze-y1_jQL4v.js +31 -0
- package/dist/from-snapshot-BMGnhmgv.js +552 -0
- package/dist/generate-CH7ThJ14.js +173 -0
- package/dist/grantee-Bv04_Vzf.js +521 -0
- package/dist/headers-B5RRv3Xm.js +6 -0
- package/dist/headers-C8SHQccD.d.ts +6 -0
- package/dist/helpers-DnSOrhB9.js +682 -0
- package/dist/hono/index.d.ts +70 -0
- package/dist/hono/index.js +131 -0
- package/dist/hosted-BwKQ1BTA.js +265 -0
- package/dist/http-DPuDaChb.d.ts +13 -0
- package/dist/http-GgVApX1k.js +111 -0
- package/dist/index-CltcQ4Bf.d.ts +138 -0
- package/dist/index-LF_hS-yn.d.ts +177 -0
- package/dist/index-fG6NSXlc.d.ts +9 -0
- package/dist/index-xIxJLwOQ.d.ts +415 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +21 -0
- package/dist/jwt/index.d.ts +87 -0
- package/dist/jwt/index.js +571 -0
- package/dist/kernel-YOGCWNLf.js +211 -0
- package/dist/kysely/index.d.ts +77 -0
- package/dist/kysely/index.js +129 -0
- package/dist/load-BZ24CpZP.js +69 -0
- package/dist/load-QOOm1z70.js +2 -0
- package/dist/load-jose-BL6LH4bL.js +11 -0
- package/dist/lru-8q4WZjBV.js +28 -0
- package/dist/manifest-DDQbC6K0.d.ts +118 -0
- package/dist/map-DowSO96j.js +158 -0
- package/dist/map-claims-B_6I1Rn-.js +360 -0
- package/dist/map-error-RJ3ZsUyA.js +16 -0
- package/dist/markers-B0hYLvMD.js +60 -0
- package/dist/may-use-CnFEjVEp.js +37 -0
- package/dist/mcp/index.d.ts +127 -0
- package/dist/mcp/index.js +563 -0
- package/dist/nest/index.d.ts +80 -0
- package/dist/nest/index.js +270 -0
- package/dist/next/client.d.ts +24 -0
- package/dist/next/client.js +31 -0
- package/dist/next/index.d.ts +110 -0
- package/dist/next/index.js +195 -0
- package/dist/next/plugin.d.ts +14 -0
- package/dist/next/plugin.js +2 -0
- package/dist/node/index.d.ts +43 -0
- package/dist/node/index.js +66 -0
- package/dist/openai/index.d.ts +71 -0
- package/dist/openai/index.js +105 -0
- package/dist/openapi/index.d.ts +93 -0
- package/dist/openapi/index.js +3 -0
- package/dist/openapi-CwePaF7C.js +164 -0
- package/dist/openapi-DWD0Uc_4.js +250 -0
- package/dist/openapi-DcqM8nU7.js +306 -0
- package/dist/openapi-import-BWRUNNeW.js +5959 -0
- package/dist/openapi-schema-D8j_T9tO.js +6902 -0
- package/dist/orpc/index.d.ts +64 -0
- package/dist/orpc/index.js +188 -0
- package/dist/otel/index.d.ts +13 -0
- package/dist/otel/index.js +202 -0
- package/dist/package-root-zGkxO3oN.js +30 -0
- package/dist/parse-DPfIvFMU.js +135 -0
- package/dist/pdp/index.d.ts +22 -0
- package/dist/pdp/index.js +795 -0
- package/dist/peer-BOr_kJE1.js +31 -0
- package/dist/permdock-yoZ7EjxX.js +2956 -0
- package/dist/permissions-B4apnahQ.d.ts +185 -0
- package/dist/permissions-B8vCg_bI.d.ts +52 -0
- package/dist/permissions-CofRqesP.js +142 -0
- package/dist/permissions-DC7GROPA.js +600 -0
- package/dist/pg-4GJWDUxG.js +953 -0
- package/dist/pins-CqE1jZuF.js +12 -0
- package/dist/plugin-4gr7IxFJ.js +65 -0
- package/dist/policy-ANp36PnI.js +971 -0
- package/dist/policy-CInmNGkM.d.ts +1959 -0
- package/dist/policy-Cq2fB8Q5.d.ts +20 -0
- package/dist/prisma/index.d.ts +135 -0
- package/dist/prisma/index.js +430 -0
- package/dist/problem-Cgp9-KZA.js +226 -0
- package/dist/prompt-CXYhLfsS.js +32 -0
- package/dist/protected-B4K3BKoX.js +138 -0
- package/dist/protected-BuPAycJT.d.ts +26 -0
- package/dist/protected-wY7nXhY9.d.ts +23 -0
- package/dist/provider-_wx46HpB.js +48 -0
- package/dist/provider-wTAUda2v.d.ts +6 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +6 -0
- package/dist/react/provider-client.d.ts +2 -0
- package/dist/react/provider-client.js +3 -0
- package/dist/react-native/index.d.ts +42 -0
- package/dist/react-native/index.js +174 -0
- package/dist/refs-ChLSxbST.js +90 -0
- package/dist/relations-r4soIFZB.js +426 -0
- package/dist/revocations-Cy06JNx2.d.ts +21 -0
- package/dist/rls-BOFU3chG.js +233 -0
- package/dist/rls-CJVja9Ww.js +2119 -0
- package/dist/rls-graph-DxQ39PJj.js +371 -0
- package/dist/rls-helpers-BxRuif0l.js +1346 -0
- package/dist/rls-import-CXV6LBlS.js +942 -0
- package/dist/rls-migrate-DrFPbf8p.js +366 -0
- package/dist/row-check-BajTgQZ-.d.ts +43 -0
- package/dist/run-CJ6UvS3a.js +155 -0
- package/dist/runtime-DP9ttFh1.js +27 -0
- package/dist/saas-BRrZzJkM.js +1193 -0
- package/dist/schema-P8yoma__.js +296 -0
- package/dist/scim/index.d.ts +2 -0
- package/dist/scim/index.js +2 -0
- package/dist/scim-9NFa0XVZ.js +1445 -0
- package/dist/scopes-cKVp_WTw.js +212 -0
- package/dist/server/index.d.ts +123 -0
- package/dist/server/index.js +8 -0
- package/dist/sha256-BO0swRXL.js +150 -0
- package/dist/sink-Bd9PSyfq.js +141 -0
- package/dist/sink-Cfr9-7YC.d.ts +104 -0
- package/dist/skills-C_lpV4Jx.js +50 -0
- package/dist/skills-Dx3QLnMY.js +110 -0
- package/dist/snapshot-DE8dE_hz.js +1051 -0
- package/dist/solid/index.d.ts +63 -0
- package/dist/solid/index.js +197 -0
- package/dist/source-DoBBYJi2.js +6 -0
- package/dist/sources-DOpW5Ila.d.ts +347 -0
- package/dist/sources-DVHM3Mwq.js +284 -0
- package/dist/sql-Bll1d7y0.js +22 -0
- package/dist/src-CTNT-PBW.js +430 -0
- package/dist/ssf/index.d.ts +3 -0
- package/dist/ssf/index.js +622 -0
- package/dist/store-Bq90395i.d.ts +27 -0
- package/dist/store-C6hFW6ta.js +508 -0
- package/dist/stores-CkG2HrSg.js +140 -0
- package/dist/stores-CvOnu_2T.d.ts +41 -0
- package/dist/stream-BhMfZOwr.d.ts +12 -0
- package/dist/stream-Q_xlB6Ko.js +52 -0
- package/dist/style-CTm1AXDT.js +22 -0
- package/dist/subject-C6dLxqHU.js +24 -0
- package/dist/subject-settings-xt7V845g.js +82 -0
- package/dist/supabase/index.d.ts +67 -0
- package/dist/supabase/index.js +4 -0
- package/dist/supabase/middleware.d.ts +77 -0
- package/dist/supabase/middleware.js +68 -0
- package/dist/supabase-D8UlBA7Z.js +83 -0
- package/dist/supabase-DTxGtYdi.js +796 -0
- package/dist/supabase-hook-DW-xP4hU.js +2 -0
- package/dist/supabase-hook-D_OqGb_V.js +1528 -0
- package/dist/svelte/Protected.svelte +34 -0
- package/dist/svelte/index.d.ts +10 -0
- package/dist/svelte/index.js +53 -0
- package/dist/svelte/runtime.d.ts +6 -0
- package/dist/svelte/runtime.js +3 -0
- package/dist/svelte/source.d.ts +10 -0
- package/dist/svelte/source.js +8 -0
- package/dist/terminal/index.d.ts +171 -0
- package/dist/terminal/index.js +821 -0
- package/dist/testing/index.d.ts +656 -0
- package/dist/testing/index.js +3208 -0
- package/dist/testing/saas/index.d.ts +194 -0
- package/dist/testing/saas/index.js +3 -0
- package/dist/testing/saas/permissions.d.ts +2 -0
- package/dist/testing/saas/permissions.js +2 -0
- package/dist/text-diff-BdkkYSbi.js +15 -0
- package/dist/thenable-okc2xDsj.js +10 -0
- package/dist/timeout-D51niuQP.js +8 -0
- package/dist/trpc/index.d.ts +80 -0
- package/dist/trpc/index.js +205 -0
- package/dist/types-B8w5PFtS.d.ts +141 -0
- package/dist/types-B9dmiiab.d.ts +66 -0
- package/dist/types-BBK-exvJ.d.ts +177 -0
- package/dist/types-BvBk1wgn.d.ts +118 -0
- package/dist/types-CxquUByI.d.ts +9 -0
- package/dist/types-D6Z6-rKJ.d.ts +312 -0
- package/dist/types-DbWdEfcm.d.ts +87 -0
- package/dist/types-bva3i4Gf.d.ts +98 -0
- package/dist/types-i4BAOvdb.d.ts +97 -0
- package/dist/unplugin/index.d.ts +7 -0
- package/dist/unplugin/index.js +30 -0
- package/dist/usage-1ozMubLY.js +42 -0
- package/dist/usage-CUnK6Ou9.js +530 -0
- package/dist/usage-PyEor6GA.js +2 -0
- package/dist/validity-D0uRmJKJ.js +224 -0
- package/dist/verifier-B90agnhl.js +461 -0
- package/dist/version-CnSh33Fj.js +16 -0
- package/dist/vocabulary-Dk0fs-Jk.d.ts +56 -0
- package/dist/vue/index.d.ts +57 -0
- package/dist/vue/index.js +203 -0
- package/dist/webmcp/index.d.ts +75 -0
- package/dist/webmcp/index.js +313 -0
- package/package.json +423 -4
- package/rulesets/permdock.yaml +29 -0
- package/schemas/catalog-v1.json +507 -0
- package/schemas/openapi/oas-3.1.json +1298 -0
- package/schemas/openapi/oas-3.2.json +1516 -0
- package/schemas/openapi/overlay-1.1.json +79 -0
- package/schemas/supabase-claims-v1.json +139 -0
- package/schemas/supabase-manifest-v1.json +217 -0
- package/skills/permdock/SKILL.md +66 -0
- package/skills/permdock-agents/SKILL.md +77 -0
- package/skills/permdock-agents/references/runtimes.md +211 -0
- package/skills/permdock-approvals/SKILL.md +80 -0
- package/skills/permdock-approvals/references/stores-and-resume.md +83 -0
- package/skills/permdock-audit/SKILL.md +67 -0
- package/skills/permdock-credentials/SKILL.md +55 -0
- package/skills/permdock-credentials/references/tokens-keys-links.md +127 -0
- package/skills/permdock-data/SKILL.md +57 -0
- package/skills/permdock-data/references/queries-and-rls.md +54 -0
- package/skills/permdock-data/references/relationships.md +65 -0
- package/skills/permdock-tenancy/SKILL.md +77 -0
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +83 -0
- package/skills/permdock-wire/SKILL.md +116 -0
- package/skills/permdock-wire/references/adapters.md +480 -0
- package/skills/permdock-wire/references/policy-options.md +43 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { C as Policy, hr as Subject, mr as Principal } from "./policy-CInmNGkM.js";
|
|
2
|
+
import { c as saasPlans, l as saasRoles, s as saasPermissions } from "./permissions-B8vCg_bI.js";
|
|
3
|
+
//#region src/testing/saas/policy.d.ts
|
|
4
|
+
/** Daily API-key quota per subject; the bucket should be per tenant too. */
|
|
5
|
+
declare const SAAS_API_KEY_LIMIT = 5;
|
|
6
|
+
/**
|
|
7
|
+
* The shared multi-tenant SaaS policy: four tenant roles, a team role, a
|
|
8
|
+
* resource-scoped role, plan-gated features, a closure deny, a quota, an
|
|
9
|
+
* approval and a folder tree shared through edges. Row conditions and
|
|
10
|
+
* relations are portable; the closure is not, and the folder grants need
|
|
11
|
+
* a `RelationSource` (`saasRelations()`).
|
|
12
|
+
*/
|
|
13
|
+
type SaasVocabulary = {
|
|
14
|
+
readonly permissions: typeof saasPermissions;
|
|
15
|
+
readonly roles: typeof saasRoles;
|
|
16
|
+
readonly plans: typeof saasPlans;
|
|
17
|
+
};
|
|
18
|
+
declare const saasPolicy: Policy<Principal | Subject | null, Principal, SaasVocabulary>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { saasPolicy as n, SAAS_API_KEY_LIMIT as t };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { _r as Condition, hr as Subject, tn as WhereResult } from "../policy-CInmNGkM.js";
|
|
2
|
+
import { n as WithSubjectOptions, r as RelationsMapping, t as RowCheck } from "../row-check-BajTgQZ-.js";
|
|
3
|
+
//#region src/prisma/model-fields.d.ts
|
|
4
|
+
/** A model's non-nullable scalar fields and its scalar list fields, by Prisma field name. */
|
|
5
|
+
type PrismaModelFields = {
|
|
6
|
+
readonly required: readonly string[];
|
|
7
|
+
readonly lists: readonly string[];
|
|
8
|
+
};
|
|
9
|
+
/** The `datamodel` of Prisma's DMMF (`getDMMF`, or a generator's `options.dmmf.datamodel`). */
|
|
10
|
+
type PrismaDatamodel = {
|
|
11
|
+
readonly models: readonly {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly fields: readonly {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly kind: string;
|
|
16
|
+
readonly isRequired: boolean;
|
|
17
|
+
readonly isList: boolean;
|
|
18
|
+
}[];
|
|
19
|
+
}[];
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Reads a model's required and list fields from `schema.prisma` text or a DMMF datamodel, for
|
|
23
|
+
* the `model` option of `toWhere` and `toPredicate`. Relation fields are skipped.
|
|
24
|
+
*/
|
|
25
|
+
export declare function prismaModelFields(datamodel: string | PrismaDatamodel, model: string): PrismaModelFields;
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/prisma/to-where.d.ts
|
|
28
|
+
type PrismaWhereOptions = {
|
|
29
|
+
readonly fields?: Readonly<Record<string, string>>;
|
|
30
|
+
readonly subject?: Subject;
|
|
31
|
+
readonly now?: number;
|
|
32
|
+
readonly listFields?: readonly string[];
|
|
33
|
+
readonly requiredFields?: readonly string[];
|
|
34
|
+
/** Required and list fields read from the schema by `prismaModelFields`; adds to `requiredFields` and `listFields`. */
|
|
35
|
+
readonly model?: PrismaModelFields;
|
|
36
|
+
};
|
|
37
|
+
export declare function toWhere<T extends Record<string, unknown> = Record<string, unknown>>(input: Condition | WhereResult, options?: PrismaWhereOptions): T;
|
|
38
|
+
export declare function permdockExtension(): {
|
|
39
|
+
readonly name: "permdock";
|
|
40
|
+
readonly query: {
|
|
41
|
+
readonly $allModels: Record<string, (args: {
|
|
42
|
+
readonly args: Record<string, unknown>;
|
|
43
|
+
readonly query: (next: Record<string, unknown>) => Promise<unknown>;
|
|
44
|
+
}) => Promise<unknown>>;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
type PrismaTransactionClient = {
|
|
48
|
+
$executeRawUnsafe(query: string, ...values: unknown[]): Promise<number>;
|
|
49
|
+
};
|
|
50
|
+
type PrismaLike<Tx> = {
|
|
51
|
+
$transaction<T>(fn: (tx: Tx) => Promise<T>): Promise<T>;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Runs `fn` in an interactive transaction whose role and claims are `permdock.subject`'s, so
|
|
55
|
+
* the generated RLS policies decide for the same subject as the in-process checks.
|
|
56
|
+
*/
|
|
57
|
+
export declare function withSubject<Tx extends PrismaTransactionClient, T>(prisma: PrismaLike<Tx>, permdock: {
|
|
58
|
+
readonly subject: Subject;
|
|
59
|
+
}, fn: (tx: Tx) => Promise<T>, options?: WithSubjectOptions): Promise<T>;
|
|
60
|
+
type PrismaDelegate = {
|
|
61
|
+
findFirst(args: {
|
|
62
|
+
readonly where: Record<string, unknown>;
|
|
63
|
+
}): Promise<unknown>;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Checks one row by its unique key, for `findUnique`, `update` and `delete`, which take no
|
|
67
|
+
* filter: `{ found: false }` when `unique` matches nothing, otherwise whether the permission
|
|
68
|
+
* filter keeps the row. One query when granted, two otherwise.
|
|
69
|
+
*/
|
|
70
|
+
export declare function checkRow(delegate: PrismaDelegate, input: Condition | WhereResult, unique: Record<string, unknown>, options?: PrismaWhereOptions): Promise<RowCheck>;
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/prisma/predicate.d.ts
|
|
73
|
+
/** A Prisma 8 ORM field proxy: `u.email` inside `.where((u) => ...)`. */
|
|
74
|
+
type PrismaFieldProxy = {
|
|
75
|
+
eq(value: unknown): unknown;
|
|
76
|
+
neq(value: unknown): unknown;
|
|
77
|
+
gt(value: unknown): unknown;
|
|
78
|
+
gte(value: unknown): unknown;
|
|
79
|
+
lt(value: unknown): unknown;
|
|
80
|
+
lte(value: unknown): unknown;
|
|
81
|
+
like(pattern: string): unknown;
|
|
82
|
+
in(values: readonly unknown[]): unknown;
|
|
83
|
+
isNull(): unknown;
|
|
84
|
+
isNotNull(): unknown;
|
|
85
|
+
};
|
|
86
|
+
/** `import { and, or, not } from '@prisma/orm-postgres/orm-client'`. */
|
|
87
|
+
type PrismaCombinators = {
|
|
88
|
+
readonly and: (...predicates: unknown[]) => unknown;
|
|
89
|
+
readonly or: (...predicates: unknown[]) => unknown;
|
|
90
|
+
readonly not: (predicate: unknown) => unknown;
|
|
91
|
+
};
|
|
92
|
+
type PrismaPredicateOptions = {
|
|
93
|
+
readonly fields?: Readonly<Record<string, string>>;
|
|
94
|
+
readonly subject?: Subject;
|
|
95
|
+
readonly now?: number;
|
|
96
|
+
/** Required and list fields from `prismaModelFields`; `contains` on a list field is refused. */
|
|
97
|
+
readonly model?: PrismaModelFields;
|
|
98
|
+
readonly listFields?: readonly string[];
|
|
99
|
+
/** A non-null column (the primary key) that spells constant true and false. Default `id`. */
|
|
100
|
+
readonly key?: string;
|
|
101
|
+
/** Loaded from `@prisma/orm-postgres/orm-client` by default. */
|
|
102
|
+
readonly combinators?: PrismaCombinators;
|
|
103
|
+
};
|
|
104
|
+
type Model = Readonly<Record<string, PrismaFieldProxy>>;
|
|
105
|
+
/**
|
|
106
|
+
* Compiles a condition into a Prisma 8 ORM predicate: pass the result to
|
|
107
|
+
* `db.orm.<ns>.<Model>.where(...)`. No grant compiles to a predicate that matches no row.
|
|
108
|
+
*/
|
|
109
|
+
export declare function toPredicate<M = Model>(input: Condition | WhereResult, options?: PrismaPredicateOptions): (model: M) => unknown;
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/conditions/resolve-related.d.ts
|
|
112
|
+
type ResolveRelatedOptions = {
|
|
113
|
+
/**
|
|
114
|
+
* Runs one Postgres query with `$1`-style placeholders and returns its
|
|
115
|
+
* rows; each row's `id` is an id the filtered field may hold. With Prisma:
|
|
116
|
+
* `({ sql, values }) => prisma.$queryRawUnsafe(sql, ...values)`.
|
|
117
|
+
*/
|
|
118
|
+
readonly run: (query: {
|
|
119
|
+
readonly sql: string;
|
|
120
|
+
readonly values: readonly unknown[];
|
|
121
|
+
}) => Promise<readonly Readonly<Record<string, unknown>>[]>;
|
|
122
|
+
/** Where the relation graph lives. */
|
|
123
|
+
readonly relations?: RelationsMapping;
|
|
124
|
+
/** Turns an id (always text) into the field's type, e.g. `Number` for an integer key. */
|
|
125
|
+
readonly parse?: (id: string, field: string) => unknown;
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* `where` with every `related` node replaced by the ids it reaches, read in
|
|
129
|
+
* one query per node, so an ORM without raw subqueries (Prisma) filters the
|
|
130
|
+
* graph with a plain `in`. The ids are read now: run the filtered query right
|
|
131
|
+
* after, in the same transaction when the graph may change in between.
|
|
132
|
+
*/
|
|
133
|
+
export declare function resolveRelated(where: WhereResult, options: ResolveRelatedOptions): Promise<WhereResult>;
|
|
134
|
+
//#endregion
|
|
135
|
+
export type { PrismaCombinators, PrismaDatamodel, PrismaFieldProxy, PrismaModelFields, PrismaPredicateOptions, PrismaWhereOptions, ResolveRelatedOptions, RowCheck, WithSubjectOptions };
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import { t as compact } from "../compact-y6vfu2_f.js";
|
|
2
|
+
import { n as freezeDeep } from "../freeze-y1_jQL4v.js";
|
|
3
|
+
import { x as assertSafeKey } from "../permissions-DC7GROPA.js";
|
|
4
|
+
import { i as PermDockValidationError } from "../errors-Iy71s7Oj.js";
|
|
5
|
+
import { a as relatedRowGuard, l as renderGraphSql, n as escapeLike, s as relatedTargetsSql, t as compileWhere } from "../compile-D22iwvuV.js";
|
|
6
|
+
import { a as rowCheckOf, n as statementText, r as subjectStatements } from "../subject-settings-xt7V845g.js";
|
|
7
|
+
//#region src/prisma/to-where.ts
|
|
8
|
+
function fieldTests(options) {
|
|
9
|
+
const mapped = (field) => fieldName(field, options.fields);
|
|
10
|
+
return {
|
|
11
|
+
required: (field) => options.requiredFields?.includes(field) === true || options.model?.required.includes(mapped(field)) === true,
|
|
12
|
+
list: (field) => options.listFields?.includes(field) === true || options.model?.lists.includes(mapped(field)) === true
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const EMPTY_OR = { OR: [] };
|
|
16
|
+
function fieldName(field, fields) {
|
|
17
|
+
assertSafeKey(field, "condition field");
|
|
18
|
+
return fields?.[field] ?? field;
|
|
19
|
+
}
|
|
20
|
+
const NEVER = { kind: "never" };
|
|
21
|
+
const ALWAYS = { kind: "always" };
|
|
22
|
+
function foldRequired(node, required) {
|
|
23
|
+
switch (node.kind) {
|
|
24
|
+
case "isNull":
|
|
25
|
+
if (!required(node.field)) return node;
|
|
26
|
+
return node.negated ? ALWAYS : NEVER;
|
|
27
|
+
case "and": {
|
|
28
|
+
const items = node.items.map((item) => foldRequired(item, required)).filter((item) => item.kind !== "always");
|
|
29
|
+
if (items.some((item) => item.kind === "never")) return NEVER;
|
|
30
|
+
return items.length === 0 ? ALWAYS : items.length === 1 ? items[0] : {
|
|
31
|
+
kind: "and",
|
|
32
|
+
items
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
case "or": {
|
|
36
|
+
const items = node.items.map((item) => foldRequired(item, required)).filter((item) => item.kind !== "never");
|
|
37
|
+
if (items.some((item) => item.kind === "always")) return ALWAYS;
|
|
38
|
+
return items.length === 0 ? NEVER : items.length === 1 ? items[0] : {
|
|
39
|
+
kind: "or",
|
|
40
|
+
items
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
case "not": {
|
|
44
|
+
const item = foldRequired(node.item, required);
|
|
45
|
+
return item.kind === "never" ? ALWAYS : item.kind === "always" ? NEVER : {
|
|
46
|
+
kind: "not",
|
|
47
|
+
item
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
case "never":
|
|
51
|
+
case "always":
|
|
52
|
+
case "exists":
|
|
53
|
+
case "compare":
|
|
54
|
+
case "sql": return node;
|
|
55
|
+
/* v8 ignore next 6 */
|
|
56
|
+
default: throw new Error(`PermDock: unknown compiled node '${String(node)}'`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function render$1(node, options, tests) {
|
|
60
|
+
switch (node.kind) {
|
|
61
|
+
case "never": return { ...EMPTY_OR };
|
|
62
|
+
case "always": return {};
|
|
63
|
+
case "isNull": {
|
|
64
|
+
const name = fieldName(node.field, options.fields);
|
|
65
|
+
return node.negated ? { [name]: { not: null } } : { [name]: { equals: null } };
|
|
66
|
+
}
|
|
67
|
+
case "and": return { AND: node.items.map((item) => render$1(item, options, tests)) };
|
|
68
|
+
case "or": return { OR: node.items.map((item) => render$1(item, options, tests)) };
|
|
69
|
+
case "not": return { NOT: render$1(node.item, options, tests) };
|
|
70
|
+
/* v8 ignore next 6 */
|
|
71
|
+
case "exists": return { [fieldName(node.rowField, options.fields)]: { in: [] } };
|
|
72
|
+
/* v8 ignore next 2 */
|
|
73
|
+
case "sql": return { ...EMPTY_OR };
|
|
74
|
+
case "compare": {
|
|
75
|
+
const name = fieldName(node.field, options.fields);
|
|
76
|
+
switch (node.op) {
|
|
77
|
+
case "eq": return { [name]: { equals: node.value } };
|
|
78
|
+
case "ne": return { [name]: { not: node.value } };
|
|
79
|
+
case "gt": return { [name]: { gt: node.value } };
|
|
80
|
+
case "gte": return { [name]: { gte: node.value } };
|
|
81
|
+
case "lt": return { [name]: { lt: node.value } };
|
|
82
|
+
case "lte": return { [name]: { lte: node.value } };
|
|
83
|
+
case "in": return { [name]: { in: node.value } };
|
|
84
|
+
case "notIn": return { [name]: { notIn: node.value } };
|
|
85
|
+
case "contains": return tests.list(node.field) ? { [name]: { has: node.value } } : { [name]: { contains: typeof node.value === "string" ? escapeLike(node.value) : node.value } };
|
|
86
|
+
/* v8 ignore next 4 */
|
|
87
|
+
default: {
|
|
88
|
+
const exhaustive = node.op;
|
|
89
|
+
throw new Error(`PermDock: unknown compare '${String(exhaustive)}'`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/* v8 ignore next 6 */
|
|
94
|
+
default: throw new Error(`PermDock: unknown compiled node '${String(node)}'`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function containsEmptyOr(value) {
|
|
98
|
+
if (value === null || typeof value !== "object") return false;
|
|
99
|
+
if (Array.isArray(value)) return value.some((item) => containsEmptyOr(item));
|
|
100
|
+
const record = value;
|
|
101
|
+
if (Array.isArray(record["OR"]) && record["OR"].length === 0) return true;
|
|
102
|
+
return Object.values(record).some((item) => containsEmptyOr(item));
|
|
103
|
+
}
|
|
104
|
+
function rewriteEmptyOr(args) {
|
|
105
|
+
const where = args["where"];
|
|
106
|
+
if (where === void 0 || !containsEmptyOr(where)) return args;
|
|
107
|
+
return {
|
|
108
|
+
...args,
|
|
109
|
+
where: {
|
|
110
|
+
AND: [where, EMPTY_OR],
|
|
111
|
+
OR: []
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function toWhere(input, options = {}) {
|
|
116
|
+
const compiled = compileWhere(input, compact({
|
|
117
|
+
subject: options.subject,
|
|
118
|
+
now: options.now
|
|
119
|
+
}));
|
|
120
|
+
const tests = fieldTests(options);
|
|
121
|
+
return render$1(foldRequired(compiled, tests.required), options, tests);
|
|
122
|
+
}
|
|
123
|
+
function wrap({ args, query }) {
|
|
124
|
+
return query(rewriteEmptyOr(args));
|
|
125
|
+
}
|
|
126
|
+
function permdockExtension() {
|
|
127
|
+
return {
|
|
128
|
+
name: "permdock",
|
|
129
|
+
query: { $allModels: {
|
|
130
|
+
findMany: wrap,
|
|
131
|
+
findFirst: wrap,
|
|
132
|
+
count: wrap,
|
|
133
|
+
aggregate: wrap,
|
|
134
|
+
updateMany: wrap,
|
|
135
|
+
deleteMany: wrap
|
|
136
|
+
} }
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Runs `fn` in an interactive transaction whose role and claims are `permdock.subject`'s, so
|
|
141
|
+
* the generated RLS policies decide for the same subject as the in-process checks.
|
|
142
|
+
*/
|
|
143
|
+
function withSubject(prisma, permdock, fn, options = {}) {
|
|
144
|
+
const statements = subjectStatements(permdock, options);
|
|
145
|
+
return prisma.$transaction(async (tx) => {
|
|
146
|
+
for (const statement of statements) await tx.$executeRawUnsafe(statementText(statement), ...statement.values);
|
|
147
|
+
return fn(tx);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Checks one row by its unique key, for `findUnique`, `update` and `delete`, which take no
|
|
152
|
+
* filter: `{ found: false }` when `unique` matches nothing, otherwise whether the permission
|
|
153
|
+
* filter keeps the row. One query when granted, two otherwise.
|
|
154
|
+
*/
|
|
155
|
+
async function checkRow(delegate, input, unique, options = {}) {
|
|
156
|
+
const filter = toWhere(input, options);
|
|
157
|
+
const kept = await delegate.findFirst(rewriteEmptyOr({ where: { AND: [unique, filter] } }));
|
|
158
|
+
if (kept !== null && kept !== void 0) return rowCheckOf(true, true);
|
|
159
|
+
const row = await delegate.findFirst({ where: unique });
|
|
160
|
+
return rowCheckOf(row !== null && row !== void 0, false);
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/prisma/predicate.ts
|
|
164
|
+
function loadCombinators(injected) {
|
|
165
|
+
if (injected !== void 0) return injected;
|
|
166
|
+
const loader = globalThis.process?.getBuiltinModule?.("node:module");
|
|
167
|
+
try {
|
|
168
|
+
if (loader === void 0) throw new Error("no module loader");
|
|
169
|
+
return loader.createRequire(import.meta.url)("@prisma/orm-postgres/orm-client");
|
|
170
|
+
} catch {
|
|
171
|
+
throw new Error("PermDock: toPredicate needs @prisma/orm-postgres; pass `combinators` on runtimes without require");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function refused$1(detail) {
|
|
175
|
+
return new PermDockValidationError({
|
|
176
|
+
code: "non-portable-condition",
|
|
177
|
+
permission: "",
|
|
178
|
+
resource: "",
|
|
179
|
+
boundary: "where",
|
|
180
|
+
message: `PermDock: non-portable-condition: ${detail}`
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function render(node, model, options, ops) {
|
|
184
|
+
const proxy = (field) => {
|
|
185
|
+
assertSafeKey(field, "condition field");
|
|
186
|
+
const name = options.fields?.[field] ?? field;
|
|
187
|
+
assertSafeKey(name, "Prisma field");
|
|
188
|
+
const value = model[name];
|
|
189
|
+
if (value === void 0) throw refused$1(`no field '${name}' on the Prisma model`);
|
|
190
|
+
return value;
|
|
191
|
+
};
|
|
192
|
+
const key = () => proxy(options.key ?? "id");
|
|
193
|
+
switch (node.kind) {
|
|
194
|
+
case "never": return key().isNull();
|
|
195
|
+
case "always": return key().isNotNull();
|
|
196
|
+
case "isNull": return node.negated ? proxy(node.field).isNotNull() : proxy(node.field).isNull();
|
|
197
|
+
case "and": return ops.and(...node.items.map((item) => render(item, model, options, ops)));
|
|
198
|
+
case "or": return ops.or(...node.items.map((item) => render(item, model, options, ops)));
|
|
199
|
+
case "not": return ops.not(render(node.item, model, options, ops));
|
|
200
|
+
/* v8 ignore start */
|
|
201
|
+
case "exists": throw refused$1("memberOf with a memberships table");
|
|
202
|
+
case "sql": throw refused$1("relationship grant; resolve it first with resolveRelated");
|
|
203
|
+
/* v8 ignore stop */
|
|
204
|
+
case "compare": {
|
|
205
|
+
const field = proxy(node.field);
|
|
206
|
+
switch (node.op) {
|
|
207
|
+
case "eq": return field.eq(node.value);
|
|
208
|
+
case "ne": return field.neq(node.value);
|
|
209
|
+
case "gt": return field.gt(node.value);
|
|
210
|
+
case "gte": return field.gte(node.value);
|
|
211
|
+
case "lt": return field.lt(node.value);
|
|
212
|
+
case "lte": return field.lte(node.value);
|
|
213
|
+
case "in": {
|
|
214
|
+
const values = node.value;
|
|
215
|
+
return values.length === 0 ? key().isNull() : field.in(values);
|
|
216
|
+
}
|
|
217
|
+
case "notIn": {
|
|
218
|
+
const values = node.value;
|
|
219
|
+
return values.length === 0 ? key().isNotNull() : ops.not(field.in(values));
|
|
220
|
+
}
|
|
221
|
+
case "contains": {
|
|
222
|
+
const name = options.fields?.[node.field] ?? node.field;
|
|
223
|
+
if (options.listFields?.includes(node.field) === true || options.model?.lists.includes(name) === true) throw refused$1(`contains on the list field '${name}'`);
|
|
224
|
+
if (typeof node.value !== "string") throw refused$1(`contains with a non-string value on '${name}'`);
|
|
225
|
+
return field.like(`%${escapeLike(node.value)}%`);
|
|
226
|
+
}
|
|
227
|
+
/* v8 ignore next 4 */
|
|
228
|
+
default: {
|
|
229
|
+
const exhaustive = node.op;
|
|
230
|
+
throw new Error(`PermDock: unknown compare '${String(exhaustive)}'`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/* v8 ignore next 6 */
|
|
235
|
+
default: throw new Error(`PermDock: unknown compiled node '${String(node)}'`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Compiles a condition into a Prisma 8 ORM predicate: pass the result to
|
|
240
|
+
* `db.orm.<ns>.<Model>.where(...)`. No grant compiles to a predicate that matches no row.
|
|
241
|
+
*/
|
|
242
|
+
function toPredicate(input, options = {}) {
|
|
243
|
+
const compiled = compileWhere(input, compact({
|
|
244
|
+
subject: options.subject,
|
|
245
|
+
now: options.now
|
|
246
|
+
}));
|
|
247
|
+
const ops = loadCombinators(options.combinators);
|
|
248
|
+
return (model) => render(compiled, model, options, ops);
|
|
249
|
+
}
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/prisma/model-fields.ts
|
|
252
|
+
const BLOCK = /^\s*(model|type|view)\s+([A-Za-z_]\w*)\s*\{/u;
|
|
253
|
+
const FIELD = /^\s*([A-Za-z_]\w*)\s+([A-Za-z_][\w.:]*)(\([^)]*\))?(\[\])?(\?)?/u;
|
|
254
|
+
function fromSchema(schema, model) {
|
|
255
|
+
const lines = schema.split(/\r?\n/u);
|
|
256
|
+
const composite = /* @__PURE__ */ new Set();
|
|
257
|
+
for (const line of lines) {
|
|
258
|
+
const block = BLOCK.exec(line);
|
|
259
|
+
if (block !== null) composite.add(block[2] ?? "");
|
|
260
|
+
}
|
|
261
|
+
const required = [];
|
|
262
|
+
const lists = [];
|
|
263
|
+
let inside = false;
|
|
264
|
+
let found = false;
|
|
265
|
+
for (const line of lines) {
|
|
266
|
+
const code = line.replace(/\/\/.*$/u, "").trim();
|
|
267
|
+
if (!inside) {
|
|
268
|
+
const block = BLOCK.exec(code);
|
|
269
|
+
if (block?.[1] === "model" && block[2] === model) {
|
|
270
|
+
inside = true;
|
|
271
|
+
found = true;
|
|
272
|
+
}
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (code === "}") break;
|
|
276
|
+
if (code === "" || code.startsWith("@@")) continue;
|
|
277
|
+
const field = FIELD.exec(code);
|
|
278
|
+
if (field === null) continue;
|
|
279
|
+
const [, name = "", type = "", , list, optional] = field;
|
|
280
|
+
if (type.includes(":") || composite.has(type)) continue;
|
|
281
|
+
if (list !== void 0) lists.push(name);
|
|
282
|
+
else if (optional === void 0) required.push(name);
|
|
283
|
+
}
|
|
284
|
+
return found ? {
|
|
285
|
+
required,
|
|
286
|
+
lists
|
|
287
|
+
} : void 0;
|
|
288
|
+
}
|
|
289
|
+
function fromDatamodel(datamodel, model) {
|
|
290
|
+
const found = datamodel.models.find((item) => item.name === model);
|
|
291
|
+
if (found === void 0) return;
|
|
292
|
+
const scalars = found.fields.filter((field) => field.kind === "scalar" || field.kind === "enum");
|
|
293
|
+
return {
|
|
294
|
+
required: scalars.filter((field) => field.isRequired && !field.isList).map((field) => field.name),
|
|
295
|
+
lists: scalars.filter((field) => field.isList).map((field) => field.name)
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Reads a model's required and list fields from `schema.prisma` text or a DMMF datamodel, for
|
|
300
|
+
* the `model` option of `toWhere` and `toPredicate`. Relation fields are skipped.
|
|
301
|
+
*/
|
|
302
|
+
function prismaModelFields(datamodel, model) {
|
|
303
|
+
assertSafeKey(model, "Prisma model");
|
|
304
|
+
const fields = typeof datamodel === "string" ? fromSchema(datamodel, model) : fromDatamodel(datamodel, model);
|
|
305
|
+
if (fields === void 0) throw new Error(`PermDock: Prisma model '${model}' is not in the datamodel`);
|
|
306
|
+
return Object.freeze({
|
|
307
|
+
required: Object.freeze(fields.required),
|
|
308
|
+
lists: Object.freeze(fields.lists)
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/conditions/resolve-related.ts
|
|
313
|
+
const NOTHING = {
|
|
314
|
+
op: "or",
|
|
315
|
+
conditions: []
|
|
316
|
+
};
|
|
317
|
+
function notRestricted(column) {
|
|
318
|
+
return {
|
|
319
|
+
op: "or",
|
|
320
|
+
conditions: [{
|
|
321
|
+
op: "eq",
|
|
322
|
+
field: column,
|
|
323
|
+
value: false
|
|
324
|
+
}, {
|
|
325
|
+
op: "isNull",
|
|
326
|
+
field: column,
|
|
327
|
+
value: true
|
|
328
|
+
}]
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function refused(detail) {
|
|
332
|
+
return new PermDockValidationError({
|
|
333
|
+
code: "non-portable-condition",
|
|
334
|
+
permission: "",
|
|
335
|
+
resource: "",
|
|
336
|
+
boundary: "where",
|
|
337
|
+
message: `PermDock: non-portable-condition: ${detail}`
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* `where` with every `related` node replaced by the ids it reaches, read in
|
|
342
|
+
* one query per node, so an ORM without raw subqueries (Prisma) filters the
|
|
343
|
+
* graph with a plain `in`. The ids are read now: run the filtered query right
|
|
344
|
+
* after, in the same transaction when the graph may change in between.
|
|
345
|
+
*/
|
|
346
|
+
async function resolveRelated(where, options) {
|
|
347
|
+
const resources = where.resources;
|
|
348
|
+
const subject = where.subject?.principal?.id;
|
|
349
|
+
async function resolveNode(node) {
|
|
350
|
+
if (resources === void 0) throw refused("related: the where() result carries no resource graph");
|
|
351
|
+
if (node.ids === void 0 && (subject === void 0 || subject === "")) return NOTHING;
|
|
352
|
+
const query = renderGraphSql(relatedTargetsSql(node, {
|
|
353
|
+
...options.relations,
|
|
354
|
+
resources
|
|
355
|
+
}), {
|
|
356
|
+
subject: subject ?? "",
|
|
357
|
+
placeholder: (index) => `$${String(index)}`,
|
|
358
|
+
/* v8 ignore next 3 */
|
|
359
|
+
column: (name) => {
|
|
360
|
+
throw refused(`related: no row column '${name}' in an id query`);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
const ids = (await options.run({
|
|
364
|
+
sql: `select distinct r.id from (${query.sql}) r where r.id is not null`,
|
|
365
|
+
values: query.values
|
|
366
|
+
})).flatMap((row) => {
|
|
367
|
+
const id = row["id"];
|
|
368
|
+
if (typeof id !== "string" && typeof id !== "number") return [];
|
|
369
|
+
const text = String(id);
|
|
370
|
+
const parsed = options.parse === void 0 ? text : options.parse(text, node.field);
|
|
371
|
+
return typeof parsed === "string" || typeof parsed === "number" || typeof parsed === "boolean" ? [parsed] : [];
|
|
372
|
+
});
|
|
373
|
+
const reach = ids.length === 0 ? NOTHING : {
|
|
374
|
+
op: "in",
|
|
375
|
+
field: node.field,
|
|
376
|
+
value: ids
|
|
377
|
+
};
|
|
378
|
+
const guard = relatedRowGuard(node);
|
|
379
|
+
return guard === void 0 || ids.length === 0 ? reach : {
|
|
380
|
+
op: "and",
|
|
381
|
+
conditions: [reach, notRestricted(guard)]
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
async function resolve(node) {
|
|
385
|
+
switch (node.op) {
|
|
386
|
+
case "related": return resolveNode(node);
|
|
387
|
+
case "and":
|
|
388
|
+
case "or": return {
|
|
389
|
+
op: node.op,
|
|
390
|
+
conditions: await Promise.all(node.conditions.map(resolve))
|
|
391
|
+
};
|
|
392
|
+
case "not": return {
|
|
393
|
+
op: "not",
|
|
394
|
+
condition: await resolve(node.condition)
|
|
395
|
+
};
|
|
396
|
+
case "sqlFunction": return {
|
|
397
|
+
...node,
|
|
398
|
+
twin: await resolve(node.twin)
|
|
399
|
+
};
|
|
400
|
+
case "eq":
|
|
401
|
+
case "ne":
|
|
402
|
+
case "gt":
|
|
403
|
+
case "gte":
|
|
404
|
+
case "lt":
|
|
405
|
+
case "lte":
|
|
406
|
+
case "contains":
|
|
407
|
+
case "in":
|
|
408
|
+
case "notIn":
|
|
409
|
+
case "isNull":
|
|
410
|
+
case "memberOf":
|
|
411
|
+
case "opaque": return node;
|
|
412
|
+
default: return node;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const out = {
|
|
416
|
+
condition: await resolve(where.condition),
|
|
417
|
+
partial: where.partial
|
|
418
|
+
};
|
|
419
|
+
for (const key of [
|
|
420
|
+
"subject",
|
|
421
|
+
"scopes",
|
|
422
|
+
"resources"
|
|
423
|
+
]) if (where[key] !== void 0) Object.defineProperty(out, key, {
|
|
424
|
+
value: where[key],
|
|
425
|
+
enumerable: false
|
|
426
|
+
});
|
|
427
|
+
return freezeDeep(out);
|
|
428
|
+
}
|
|
429
|
+
//#endregion
|
|
430
|
+
export { checkRow, permdockExtension, prismaModelFields, resolveRelated, toPredicate, toWhere, withSubject };
|