@liquisio/wix-access 0.2.0 → 0.3.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 CHANGED
@@ -1,19 +1,168 @@
1
- # @liquisio/wix-access (probe stub)
1
+ # @liquisio/wix-access
2
2
 
3
- Not the real package. This stub exists to prove the packaging on a real Wix site
4
- before the real `wix-access` package is built. See `../PROBES.md`.
3
+ One authorization policy, serving the Wix web-method gate, your backend, the
4
+ database and your page code.
5
5
 
6
- Layout: `backend.js` and `public.js` are the two real bundles, `index.js` is a
7
- one-line alias to `backend.js`. The pure core under `source/core/` is bundled
8
- into both. `wix-*` and `@wix/*` stay external; `@casl/ability` is inlined.
6
+ Built against **measured** platform behaviour, not documentation: nine probe runs
7
+ on a real published site, recorded in [`../PROBES.md`](../PROBES.md), with the
8
+ resulting constraints in [`../CLAUDE.md`](../CLAUDE.md). Several things the docs
9
+ imply do not hold, and this package is shaped around the ones that do.
9
10
 
11
+ ## Install
12
+
13
+ ```bash
14
+ wix install @liquisio/wix-access
15
+ wix install @casl/ability @wix/data @wix/essentials
16
+ ```
17
+
18
+ ## The two wiring files
19
+
20
+ The package cannot find your policy or your web method: Velo forbids dynamic
21
+ imports and this bundle is built separately, so `public/access-policy` and
22
+ `backend/access.web` resolve only inside *your* project. You inject both.
23
+
24
+ **1. The policy — plain data, no imports**
25
+
26
+ ```js
27
+ // public/access-policy.js
28
+ /** @type {import('@liquisio/wix-access').Policy} */
29
+ export default {
30
+ subjects: {
31
+ visitor: { when: 'anonymous' },
32
+ member: { when: 'member' },
33
+ admin: { role: 'Admin' },
34
+ vendorStaff: { domain: 'vendorStaff' }
35
+ },
36
+ collections: {
37
+ Bookings: { resource: 'Booking', owner: 'customerId' }
38
+ },
39
+ rules: [
40
+ { subject: 'member', actions: ['read', 'cancel'], resource: 'Booking', where: { customerId: '$principal.memberId' } },
41
+ { subject: 'vendorStaff', actions: ['read', 'refund'], resource: 'Booking', where: { vendor: { $in: '$principal.domain.vendorIds' } } },
42
+ { subject: 'admin', actions: 'manage', resource: 'all' }
43
+ ],
44
+ api: {
45
+ getAvailableSlots: { permission: 'Anyone' },
46
+ cancelBooking: { permission: 'SiteMember', ability: ['cancel', 'Booking'] },
47
+ refundBooking: { permission: 'Admin', ability: ['refund', 'Booking'] }
48
+ }
49
+ }
50
+ ```
51
+
52
+ It lives in `public/` because that is the one folder both sides can import, and
53
+ it carries no runtime import so it bundles into either.
54
+
55
+ **2. Backend wiring**
56
+
57
+ ```js
58
+ // backend/access.js
59
+ import { createAccess } from '@liquisio/wix-access/backend'
60
+ import policy from 'public/access-policy'
61
+
62
+ export const { guarded, resolveCaller, db, rulesForCaller } = createAccess(policy, {
63
+ // Optional: add your own domain facts to the caller.
64
+ enrich: async (principal) => ({ vendorStaff: true, vendorIds: ['v-1'] }),
65
+ // Log refusals. Nothing else records OUR decisions — the platform logs only its own.
66
+ audit: (e) => console.warn('[access]', e.action, e.code, e.caller)
67
+ })
68
+ ```
69
+
70
+ `createAccess` validates the policy at import time, so a malformed policy fails
71
+ the **release** rather than a request.
72
+
73
+ ## Using it
74
+
75
+ **Web methods** — the gate comes from `policy.api`, the ownership check from the rules.
76
+
77
+ ```js
78
+ // backend/api.web.js
79
+ import { guarded } from 'backend/access'
80
+ import { cancelBooking as _cancel, getBooking } from 'backend/booking-service'
81
+
82
+ export const cancelBooking = guarded(
83
+ 'cancelBooking',
84
+ async ({ principal, subject }, id, options) =>
85
+ _cancel(id, { ...options, cancelledBy: principal.memberId }),
86
+ {
87
+ load: (id) => getBooking(id),
88
+ // Keys the server decides for itself. Without this a caller can smuggle
89
+ // a fee waiver past the check.
90
+ strip: ['deductFees', 'processRefund']
91
+ }
92
+ )
93
+ ```
94
+
95
+ A method missing from `policy.api` throws at construction, so an undocumented
96
+ gate fails the build.
97
+
98
+ **Data** — elevation and authorization together, so neither is used without the other.
99
+
100
+ ```js
101
+ import { db, resolveCaller } from 'backend/access'
102
+
103
+ const principal = await resolveCaller()
104
+ const { data: mine } = await db.query('Bookings', { principal }) // filtered to this caller
105
+ const result = await db.get('Bookings', id, { principal }) // opaque refusal if not theirs
106
+ await db.insert('Bookings', row, { principal, action: 'create' }) // stamps the owner field
107
+ ```
108
+
109
+ **Page code** — the same rules, so the UI agrees with the server.
110
+
111
+ ```js
112
+ // backend/access.web.js
113
+ import { webMethod, Permissions } from 'wix-web-module'
114
+ import { rulesForCaller } from 'backend/access'
115
+ export const getMyAbilities = webMethod(Permissions.Anyone, () => rulesForCaller())
116
+ ```
117
+
118
+ ```js
119
+ // pages/MyBookings.js
120
+ import { createAccess } from '@liquisio/wix-access/public'
121
+ import { getMyAbilities } from 'backend/access.web'
122
+
123
+ const access = createAccess({ fetchRules: getMyAbilities })
124
+
125
+ $w.onReady(async () => {
126
+ await access.ready()
127
+ access.guard($w('#cancelBtn'), 'cancel', 'Booking', booking)
128
+ })
10
129
  ```
11
- npm install
12
- npm run verify # build + node --test
13
- npm publish
130
+
131
+ ## Things worth knowing
132
+
133
+ Each is measured, and each will bite otherwise.
134
+
135
+ - **Refusals are returned, never thrown.** A thrown backend error reaches the
136
+ browser as "Unable to handle the request" with the reason discarded. Check
137
+ `result.ok`.
138
+ - **A refusal on a caller-supplied id is opaque.** Forbidden and not-found return
139
+ the same code, so refusals cannot be used to enumerate ids.
140
+ - **`_owner` is unusable.** Every elevated write stores `_owner: null`, and the
141
+ app must write elevated. Declare `owner` on the collection and the gateway
142
+ stamps it explicitly.
143
+ - **`update` is checked against the stored row**, never the submitted one, so a
144
+ caller cannot authorise themselves by sending an owner field they do not own.
145
+ - **"Could not verify" is not "not allowed".** A failed roles read or enricher
146
+ yields `UNVERIFIED`, which a caller may retry. Do not collapse the two.
147
+ - **Two different admins.** `Permissions.Admin` means a site member holding the
148
+ Admin role. A collection ACL's `ADMIN` means a Wix user. They do not line up.
149
+ - **Elevation wraps SDK method references only.** `auth.elevate(items.query)`
150
+ works; `auth.elevate(() => q.find())` throws.
151
+
152
+ ## Not in this version
153
+
154
+ Measured as impossible from an installed app, rather than merely unbuilt:
155
+ collection ACLs cannot be written from code, member roles cannot be created or
156
+ assigned from code, and data hooks never fire for app-namespaced collections.
157
+ Set ACLs and roles in the CMS and dashboard. Guest capability tokens and
158
+ custom-role end-to-end flows are simply untested.
159
+
160
+ ## Development
161
+
162
+ ```bash
163
+ npm install && npm run verify # build both bundles, then 60 tests
14
164
  ```
15
165
 
16
- On the site: `wix install @liquisio/wix-access` (and `wix install @casl/ability`
17
- for the direct-import comparison), then copy `probes/probes-pkg.web.js` to
18
- `src/backend/` and `probes/pkg-probe.js` to `src/public/`, and uncomment the two
19
- lines at the top of the widget.
166
+ `backend.js` and `public.js` are the two real bundles; `index.js` is a one-line
167
+ alias so npm's `main` resolves. The core is bundled into both and must stay
168
+ pure — the purity test enforces it.
package/backend.d.ts ADDED
@@ -0,0 +1,65 @@
1
+ export * from './types'
2
+ import { Policy, Principal, Ability, SerialisedRule, Result, Clause, Scope } from './types'
3
+
4
+ export interface AuditEvent {
5
+ event: 'access.denied'
6
+ action: string
7
+ code: string
8
+ caller: string | null
9
+ detail?: unknown
10
+ }
11
+
12
+ export interface CreateAccessOptions {
13
+ /** Adds domain facts to the Principal — vendor membership, tenancy, staff rows. */
14
+ enrich?: (principal: Principal) => Promise<Record<string, unknown>>
15
+ /** Called on every refusal. Log it: nothing else records OUR decisions. */
16
+ audit?: (event: AuditEvent) => void
17
+ /** Called when identity resolution or a guard fails internally. */
18
+ onError?: (stage: string, error: unknown) => void
19
+ /** Override the injected Wix modules. Tests only. */
20
+ deps?: Record<string, unknown>
21
+ }
22
+
23
+ export interface GuardConfig<A extends unknown[] = unknown[]> {
24
+ /** Loads the row the ability is tested against. Returning null gives an opaque refusal. */
25
+ load?: (...args: A) => Promise<unknown>
26
+ /** Caller-supplied keys stripped from object arguments before the handler sees them. */
27
+ strip?: string[]
28
+ }
29
+
30
+ export interface DbOptions {
31
+ principal: Principal
32
+ action?: string
33
+ limit?: number
34
+ }
35
+
36
+ export interface Db {
37
+ query(collection: string, opts: DbOptions): Promise<{ ok: true; data: unknown[]; scope: Scope }>
38
+ get(collection: string, id: string, opts: DbOptions): Promise<Result<unknown>>
39
+ insert(collection: string, record: Record<string, unknown>, opts: DbOptions): Promise<Result<unknown>>
40
+ update(collection: string, id: string, changes: Record<string, unknown>, opts: DbOptions): Promise<Result<unknown>>
41
+ remove(collection: string, id: string, opts: DbOptions): Promise<Result<unknown>>
42
+ }
43
+
44
+ export interface Access {
45
+ policy: Policy
46
+ resolveCaller(): Promise<Principal>
47
+ abilityFor(principal: Principal): Ability
48
+ guarded<A extends unknown[], R>(
49
+ name: string,
50
+ handler: (ctx: { principal: Principal; subject: unknown }, ...args: A) => Promise<R>,
51
+ config?: GuardConfig<A>
52
+ ): (...args: A) => Promise<R | { ok: false; code: string }>
53
+ db: Db
54
+ /** Hand these to page code from a web method. Plain JSON. */
55
+ rulesForCaller(): Promise<SerialisedRule[]>
56
+ }
57
+
58
+ export declare function createAccess(policy: Policy, options?: CreateAccessOptions): Access
59
+ /** Fails the build when an exported web method is missing from policy.api. */
60
+ export declare function assertDeclared(policy: Policy, exportedNames: string[]): true
61
+
62
+ export declare function backendPing(): { ok: boolean; side: string; version: string }
63
+ export declare function backendMemberId(): Promise<string | null>
64
+ export declare function caseTable(ability: Ability): Array<{ action: string; type: string; object: object; can: boolean }>
65
+ export declare const CASES: Array<{ action: string; type: string; object: object }>
package/backend.js CHANGED
@@ -1 +1 @@
1
- var T=Object.defineProperty;var Ye=Object.getOwnPropertyDescriptor;var He=Object.getOwnPropertyNames;var We=Object.prototype.hasOwnProperty;var Xe=(t,e)=>{for(var r in e)T(t,r,{get:e[r],enumerable:!0})},Ze=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of He(e))!We.call(t,s)&&s!==r&&T(t,s,{get:()=>e[s],enumerable:!(n=Ye(e,s))||n.enumerable});return t};var et=t=>Ze(T({},"__esModule",{value:!0}),t);var Lt={};Xe(Lt,{CASES:()=>we,PACKAGE_VERSION:()=>be,abilityFor:()=>Je,abilityFromRules:()=>ve,backendMemberId:()=>Dt,backendPing:()=>zt,caseTable:()=>Qe,resolvePlaceholders:()=>v,rulesFor:()=>$e});module.exports=et(Lt);var Ge=require("wix-members-backend");var w=class{constructor(e,r){this.operator=e,this.value=r,Object.defineProperty(this,"t",{writable:!0})}get notes(){return this.t}addNote(e){this.t=this.t||[],this.t.push(e)}},y=class extends w{},p=class extends y{constructor(e,r){if(!Array.isArray(r))throw new Error(`"${e}" operator expects to receive an array of conditions`);super(e,r)}},l="__itself__",f=class extends w{constructor(e,r,n){super(e,n),this.field=r}},k=new y("__null__",null),R=Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function tt(t,e){return e instanceof p&&e.operator===t}function q(t,e){return e.length===1?e[0]:new p(t,(function r(n,s,o){let i=o||[];for(let a=0,c=s.length;a<c;a++){let u=s[a];tt(n,u)?r(n,u.value,i):i.push(u)}return i})(t,e))}var rt=t=>t,xe=()=>Object.create(null),je=Object.defineProperty(xe(),"__@type@__",{value:"ignore value"});function nt(t,e,r=!1){if(!t||t&&t.constructor!==Object)return!1;for(let n in t)if(R(t,n)&&R(e,n)&&(!r||t[n]!==je))return!0;return!1}function st(t){let e=[];for(let r in t)R(t,r)&&t[r]!==je&&e.push(r);return e}function N(t,e){e!==k&&t.push(e)}var z=t=>q("and",t);var x={compound(t,e,r){let n=(Array.isArray(e)?e:[e]).map(s=>r.parse(s));return new p(t.name,n)},field:(t,e,r)=>new f(t.name,r.field,e),document:(t,e)=>new y(t.name,e)},g=class{constructor(e,r=xe()){this.o=void 0,this.s=void 0,this.i=void 0,this.u=void 0,this.h=void 0,this.parse=this.parse.bind(this),this.u={operatorToConditionName:r.operatorToConditionName||rt,defaultOperatorName:r.defaultOperatorName||"eq",mergeFinalConditions:r.mergeFinalConditions||z},this.o=Object.keys(e).reduce((n,s)=>(n[s]=Object.assign({name:this.u.operatorToConditionName(s)},e[s]),n),{}),this.s=Object.assign({},r.fieldContext,{field:"",query:{},parse:this.parse,hasOperators:n=>nt(n,this.o,r.useIgnoreValue)}),this.i=Object.assign({},r.documentContext,{parse:this.parse,query:{}}),this.h=r.useIgnoreValue?st:Object.keys}setParse(e){this.parse=e,this.s.parse=e,this.i.parse=e}parseField(e,r,n,s){let o=this.o[r];if(!o)throw new Error(`Unsupported operator "${r}"`);if(o.type!=="field")throw new Error(`Unexpected ${o.type} operator "${r}" at field level`);return this.s.field=e,this.s.query=s,this.parseInstruction(o,n,this.s)}parseInstruction(e,r,n){return typeof e.validate=="function"&&e.validate(e,r),(e.parse||x[e.type])(e,r,n)}parseFieldOperators(e,r){let n=[],s=this.h(r);for(let o=0,i=s.length;o<i;o++){let a=s[o];if(!this.o[a])throw new Error(`Field query for "${e}" may contain only operators or a plain object as a value`);N(n,this.parseField(e,a,r[a],r))}return n}parse(e){let r=[],n=this.h(e);this.i.query=e;for(let s=0,o=n.length;s<o;s++){let i=n[s],a=e[i],c=this.o[i];if(c){if(c.type!=="document"&&c.type!=="compound")throw new Error(`Cannot use parsing instruction for operator "${i}" in "document" context as it is supposed to be used in "${c.type}" context`);N(r,this.parseInstruction(c,a,this.i))}else this.s.hasOperators(a)?r.push(...this.parseFieldOperators(i,a)):N(r,this.parseField(i,this.u.defaultOperatorName,a,e))}return this.u.mergeFinalConditions(r)}};function S(t,e){let r=t[e];if(typeof r!="function")throw new Error(`Unable to interpret "${e}" condition. Did you forget to register interpreter for it?`);return r}function ot(t){return t.operator}function Oe(t,e){let r=e,n=r&&r.getInterpreterName||ot,s;switch(r?r.numberOfArguments:0){case 1:s=i=>{let a=n(i,r);return S(t,a)(i,o)};break;case 3:s=(i,a,c)=>{let u=n(i,r);return S(t,u)(i,a,c,o)};break;default:s=(i,a)=>{let c=n(i,r);return S(t,c)(i,a,o)}}let o=Object.assign({},r,{interpret:s});return o.interpret}function Ae(t,e){return(r,...n)=>{let s=t(r,...n),o=e.bind(null,s);return o.ast=s,o}}var Vt=g.prototype.parseInstruction;function Ee(t,e){if(!Array.isArray(e))throw new Error(`"${t.name}" expects value to be an array`)}function Fe(t,e){if(Ee(t,e),!e.length)throw new Error(`"${t.name}" expects to have at least one element in array`)}var D=t=>(e,r)=>{if(typeof r!==t)throw new Error(`"${e.name}" expects value to be a "${t}"`)},Ce={type:"compound",validate:Fe,parse(t,e,{parse:r}){let n=e.map(s=>r(s));return q(t.name,n)}},it=Ce,at={type:"compound",validate:Fe},ct={type:"field",validate(t,e){if(!(e&&(e instanceof RegExp||e.constructor===Object)))throw new Error(`"${t.name}" expects to receive either regular expression or object of field operators`)},parse(t,e,r){let n=e instanceof RegExp?new f("regex",r.field,e):r.parse(e,r);return new p(t.name,[n])}},L={type:"field",validate(t,e){if(!e||e.constructor!==Object)throw new Error(`"${t.name}" expects to receive an object with nested query or field level operators`)},parse(t,e,{parse:r,field:n,hasOperators:s}){let o=s(e)?r(e,{field:l}):r(e);return new f(t.name,n,o)}},U={type:"field",validate:D("number")},m={type:"field",validate:Ee},V=m,B=m,ut={type:"field",validate(t,e){if(!Array.isArray(e)||e.length!==2)throw new Error(`"${t.name}" expects an array with 2 numeric elements`)}},J={type:"field",validate:D("boolean")},O={type:"field",validate:function(t,e){if(!(typeof e=="string"||typeof e=="number"||e instanceof Date))throw new Error(`"${t.name}" expects value to be comparable (i.e., string, number or date)`)}},b=O,Q=b,G=b,A={type:"field"},K=A,Y={type:"field",validate(t,e){if(!(e instanceof RegExp)&&typeof e!="string")throw new Error(`"${t.name}" expects value to be a regular expression or a string that represents regular expression`)},parse(t,e,r){let n=typeof e=="string"?new RegExp(e,r.query.$options||""):e;return new f(t.name,r.field,n)}},H={type:"field",parse:()=>k},lt={type:"document",validate:D("function")},pt=Object.freeze({__proto__:null,$and:Ce,$or:it,$nor:at,$not:ct,$elemMatch:L,$size:U,$in:m,$nin:V,$all:B,$mod:ut,$exists:J,$gte:O,$gt:b,$lt:Q,$lte:G,$eq:A,$ne:K,$regex:Y,$options:H,$where:lt}),j=class extends g{constructor(e){super(e,{defaultOperatorName:"$eq",operatorToConditionName:r=>r.slice(1)})}parse(e,r){return r&&r.field?z(this.parseFieldOperators(r.field,e)):super.parse(e)}},E=pt;function W(t,e,r){for(let n=0,s=t.length;n<s;n++)if(r(t[n],e)===0)return!0;return!1}function X(t,e){return Array.isArray(t)&&Number.isNaN(Number(e))}function Me(t,e,r){if(!X(t,e))return r(t,e);let n=[];for(let s=0;s<t.length;s++){let o=r(t[s],e);o!==void 0&&(n=n.concat(o))}return n}function h(t){return(e,r,n)=>{let s=n.get(r,e.field);return Array.isArray(s)?s.some(o=>t(e,o,n)):t(e,s,n)}}var ft=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty),ht=(t,e)=>t[e];function _e(t,e,r){let n=e.lastIndexOf(".");return n===-1?[t,e]:[r(t,e.slice(0,n)),e.slice(n+1)]}function dt(t,e,r=ht){if(e===l)return t;if(!t)throw new Error(`Unable to get field "${e}" out of ${String(t)}.`);return(function(n,s,o){if(s.indexOf(".")===-1)return Me(n,s,o);let i=s.split("."),a=n;for(let c=0,u=i.length;c<u;c++)if(a=Me(a,i[c],o),!a||typeof a!="object")return c<u-1?void 0:a;return a})(t,e,r)}function Z(t,e){return t===e?0:t>e?1:-1}function ee(t,e={}){return Oe(t,Object.assign({get:dt,compare:Z},e))}var Ie=(t,e,{interpret:r})=>t.value.some(n=>r(n,e)),yt=(t,e,r)=>!Ie(t,e,r),te=(t,e,{interpret:r})=>t.value.every(n=>r(n,e)),gt=(t,e,{interpret:r})=>!r(t.value[0],e),F=(t,e,{compare:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&!Array.isArray(t.value)?W(s,t.value,r):r(s,t.value)===0},re=(t,e,r)=>!F(t,e,r),ne=h((t,e,r)=>{let n=r.compare(e,t.value);return n===0||n===-1}),se=h((t,e,r)=>r.compare(e,t.value)===-1),oe=h((t,e,r)=>r.compare(e,t.value)===1),ie=h((t,e,r)=>{let n=r.compare(e,t.value);return n===0||n===1}),ae=(t,e,{get:r})=>{if(t.field===l)return e!==void 0;let[n,s]=_e(e,t.field,r),o=i=>i==null?!!i===t.value:ft(i,s)===t.value;return X(n,s)?n.some(o):o(n)},mt=h((t,e)=>typeof e=="number"&&e%t.value[0]===t.value[1]),ce=(t,e,{get:r})=>{let[n,s]=_e(e,t.field,r),o=i=>{let a=r(i,s);return Array.isArray(a)&&a.length===t.value};return t.field!==l&&X(n,s)?n.some(o):o(n)},ue=h((t,e)=>typeof e=="string"&&t.value.test(e)),$=h((t,e,{compare:r})=>W(t.value,e,r)),le=(t,e,r)=>!$(t,e,r),pe=(t,e,{compare:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&t.value.every(o=>W(s,o,r))},fe=(t,e,{interpret:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&s.some(o=>r(t.value,o))},bt=(t,e)=>t.value.call(e),$t=Object.freeze({__proto__:null,or:Ie,nor:yt,and:te,not:gt,eq:F,ne:re,lte:ne,lt:se,gt:oe,gte:ie,exists:ae,mod:mt,size:ce,regex:ue,within:$,nin:le,all:pe,elemMatch:fe,where:bt}),C=Object.assign({},$t,{in:$}),Yt=ee(C);function Pe(t){return t===null||typeof t!="object"?t:t instanceof Date?t.getTime():t&&typeof t.toJSON=="function"?t.toJSON():t}var vt=(t,e)=>Z(Pe(t),Pe(e));function M(t,e,r){let n=new j(t),s=ee(e,Object.assign({compare:vt},r));if(r&&r.forPrimitives){let o={field:l},i=n.parse;n.setParse(a=>i(a,o))}return Ae(n.parse,s)}var er=M(E,C),tr=M(["$and","$or"].reduce((t,e)=>(t[e]=Object.assign({},t[e],{type:"field"}),t),Object.assign({},E,{$nor:Object.assign({},E.$nor,{type:"field",parse:x.compound})})),C,{forPrimitives:!0});var qe=Object.hasOwn||((t,e)=>Object.prototype.hasOwnProperty.call(t,e));function he(t){return Array.isArray(t)?t:[t]}var d="__caslSubjectType__";function ze(t,e){if(e){if(!qe(e,d))Object.defineProperty(e,d,{value:t});else if(t!==e[d])throw new Error(`Trying to cast object to subject type ${t} but previously it was casted to ${e[d]}`)}return e}var I=t=>{let e=typeof t;return e==="string"||e==="function"},De=t=>t.modelName||t.name;function wt(t){return typeof t=="string"?t:De(t)}function Le(t){return qe(t,d)?t[d]:De(t.constructor)}var Te={function:t=>t.constructor,string:Le};function Ne(t,e,r){for(let n=r;n<e.length;n++)t.push(e[n])}function Se(t,e){if(!t||!t.length)return e||[];if(!e||!e.length)return t||[];let r=0,n=0,s=[];for(;r<t.length&&n<e.length;)t[r].priority<e[n].priority?(s.push(t[r]),r++):t[r].priority>e[n].priority?(s.push(e[n]),n++):(s.push(t[r]),r++,n++);return Ne(s,t,r),Ne(s,e,n),s}function _(t,e,r){let n=t.get(e);return n||(n=r(),t.set(e,n)),n}var xt=t=>t;function jt(t,e){let r;for(let n=0;n<t.length;n++){let s=e(t[n]);r&&s&&r.push(t[n]),s||(r??=t.slice(0,n))}return r||t}function Ot(t,e){if(Array.isArray(t.fields)&&!t.fields.length)throw new Error("`rawRule.fields` cannot be an empty array. https://bit.ly/390miLa");if(t.fields&&!e.fieldMatcher)throw new Error('You need to pass "fieldMatcher" option in order to restrict access by fields');if(t.conditions&&!e.conditionsMatcher)throw new Error('You need to pass "conditionsMatcher" option in order to restrict access by conditions')}var de=class{constructor(e,r,n=0){Ot(e,r),this.action=r.resolveAction(e.action),this.subject=e.subject,this.inverted=!!e.inverted,this.conditions=e.conditions,this.reason=e.reason,this.origin=e,this.fields=e.fields?he(e.fields):void 0,this.priority=n,this.t=r}i(){return this.conditions&&!this.o&&(this.o=this.t.conditionsMatcher(this.conditions)),this.o}get ast(){let e=this.i();return e?e.ast:void 0}matchesConditions(e){return this.conditions?!e||I(e)?!this.inverted:this.i()(e):!0}matchesField(e){return this.fields?e?(this.u||(this.u=this.t.fieldMatcher(this.fields)),this.u(e)):!this.inverted:!0}};function At(t,e){let r={value:t,prev:e,next:null};return e&&(e.next=r),r}function Et(t){t.next&&(t.next.prev=t.prev),t.prev&&(t.prev.next=t.next),t.next=t.prev=null}var Re=()=>({rules:[],merged:!1}),ke=()=>new Map,ye=class{constructor(e=[],r={}){this.h=!1,this.l=new Map,this.p={conditionsMatcher:r.conditionsMatcher,fieldMatcher:r.fieldMatcher,resolveAction:r.resolveAction||xt},this.$=r.anyAction||"manage",this.A=r.anySubjectType||"all",this.m=e,this.M=!!r.detectSubjectType,this.j=r.detectSubjectType||Le,this.v(e)}get rules(){return this.m}detectSubjectType(e){return I(e)?e:e?this.j(e):this.A}update(e){let r={rules:e,ability:this,target:this};return this._("update",r),this.m=e,this.v(e),this._("updated",r),this}v(e){let r=new Map,n;for(let s=e.length-1;s>=0;s--){let o=e.length-s-1,i=new de(e[s],this.p,o),a=he(i.action),c=he(i.subject||this.A);!this.h&&i.fields&&(this.h=!0);for(let u=0;u<c.length;u++){let Ke=_(r,c[u],ke);n===void 0&&(n=typeof c[u]),typeof c[u]!==n&&n!=="mixed"&&(n="mixed");for(let P=0;P<a.length;P++)_(Ke,a[P],Re).rules.push(i)}}if(this.l=r,n!=="mixed"&&!this.M){let s=Te[n]||Te.string;this.j=s}}possibleRulesFor(e,r=this.A){if(!I(r))throw new Error('"possibleRulesFor" accepts only subject types (i.e., string or class) as the 2nd parameter');let n=_(this.l,r,ke),s=_(n,e,Re);if(s.merged)return s.rules;let o=e!==this.$&&n.has(this.$)?n.get(this.$).rules:void 0,i=Se(s.rules,o);return r!==this.A&&(i=Se(i,this.possibleRulesFor(e,this.A))),s.rules=i,s.merged=!0,i}rulesFor(e,r,n){let s=this.possibleRulesFor(e,r);if(n&&typeof n!="string")throw new Error("The 3rd, `field` parameter is expected to be a string. See https://stalniy.github.io/casl/en/api/casl-ability#can-of-pure-ability for details");return this.h?jt(s,o=>o.matchesField(n)):s}actionsFor(e){if(!I(e))throw new Error('"actionsFor" accepts only subject types (i.e., string or class) as a parameter');let r=new Set,n=this.l.get(e);n&&Array.from(n.keys()).forEach(o=>r.add(o));let s=e!==this.A?this.l.get(this.A):void 0;return s&&Array.from(s.keys()).forEach(o=>r.add(o)),Array.from(r)}on(e,r){this.F=this.F||new Map;let n=this.F,s=n.get(e)||null,o=At(r,s);return n.set(e,o),()=>{let i=n.get(e);!o.next&&!o.prev&&i===o?n.delete(e):o===i&&n.set(e,o.prev),Et(o)}}_(e,r){if(!this.F)return;let n=this.F.get(e)||null,s=[];for(;n!==null;)s.push(n.value),n=n.prev;for(let o=0;o<s.length;o++)s[o](r)}},ge=class extends ye{can(e,r,n){let s=this.relevantRuleFor(e,r,n);return!!s&&!s.inverted}relevantRuleFor(e,r,n){let s=this.detectSubjectType(r),o=this.rulesFor(e,s,n);for(let i=0,a=o.length;i<a;i++)if(o[i].matchesConditions(r))return o[i];return null}cannot(e,r,n){return!this.can(e,r,n)}},Ft={$eq:A,$ne:K,$lt:Q,$lte:G,$gt:b,$gte:O,$in:m,$nin:V,$all:B,$size:U,$regex:Y,$options:H,$elemMatch:L,$exists:J},Ct={eq:F,ne:re,lt:se,lte:ne,gt:oe,gte:ie,in:$,nin:le,all:pe,size:ce,regex:ue,elemMatch:fe,exists:ae,and:te};var Mt=M(Ft,Ct),_t=/[-/\\^$+?.()|[\]{}]/g,It=/\.?\*+\.?/g,Pt=/\*+/,Tt=/\./g;function Nt(t,e,r){let n=r[0]==="*"||t[0]==="."&&t[t.length-1]==="."?"+":"*",s=t.indexOf("**")===-1?"[^.]":".",o=t.replace(Tt,"\\$&").replace(Pt,s+n);return e+t.length===r.length?`(?:${o})?`:o}function St(t,e,r){return t==="."&&(r[e-1]==="*"||r[e+1]==="*")?t:`\\${t}`}function Rt(t){let e=t.map(n=>n.replace(_t,St).replace(It,Nt)),r=e.length>1?`(?:${e.join("|")})`:e[0];return new RegExp(`^${r}$`)}var kt=t=>{let e;return r=>(typeof e>"u"&&(e=t.every(n=>n.indexOf("*")===-1)?null:Rt(t)),e===null?t.indexOf(r)!==-1:e.test(r))};function Ue(t=[],e={}){return new ge(t,Object.assign({conditionsMatcher:Mt,fieldMatcher:kt},e))}var qt=t=>`Cannot execute "${t.action}" on "${t.subjectType}"`,Ve=function(e){this.message=e};Ve.prototype=Object.create(Error.prototype);var me=class extends Ve{static setDefaultMessage(e){this.P=typeof e=="string"?()=>e:e}static from(e){return new this(e)}constructor(e){super(""),this.ability=e,typeof Error.captureStackTrace=="function"&&(this.name="ForbiddenError",Error.captureStackTrace(this,this.constructor))}setMessage(e){return this.message=e,this}throwUnlessCan(e,r,n){let s=this.unlessCan(e,r,n);if(s)throw s}unlessCan(e,r,n){let s=this.ability.relevantRuleFor(e,r,n);if(s&&!s.inverted)return;this.action=e,this.subject=r,this.subjectType=wt(this.ability.detectSubjectType(r)),this.field=n;let o=s?s.reason:"";return this.message=this.message||o||this.constructor.P(this),this}};me.P=qt;var ar=Object.freeze({__proto__:null});var be="0.2.0";function Be(t){return{ok:!0,side:t,version:be}}function v(t,e){if(t==null)return t;if(typeof t=="string")return t.indexOf("$principal.")===0?t.slice(11).split(".").reduce((n,s)=>n==null?n:n[s],e):t;if(Array.isArray(t))return t.map(r=>v(r,e));if(typeof t=="object"){let r={};for(let n of Object.keys(t))r[n]=v(t[n],e);return r}return t}function $e(t,e){let r=new Set(t&&t.subjects||[]);return(e.rules||[]).filter(n=>r.has(n.subject)).map(n=>{let s={action:n.actions,subject:n.resource};return n.where&&(s.conditions=v(n.where,t)),s})}function ve(t){return Ue(t)}function Je(t,e){return ve($e(t,e))}var we=[{action:"read",type:"Booking",object:{customerId:"m-1"}},{action:"read",type:"Booking",object:{customerId:"m-2"}},{action:"cancel",type:"Booking",object:{customerId:"m-1"}},{action:"delete",type:"Booking",object:{customerId:"m-1"}},{action:"manage",type:"Vendor",object:{_id:"v-1"}}];function Qe(t){return we.map(e=>({action:e.action,type:e.type,object:e.object,can:t.can(e.action,ze(e.type,Object.assign({},e.object)))}))}function zt(){return Be("backend")}async function Dt(){try{let t=await Ge.currentMember.getMember();return t&&t._id||null}catch{return null}}0&&(module.exports={CASES,PACKAGE_VERSION,abilityFor,abilityFromRules,backendMemberId,backendPing,caseTable,resolvePlaceholders,rulesFor});
1
+ var Vt=Object.create;var Y=Object.defineProperty;var zt=Object.getOwnPropertyDescriptor;var Gt=Object.getOwnPropertyNames;var Yt=Object.getPrototypeOf,Jt=Object.prototype.hasOwnProperty;var Kt=(t,e)=>{for(var r in e)Y(t,r,{get:e[r],enumerable:!0})},tt=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Gt(e))!Jt.call(t,s)&&s!==r&&Y(t,s,{get:()=>e[s],enumerable:!(n=zt(e,s))||n.enumerable});return t};var Ht=(t,e,r)=>(r=t!=null?Vt(Yt(t)):{},tt(e||!t||!t.__esModule?Y(r,"default",{value:t,enumerable:!0}):r,t)),Qt=t=>tt(Y({},"__esModule",{value:!0}),t);var Yr={};Kt(Yr,{CASES:()=>Ze,CODES:()=>v,KIND:()=>E,PACKAGE_VERSION:()=>Xe,PolicyError:()=>C,SCOPE:()=>x,WHEN:()=>N,abilityFor:()=>ae,abilityFromRules:()=>We,anonymous:()=>st,applyClauses:()=>ue,assertDeclared:()=>Dt,backendMemberId:()=>Gr,backendPing:()=>zr,can:()=>w,caseTable:()=>St,createAccess:()=>Vr,createPrincipal:()=>q,deny:()=>M,denyOpaque:()=>j,filterFor:()=>ce,hasRole:()=>ot,isDenial:()=>nt,normaliseRoles:()=>fe,ok:()=>rt,permissionFor:()=>at,resolvePlaceholders:()=>Ct,resolveSubjects:()=>K,resolveWhere:()=>ie,rulesFor:()=>D,validatePolicy:()=>J});module.exports=Qt(Yr);var et=require("wix-members-backend"),Ut=Ht(require("wix-users-backend"),1),le=require("wix-web-module"),qt=require("@wix/data"),Bt=require("@wix/essentials");var v={FORBIDDEN:"FORBIDDEN",UNAUTHENTICATED:"UNAUTHENTICATED",UNVERIFIED:"UNVERIFIED",NOT_FOUND:"NOT_FOUND",INVALID_POLICY:"INVALID_POLICY",INVALID_ARGUMENT:"INVALID_ARGUMENT"},C=class extends Error{constructor(e){super(e),this.name="PolicyError",this.code=v.INVALID_POLICY}};function rt(t){return{ok:!0,data:t===void 0?null:t}}function M(t,e,r){let n={ok:!1,code:t||v.FORBIDDEN};return e&&(n.action=e),r&&(n.detail=r),n}var nt=t=>!!t&&t.ok===!1;function j(t){return M(v.NOT_FOUND,t)}var E={VISITOR:"visitor",MEMBER:"member",CAPABILITY:"capability",SERVICE:"service"};function fe(t){if(!Array.isArray(t))return[];let e=[];for(let r of t){if(typeof r=="string"){e.push(r);continue}if(!r||typeof r!="object")continue;let n=r.title||r.name||r.roleKey;n&&e.push(n)}return e}function q(t){let e=t||{},r=e.memberId||null,n=fe(e.roles);return{kind:e.kind||(r?E.MEMBER:E.VISITOR),memberId:r,roles:n,subjects:Array.isArray(e.subjects)?e.subjects.slice():[],domain:e.domain&&typeof e.domain=="object"?e.domain:{},unverified:!!e.unverified}}var st=()=>q({kind:E.VISITOR}),ot=(t,e)=>t.roles.indexOf(e)!==-1;var N={ANYONE:"anyone",ANONYMOUS:"anonymous",MEMBER:"member"},I=t=>!!t&&typeof t=="object"&&!Array.isArray(t),Wt=t=>Array.isArray(t)?t:[t];function m(t,e){throw new C("policy"+t+": "+e)}function Xt(t,e){let r=".subjects."+t;I(e)||m(r,"must be an object");let s=["when","role","domain"].filter(o=>e[o]!==void 0);if(s.length===0&&m(r,'needs exactly one of when/role/domain \u2014 "{}" is ambiguous between a visitor and a member'),s.length>1&&m(r,"has "+s.join(" and ")+"; use exactly one"),e.when!==void 0){let o=[N.ANYONE,N.ANONYMOUS,N.MEMBER];o.indexOf(e.when)===-1&&m(r+".when","must be one of "+o.join(", ")+" (got "+JSON.stringify(e.when)+")")}e.role!==void 0&&typeof e.role!="string"&&m(r+".role","must be a string"),e.domain!==void 0&&typeof e.domain!="string"&&m(r+".domain","must be a string")}function Zt(t,e,r){let n=".rules["+e+"]";I(t)||m(n,"must be an object"),typeof t.subject!="string"&&m(n+".subject","must be a string"),r.indexOf(t.subject)===-1&&m(n+".subject",'"'+t.subject+'" is not declared in policy.subjects'),t.actions===void 0&&m(n+".actions","is required");for(let s of Wt(t.actions))typeof s!="string"&&m(n+".actions","must be a string or an array of strings");typeof t.resource!="string"&&m(n+".resource","must be a string"),t.where!==void 0&&!I(t.where)&&m(n+".where","must be an object")}var it=["Anyone","SiteMember","Admin"];function er(t,e,r){let n=".api."+t;I(e)||m(n,"must be an object"),it.indexOf(e.permission)===-1&&m(n+".permission","must be one of "+it.join(", ")+" (got "+JSON.stringify(e.permission)+")"),e.ability!==void 0&&((!Array.isArray(e.ability)||e.ability.length!==2)&&m(n+".ability","must be [action, resource]"),(typeof e.ability[0]!="string"||typeof e.ability[1]!="string")&&m(n+".ability","both entries must be strings")),e.subject!==void 0&&r.indexOf(e.subject)===-1&&m(n+".subject",'"'+e.subject+'" is not declared in policy.subjects')}function J(t){if(!I(t))throw new C("policy must be an object");I(t.subjects)||m(".subjects","is required and must be an object");let e=Object.keys(t.subjects);e.length===0&&m(".subjects","declares no subjects");for(let r of e)Xt(r,t.subjects[r]);if(Array.isArray(t.rules)||m(".rules","is required and must be an array"),t.rules.forEach((r,n)=>Zt(r,n,e)),t.api!==void 0){I(t.api)||m(".api","must be an object");for(let r of Object.keys(t.api))er(r,t.api[r],e)}return t.collections!==void 0&&!I(t.collections)&&m(".collections","must be an object"),t}function K(t,e){let r=new Set(t.subjects||[]);for(let n of Object.keys(e.subjects)){let s=e.subjects[n];(s.when===N.ANYONE||s.when===N.ANONYMOUS&&!t.memberId||s.when===N.MEMBER&&t.memberId||s.role!==void 0&&t.roles.indexOf(s.role)!==-1||s.domain!==void 0&&t.domain[s.domain])&&r.add(n)}return Array.from(r)}function at(t,e){let r=t.api&&t.api[e];return r?r.permission:null}var H=class{constructor(e,r){this.operator=e,this.value=r,Object.defineProperty(this,"t",{writable:!0})}get notes(){return this.t}addNote(e){this.t=this.t||[],this.t.push(e)}},B=class extends H{},S=class extends B{constructor(e,r){if(!Array.isArray(r))throw new Error(`"${e}" operator expects to receive an array of conditions`);super(e,r)}},F="__itself__",R=class extends H{constructor(e,r,n){super(e,n),this.field=r}},me=new B("__null__",null),he=Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function tr(t,e){return e instanceof S&&e.operator===t}function ye(t,e){return e.length===1?e[0]:new S(t,(function r(n,s,o){let i=o||[];for(let a=0,l=s.length;a<l;a++){let d=s[a];tr(n,d)?r(n,d.value,i):i.push(d)}return i})(t,e))}var rr=t=>t,ct=()=>Object.create(null),ut=Object.defineProperty(ct(),"__@type@__",{value:"ignore value"});function nr(t,e,r=!1){if(!t||t&&t.constructor!==Object)return!1;for(let n in t)if(he(t,n)&&he(e,n)&&(!r||t[n]!==ut))return!0;return!1}function sr(t){let e=[];for(let r in t)he(t,r)&&t[r]!==ut&&e.push(r);return e}function de(t,e){e!==me&&t.push(e)}var be=t=>ye("and",t);var Q={compound(t,e,r){let n=(Array.isArray(e)?e:[e]).map(s=>r.parse(s));return new S(t.name,n)},field:(t,e,r)=>new R(t.name,r.field,e),document:(t,e)=>new B(t.name,e)},L=class{constructor(e,r=ct()){this.o=void 0,this.s=void 0,this.i=void 0,this.u=void 0,this.h=void 0,this.parse=this.parse.bind(this),this.u={operatorToConditionName:r.operatorToConditionName||rr,defaultOperatorName:r.defaultOperatorName||"eq",mergeFinalConditions:r.mergeFinalConditions||be},this.o=Object.keys(e).reduce((n,s)=>(n[s]=Object.assign({name:this.u.operatorToConditionName(s)},e[s]),n),{}),this.s=Object.assign({},r.fieldContext,{field:"",query:{},parse:this.parse,hasOperators:n=>nr(n,this.o,r.useIgnoreValue)}),this.i=Object.assign({},r.documentContext,{parse:this.parse,query:{}}),this.h=r.useIgnoreValue?sr:Object.keys}setParse(e){this.parse=e,this.s.parse=e,this.i.parse=e}parseField(e,r,n,s){let o=this.o[r];if(!o)throw new Error(`Unsupported operator "${r}"`);if(o.type!=="field")throw new Error(`Unexpected ${o.type} operator "${r}" at field level`);return this.s.field=e,this.s.query=s,this.parseInstruction(o,n,this.s)}parseInstruction(e,r,n){return typeof e.validate=="function"&&e.validate(e,r),(e.parse||Q[e.type])(e,r,n)}parseFieldOperators(e,r){let n=[],s=this.h(r);for(let o=0,i=s.length;o<i;o++){let a=s[o];if(!this.o[a])throw new Error(`Field query for "${e}" may contain only operators or a plain object as a value`);de(n,this.parseField(e,a,r[a],r))}return n}parse(e){let r=[],n=this.h(e);this.i.query=e;for(let s=0,o=n.length;s<o;s++){let i=n[s],a=e[i],l=this.o[i];if(l){if(l.type!=="document"&&l.type!=="compound")throw new Error(`Cannot use parsing instruction for operator "${i}" in "document" context as it is supposed to be used in "${l.type}" context`);de(r,this.parseInstruction(l,a,this.i))}else this.s.hasOperators(a)?r.push(...this.parseFieldOperators(i,a)):de(r,this.parseField(i,this.u.defaultOperatorName,a,e))}return this.u.mergeFinalConditions(r)}};function pe(t,e){let r=t[e];if(typeof r!="function")throw new Error(`Unable to interpret "${e}" condition. Did you forget to register interpreter for it?`);return r}function or(t){return t.operator}function lt(t,e){let r=e,n=r&&r.getInterpreterName||or,s;switch(r?r.numberOfArguments:0){case 1:s=i=>{let a=n(i,r);return pe(t,a)(i,o)};break;case 3:s=(i,a,l)=>{let d=n(i,r);return pe(t,d)(i,a,l,o)};break;default:s=(i,a)=>{let l=n(i,r);return pe(t,l)(i,a,o)}}let o=Object.assign({},r,{interpret:s});return o.interpret}function ft(t,e){return(r,...n)=>{let s=t(r,...n),o=e.bind(null,s);return o.ast=s,o}}var en=L.prototype.parseInstruction;function dt(t,e){if(!Array.isArray(e))throw new Error(`"${t.name}" expects value to be an array`)}function pt(t,e){if(dt(t,e),!e.length)throw new Error(`"${t.name}" expects to have at least one element in array`)}var ge=t=>(e,r)=>{if(typeof r!==t)throw new Error(`"${e.name}" expects value to be a "${t}"`)},ht={type:"compound",validate:pt,parse(t,e,{parse:r}){let n=e.map(s=>r(s));return ye(t.name,n)}},ir=ht,ar={type:"compound",validate:pt},cr={type:"field",validate(t,e){if(!(e&&(e instanceof RegExp||e.constructor===Object)))throw new Error(`"${t.name}" expects to receive either regular expression or object of field operators`)},parse(t,e,r){let n=e instanceof RegExp?new R("regex",r.field,e):r.parse(e,r);return new S(t.name,[n])}},Oe={type:"field",validate(t,e){if(!e||e.constructor!==Object)throw new Error(`"${t.name}" expects to receive an object with nested query or field level operators`)},parse(t,e,{parse:r,field:n,hasOperators:s}){let o=s(e)?r(e,{field:F}):r(e);return new R(t.name,n,o)}},ve={type:"field",validate:ge("number")},V={type:"field",validate:dt},we=V,xe=V,ur={type:"field",validate(t,e){if(!Array.isArray(e)||e.length!==2)throw new Error(`"${t.name}" expects an array with 2 numeric elements`)}},je={type:"field",validate:ge("boolean")},X={type:"field",validate:function(t,e){if(!(typeof e=="string"||typeof e=="number"||e instanceof Date))throw new Error(`"${t.name}" expects value to be comparable (i.e., string, number or date)`)}},z=X,$e=z,Ae=z,Z={type:"field"},Ee=Z,Ie={type:"field",validate(t,e){if(!(e instanceof RegExp)&&typeof e!="string")throw new Error(`"${t.name}" expects value to be a regular expression or a string that represents regular expression`)},parse(t,e,r){let n=typeof e=="string"?new RegExp(e,r.query.$options||""):e;return new R(t.name,r.field,n)}},Ne={type:"field",parse:()=>me},lr={type:"document",validate:ge("function")},fr=Object.freeze({__proto__:null,$and:ht,$or:ir,$nor:ar,$not:cr,$elemMatch:Oe,$size:ve,$in:V,$nin:we,$all:xe,$mod:ur,$exists:je,$gte:X,$gt:z,$lt:$e,$lte:Ae,$eq:Z,$ne:Ee,$regex:Ie,$options:Ne,$where:lr}),W=class extends L{constructor(e){super(e,{defaultOperatorName:"$eq",operatorToConditionName:r=>r.slice(1)})}parse(e,r){return r&&r.field?be(this.parseFieldOperators(r.field,e)):super.parse(e)}},ee=fr;function Fe(t,e,r){for(let n=0,s=t.length;n<s;n++)if(r(t[n],e)===0)return!0;return!1}function Ce(t,e){return Array.isArray(t)&&Number.isNaN(Number(e))}function mt(t,e,r){if(!Ce(t,e))return r(t,e);let n=[];for(let s=0;s<t.length;s++){let o=r(t[s],e);o!==void 0&&(n=n.concat(o))}return n}function _(t){return(e,r,n)=>{let s=n.get(r,e.field);return Array.isArray(s)?s.some(o=>t(e,o,n)):t(e,s,n)}}var dr=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty),pr=(t,e)=>t[e];function yt(t,e,r){let n=e.lastIndexOf(".");return n===-1?[t,e]:[r(t,e.slice(0,n)),e.slice(n+1)]}function hr(t,e,r=pr){if(e===F)return t;if(!t)throw new Error(`Unable to get field "${e}" out of ${String(t)}.`);return(function(n,s,o){if(s.indexOf(".")===-1)return mt(n,s,o);let i=s.split("."),a=n;for(let l=0,d=i.length;l<d;l++)if(a=mt(a,i[l],o),!a||typeof a!="object")return l<d-1?void 0:a;return a})(t,e,r)}function Me(t,e){return t===e?0:t>e?1:-1}function Se(t,e={}){return lt(t,Object.assign({get:hr,compare:Me},e))}var bt=(t,e,{interpret:r})=>t.value.some(n=>r(n,e)),mr=(t,e,r)=>!bt(t,e,r),Re=(t,e,{interpret:r})=>t.value.every(n=>r(n,e)),yr=(t,e,{interpret:r})=>!r(t.value[0],e),te=(t,e,{compare:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&!Array.isArray(t.value)?Fe(s,t.value,r):r(s,t.value)===0},_e=(t,e,r)=>!te(t,e,r),De=_((t,e,r)=>{let n=r.compare(e,t.value);return n===0||n===-1}),ke=_((t,e,r)=>r.compare(e,t.value)===-1),Pe=_((t,e,r)=>r.compare(e,t.value)===1),Te=_((t,e,r)=>{let n=r.compare(e,t.value);return n===0||n===1}),Ue=(t,e,{get:r})=>{if(t.field===F)return e!==void 0;let[n,s]=yt(e,t.field,r),o=i=>i==null?!!i===t.value:dr(i,s)===t.value;return Ce(n,s)?n.some(o):o(n)},br=_((t,e)=>typeof e=="number"&&e%t.value[0]===t.value[1]),qe=(t,e,{get:r})=>{let[n,s]=yt(e,t.field,r),o=i=>{let a=r(i,s);return Array.isArray(a)&&a.length===t.value};return t.field!==F&&Ce(n,s)?n.some(o):o(n)},Be=_((t,e)=>typeof e=="string"&&t.value.test(e)),G=_((t,e,{compare:r})=>Fe(t.value,e,r)),Le=(t,e,r)=>!G(t,e,r),Ve=(t,e,{compare:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&t.value.every(o=>Fe(s,o,r))},ze=(t,e,{interpret:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&s.some(o=>r(t.value,o))},gr=(t,e)=>t.value.call(e),Or=Object.freeze({__proto__:null,or:bt,nor:mr,and:Re,not:yr,eq:te,ne:_e,lte:De,lt:ke,gt:Pe,gte:Te,exists:Ue,mod:br,size:qe,regex:Be,within:G,nin:Le,all:Ve,elemMatch:ze,where:gr}),re=Object.assign({},Or,{in:G}),an=Se(re);function gt(t){return t===null||typeof t!="object"?t:t instanceof Date?t.getTime():t&&typeof t.toJSON=="function"?t.toJSON():t}var vr=(t,e)=>Me(gt(t),gt(e));function ne(t,e,r){let n=new W(t),s=Se(e,Object.assign({compare:vr},r));if(r&&r.forPrimitives){let o={field:F},i=n.parse;n.setParse(a=>i(a,o))}return ft(n.parse,s)}var dn=ne(ee,re),pn=ne(["$and","$or"].reduce((t,e)=>(t[e]=Object.assign({},t[e],{type:"field"}),t),Object.assign({},ee,{$nor:Object.assign({},ee.$nor,{type:"field",parse:Q.compound})})),re,{forPrimitives:!0});var $t=Object.hasOwn||((t,e)=>Object.prototype.hasOwnProperty.call(t,e));function Ge(t){return Array.isArray(t)?t:[t]}var P="__caslSubjectType__";function At(t,e){if(e){if(!$t(e,P))Object.defineProperty(e,P,{value:t});else if(t!==e[P])throw new Error(`Trying to cast object to subject type ${t} but previously it was casted to ${e[P]}`)}return e}var oe=t=>{let e=typeof t;return e==="string"||e==="function"},Et=t=>t.modelName||t.name;function wr(t){return typeof t=="string"?t:Et(t)}function It(t){return $t(t,P)?t[P]:Et(t.constructor)}var Ot={function:t=>t.constructor,string:It};function vt(t,e,r){for(let n=r;n<e.length;n++)t.push(e[n])}function wt(t,e){if(!t||!t.length)return e||[];if(!e||!e.length)return t||[];let r=0,n=0,s=[];for(;r<t.length&&n<e.length;)t[r].priority<e[n].priority?(s.push(t[r]),r++):t[r].priority>e[n].priority?(s.push(e[n]),n++):(s.push(t[r]),r++,n++);return vt(s,t,r),vt(s,e,n),s}function se(t,e,r){let n=t.get(e);return n||(n=r(),t.set(e,n)),n}var xr=t=>t;function jr(t,e){let r;for(let n=0;n<t.length;n++){let s=e(t[n]);r&&s&&r.push(t[n]),s||(r??=t.slice(0,n))}return r||t}function $r(t,e){if(Array.isArray(t.fields)&&!t.fields.length)throw new Error("`rawRule.fields` cannot be an empty array. https://bit.ly/390miLa");if(t.fields&&!e.fieldMatcher)throw new Error('You need to pass "fieldMatcher" option in order to restrict access by fields');if(t.conditions&&!e.conditionsMatcher)throw new Error('You need to pass "conditionsMatcher" option in order to restrict access by conditions')}var Ye=class{constructor(e,r,n=0){$r(e,r),this.action=r.resolveAction(e.action),this.subject=e.subject,this.inverted=!!e.inverted,this.conditions=e.conditions,this.reason=e.reason,this.origin=e,this.fields=e.fields?Ge(e.fields):void 0,this.priority=n,this.t=r}i(){return this.conditions&&!this.o&&(this.o=this.t.conditionsMatcher(this.conditions)),this.o}get ast(){let e=this.i();return e?e.ast:void 0}matchesConditions(e){return this.conditions?!e||oe(e)?!this.inverted:this.i()(e):!0}matchesField(e){return this.fields?e?(this.u||(this.u=this.t.fieldMatcher(this.fields)),this.u(e)):!this.inverted:!0}};function Ar(t,e){let r={value:t,prev:e,next:null};return e&&(e.next=r),r}function Er(t){t.next&&(t.next.prev=t.prev),t.prev&&(t.prev.next=t.next),t.next=t.prev=null}var xt=()=>({rules:[],merged:!1}),jt=()=>new Map,Je=class{constructor(e=[],r={}){this.h=!1,this.l=new Map,this.p={conditionsMatcher:r.conditionsMatcher,fieldMatcher:r.fieldMatcher,resolveAction:r.resolveAction||xr},this.$=r.anyAction||"manage",this.A=r.anySubjectType||"all",this.m=e,this.M=!!r.detectSubjectType,this.j=r.detectSubjectType||It,this.v(e)}get rules(){return this.m}detectSubjectType(e){return oe(e)?e:e?this.j(e):this.A}update(e){let r={rules:e,ability:this,target:this};return this._("update",r),this.m=e,this.v(e),this._("updated",r),this}v(e){let r=new Map,n;for(let s=e.length-1;s>=0;s--){let o=e.length-s-1,i=new Ye(e[s],this.p,o),a=Ge(i.action),l=Ge(i.subject||this.A);!this.h&&i.fields&&(this.h=!0);for(let d=0;d<l.length;d++){let c=se(r,l[d],jt);n===void 0&&(n=typeof l[d]),typeof l[d]!==n&&n!=="mixed"&&(n="mixed");for(let u=0;u<a.length;u++)se(c,a[u],xt).rules.push(i)}}if(this.l=r,n!=="mixed"&&!this.M){let s=Ot[n]||Ot.string;this.j=s}}possibleRulesFor(e,r=this.A){if(!oe(r))throw new Error('"possibleRulesFor" accepts only subject types (i.e., string or class) as the 2nd parameter');let n=se(this.l,r,jt),s=se(n,e,xt);if(s.merged)return s.rules;let o=e!==this.$&&n.has(this.$)?n.get(this.$).rules:void 0,i=wt(s.rules,o);return r!==this.A&&(i=wt(i,this.possibleRulesFor(e,this.A))),s.rules=i,s.merged=!0,i}rulesFor(e,r,n){let s=this.possibleRulesFor(e,r);if(n&&typeof n!="string")throw new Error("The 3rd, `field` parameter is expected to be a string. See https://stalniy.github.io/casl/en/api/casl-ability#can-of-pure-ability for details");return this.h?jr(s,o=>o.matchesField(n)):s}actionsFor(e){if(!oe(e))throw new Error('"actionsFor" accepts only subject types (i.e., string or class) as a parameter');let r=new Set,n=this.l.get(e);n&&Array.from(n.keys()).forEach(o=>r.add(o));let s=e!==this.A?this.l.get(this.A):void 0;return s&&Array.from(s.keys()).forEach(o=>r.add(o)),Array.from(r)}on(e,r){this.F=this.F||new Map;let n=this.F,s=n.get(e)||null,o=Ar(r,s);return n.set(e,o),()=>{let i=n.get(e);!o.next&&!o.prev&&i===o?n.delete(e):o===i&&n.set(e,o.prev),Er(o)}}_(e,r){if(!this.F)return;let n=this.F.get(e)||null,s=[];for(;n!==null;)s.push(n.value),n=n.prev;for(let o=0;o<s.length;o++)s[o](r)}},Ke=class extends Je{can(e,r,n){let s=this.relevantRuleFor(e,r,n);return!!s&&!s.inverted}relevantRuleFor(e,r,n){let s=this.detectSubjectType(r),o=this.rulesFor(e,s,n);for(let i=0,a=o.length;i<a;i++)if(o[i].matchesConditions(r))return o[i];return null}cannot(e,r,n){return!this.can(e,r,n)}},Ir={$eq:Z,$ne:Ee,$lt:$e,$lte:Ae,$gt:z,$gte:X,$in:V,$nin:we,$all:xe,$size:ve,$regex:Ie,$options:Ne,$elemMatch:Oe,$exists:je},Nr={eq:te,ne:_e,lt:ke,lte:De,gt:Pe,gte:Te,in:G,nin:Le,all:Ve,size:qe,regex:Be,elemMatch:ze,exists:Ue,and:Re};var Fr=ne(Ir,Nr),Cr=/[-/\\^$+?.()|[\]{}]/g,Mr=/\.?\*+\.?/g,Sr=/\*+/,Rr=/\./g;function _r(t,e,r){let n=r[0]==="*"||t[0]==="."&&t[t.length-1]==="."?"+":"*",s=t.indexOf("**")===-1?"[^.]":".",o=t.replace(Rr,"\\$&").replace(Sr,s+n);return e+t.length===r.length?`(?:${o})?`:o}function Dr(t,e,r){return t==="."&&(r[e-1]==="*"||r[e+1]==="*")?t:`\\${t}`}function kr(t){let e=t.map(n=>n.replace(Cr,Dr).replace(Mr,_r)),r=e.length>1?`(?:${e.join("|")})`:e[0];return new RegExp(`^${r}$`)}var Pr=t=>{let e;return r=>(typeof e>"u"&&(e=t.every(n=>n.indexOf("*")===-1)?null:kr(t)),e===null?t.indexOf(r)!==-1:e.test(r))};function Nt(t=[],e={}){return new Ke(t,Object.assign({conditionsMatcher:Fr,fieldMatcher:Pr},e))}var Tr=t=>`Cannot execute "${t.action}" on "${t.subjectType}"`,Ft=function(e){this.message=e};Ft.prototype=Object.create(Error.prototype);var He=class extends Ft{static setDefaultMessage(e){this.P=typeof e=="string"?()=>e:e}static from(e){return new this(e)}constructor(e){super(""),this.ability=e,typeof Error.captureStackTrace=="function"&&(this.name="ForbiddenError",Error.captureStackTrace(this,this.constructor))}setMessage(e){return this.message=e,this}throwUnlessCan(e,r,n){let s=this.unlessCan(e,r,n);if(s)throw s}unlessCan(e,r,n){let s=this.ability.relevantRuleFor(e,r,n);if(s&&!s.inverted)return;this.action=e,this.subject=r,this.subjectType=wr(this.ability.detectSubjectType(r)),this.field=n;let o=s?s.reason:"";return this.message=this.message||o||this.constructor.P(this),this}};He.P=Tr;var On=Object.freeze({__proto__:null});function Qe(t,e,r){if(t==null)return t;if(typeof t=="string"){if(t.indexOf("$principal.")!==0)return t;let s=t.slice(11).split(".").reduce((o,i)=>o==null?o:o[i],e);return s==null&&(r.unresolved=!0),s}if(Array.isArray(t))return t.map(n=>Qe(n,e,r));if(typeof t=="object"){let n={};for(let s of Object.keys(t))n[s]=Qe(t[s],e,r);return n}return t}function ie(t,e){let r={unresolved:!1};return{conditions:Qe(t,e,r),unresolved:r.unresolved}}function Ct(t,e){return ie(t,e).conditions}function D(t,e){let r=K(t,e),n=[];for(let s of e.rules){if(r.indexOf(s.subject)===-1)continue;let o={action:s.actions,subject:s.resource};if(s.where){let{conditions:i,unresolved:a}=ie(s.where,t);if(a)continue;o.conditions=i}n.push(o)}return n}function We(t){return Nt(Array.isArray(t)?t:[])}function ae(t,e){return We(D(t,e))}function w(t,e,r,n){return n==null?t.can(e,r):t.can(e,At(r,Object.assign({},n)))}var x={ALL:"all",NONE:"none",FIELDS:"fields",AMBIGUOUS:"ambiguous"},Mt={$in:"in",$nin:"nin",$ne:"ne",$gt:"gt",$gte:"gte",$lt:"lt",$lte:"lte"};function Ur(t){let e=[];for(let r of Object.keys(t)){let n=t[r];if(n===null||typeof n!="object"||Array.isArray(n)){e.push({field:r,op:"eq",value:n});continue}let s=Object.keys(n);if(s.length!==1||!Mt[s[0]])return null;e.push({field:r,op:Mt[s[0]],value:n[s[0]]})}return e}var qr=(t,e)=>t==="manage"||t===e||Array.isArray(t)&&(t.indexOf(e)!==-1||t.indexOf("manage")!==-1),Br=(t,e)=>t==="all"||t===e;function ce(t,e,r,n){let s=D(t,e).filter(i=>qr(i.action,r)&&Br(i.subject,n));if(s.length===0)return{scope:x.NONE,clauses:[]};if(s.some(i=>!i.conditions))return{scope:x.ALL,clauses:[]};if(s.length>1)return{scope:x.AMBIGUOUS,clauses:[]};let o=Ur(s[0].conditions);return o?{scope:x.FIELDS,clauses:o}:{scope:x.AMBIGUOUS,clauses:[]}}function ue(t,e){let r=t;for(let n of e)n.op==="in"?r=r.hasSome(n.field,n.value):n.op==="nin"?r=r.not(r.hasSome(n.field,n.value)):r=r[n.op](n.field,n.value);return r}var Xe="0.3.0";var Ze=[{action:"read",type:"Booking",object:{customerId:"m-1"}},{action:"read",type:"Booking",object:{customerId:"m-2"}},{action:"cancel",type:"Booking",object:{customerId:"m-1"}},{action:"delete",type:"Booking",object:{customerId:"m-1"}},{action:"manage",type:"Vendor",object:{_id:"v-1"}}];function St(t){return Ze.map(e=>({action:e.action,type:e.type,object:e.object,can:w(t,e.action,e.type,e.object)}))}function Rt(t,e){let{wixUsers:r,currentMember:n}=t,s=e&&e.enrich||null,o=e&&e.onError||null;return async function(){let a=null,l=!1,d=!1;try{a=r.currentUser&&r.currentUser.id||null,l=!!(r.currentUser&&r.currentUser.loggedIn)}catch(f){d=!0,o&&o("resolveCaller.id",f)}let c=[];if(a)try{c=await n.getRoles()}catch(f){d=!0,o&&o("resolveCaller.roles",f)}let u=q({kind:a?E.MEMBER:E.VISITOR,memberId:a,roles:c,unverified:d});if(u.loggedIn=l,s)try{let f=await s(u);f&&typeof f=="object"&&(u.domain=f)}catch(f){u.unverified=!0,o&&o("resolveCaller.enrich",f)}return u}}function _t(t,e,r){let{webMethod:n,Permissions:s}=e,o=r.resolveCaller,i=r.abilityFor,a=r.audit||null;function l(d,c,u,f){return a&&a({event:"access.denied",action:d,code:c,caller:u?u.memberId:null,detail:f||null}),M(c,d)}return function(c,u,f){let p=t.api&&t.api[c]||null;if(!p)throw new Error('wix-access: web method "'+c+'" is not declared in policy.api. Add it, or the gate it runs behind is undocumented.');let y=f||{},b=s[p.permission],h=p.ability||null,g=y.strip||[];return n(b,async function(...$){let O=await o();if(O.unverified)return l(c,v.UNVERIFIED,O);if(p.permission!=="Anyone"&&!O.memberId)return l(c,v.UNAUTHENTICATED,O);let T=$.map(A=>{if(!A||typeof A!="object"||Array.isArray(A))return A;let U=Object.assign({},A);for(let Lt of g)delete U[Lt];return U}),k=null;if(h){let[A,U]=h;if(y.load){if(k=await y.load(...T),!k)return l(c,v.NOT_FOUND,O);if(!w(i(O),A,U,k))return j(c)}else if(!w(i(O),A,U))return l(c,v.FORBIDDEN,O)}return u({principal:O,subject:k},...T)})}}function Dt(t,e){let r=Object.keys(t&&t.api||{}),n=e.filter(s=>r.indexOf(s)===-1);if(n.length)throw new Error("wix-access: web methods missing from policy.api: "+n.join(", "));return!0}var kt=100,Lr=100;function Pt(t,e,r){let{items:n,auth:s}=e,o=r.abilityFor,i={query:s.elevate(n.query),get:s.elevate(n.get),insert:s.elevate(n.insert),update:s.elevate(n.update),remove:s.elevate(n.remove)},a=c=>{let u=t.collections&&t.collections[c]||null;return u&&u.owner?u.owner:null},l=c=>{let u=t.collections&&t.collections[c]||null;return u&&u.resource||c};async function d(c,u){let f=[],p=await c.limit(Math.min(u||kt,kt)).find(),y=0;for(;p;){for(let b of p.items)f.push(b);if(u&&f.length>=u)return f.slice(0,u);if(!p.hasNext||!p.hasNext()||++y>=Lr)break;p=await p.next()}return f}return{async query(c,u){let{principal:f,action:p="read",limit:y}=u,b=l(c),h=ce(f,t,p,b);if(h.scope===x.NONE)return{ok:!0,data:[],scope:h.scope};let g=i.query(c);h.scope===x.FIELDS&&(g=ue(g,h.clauses));let $=await d(g,h.scope===x.AMBIGUOUS?null:y);if(h.scope!==x.AMBIGUOUS)return{ok:!0,data:$,scope:h.scope};let O=o(f),T=$.filter(k=>w(O,p,b,k));return{ok:!0,data:y?T.slice(0,y):T,scope:h.scope}},async get(c,u,f){let{principal:p,action:y="read"}=f,b=l(c),h=await i.get(c,u);return h?w(o(p),y,b,h)?{ok:!0,data:h}:j(y):j(y)},async insert(c,u,f){let{principal:p,action:y="create"}=f,b=l(c),h=a(c),g=Object.assign({},u);return h&&p.memberId&&(g[h]=p.memberId),w(o(p),y,b,g)?{ok:!0,data:await i.insert(c,g)}:M(v.FORBIDDEN,y)},async update(c,u,f,p){let{principal:y,action:b="update"}=p,h=l(c),g=await i.get(c,u);if(!g)return j(b);if(!w(o(y),b,h,g))return j(b);let $=a(c),O=Object.assign({},g,f,{_id:u});return $&&(O[$]=g[$]),{ok:!0,data:await i.update(c,O)}},async remove(c,u,f){let{principal:p,action:y="delete"}=f,b=l(c),h=await i.get(c,u);return h?w(o(p),y,b,h)?{ok:!0,data:await i.remove(c,u)}:j(y):j(y)}}}function Tt(t,e,r){J(t);let n=r||{},s=Rt(e,{enrich:n.enrich,onError:n.onError}),o=l=>ae(l,t),i=_t(t,e,{resolveCaller:s,abilityFor:o,audit:n.audit}),a=Pt(t,e,{abilityFor:o});return{policy:t,resolveCaller:s,abilityFor:o,guarded:i,db:a,rulesForCaller:async()=>D(await s(),t)}}function Vr(t,e){let r=e||{},n=Object.assign({wixUsers:Ut.default,currentMember:et.currentMember,items:qt.items,auth:Bt.auth,webMethod:le.webMethod,Permissions:le.Permissions},r.deps||{});return Tt(t,n,r)}function zr(){return{ok:!0,side:"backend",version:Xe}}async function Gr(){try{let t=await et.currentMember.getMember();return t&&t._id||null}catch{return null}}0&&(module.exports={CASES,CODES,KIND,PACKAGE_VERSION,PolicyError,SCOPE,WHEN,abilityFor,abilityFromRules,anonymous,applyClauses,assertDeclared,backendMemberId,backendPing,can,caseTable,createAccess,createPrincipal,deny,denyOpaque,filterFor,hasRole,isDenial,normaliseRoles,ok,permissionFor,resolvePlaceholders,resolveSubjects,resolveWhere,rulesFor,validatePolicy});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@liquisio/wix-access",
3
- "version": "0.2.0",
4
- "description": "Probe stub for @liquisio/wix-access: proves the two-bundle layout (backend.js + public.js, shared pure core, CASL inlined) on a real Wix site before the real package is built.",
3
+ "version": "0.3.0",
4
+ "description": "One authorization policy for Wix, serving the web-method gate, backend, database and page code. Built against measured platform behaviour.",
5
5
  "main": "./index.js",
6
6
  "types": "./types.d.ts",
7
7
  "scripts": {
@@ -12,11 +12,21 @@
12
12
  },
13
13
  "exports": {
14
14
  ".": { "types": "./types.d.ts", "default": "./index.js" },
15
- "./backend": { "types": "./types.d.ts", "default": "./backend.js" },
16
- "./public": { "types": "./types.d.ts", "default": "./public.js" }
15
+ "./backend": { "types": "./backend.d.ts", "default": "./backend.js" },
16
+ "./public": { "types": "./public.d.ts", "default": "./public.js" }
17
17
  },
18
- "files": ["index.js", "backend.js", "public.js", "types.d.ts", "README.md"],
18
+ "files": [
19
+ "index.js",
20
+ "backend.js",
21
+ "public.js",
22
+ "types.d.ts",
23
+ "backend.d.ts",
24
+ "public.d.ts",
25
+ "README.md"
26
+ ],
19
27
  "engines": { "node": ">=18" },
28
+ "keywords": ["wix", "velo", "blocks", "authorization", "permissions", "access-control", "casl"],
29
+ "author": "Varun Dev <hello@liquis.io>",
20
30
  "license": "MIT",
21
31
  "publishConfig": { "access": "public" },
22
32
  "devDependencies": {
package/public.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ export * from './types'
2
+ import { Ability, SerialisedRule } from './types'
3
+
4
+ export type GuardMode = 'hide' | 'disable' | 'collapse'
5
+
6
+ export interface FrontendAccessOptions {
7
+ /** YOUR web method returning this caller's rules. The package cannot import it. */
8
+ fetchRules: () => Promise<SerialisedRule[]>
9
+ onError?: (error: unknown) => void
10
+ }
11
+
12
+ export interface FrontendAccess {
13
+ /** Fetches once. Safe to call from several widgets concurrently. */
14
+ ready(): Promise<FrontendAccess>
15
+ /** Re-fetches. Call after a login. */
16
+ refresh(): Promise<FrontendAccess>
17
+ can(action: string, resource: string, object?: unknown): boolean
18
+ cannot(action: string, resource: string, object?: unknown): boolean
19
+ rules(): SerialisedRule[]
20
+ readonly loaded: boolean
21
+ /** True when the rules could not be fetched: "unavailable", not "not allowed". */
22
+ readonly failed: boolean
23
+ guard(element: unknown, action: string, resource: string, object?: unknown, mode?: GuardMode): boolean
24
+ apply(element: unknown, allowed: boolean, mode?: GuardMode): boolean
25
+ }
26
+
27
+ export declare function createAccess(options: FrontendAccessOptions): FrontendAccess
28
+ export declare function publicPing(): { ok: boolean; side: string; version: string }
29
+ export declare function frontendRoleTitles(): Promise<string[]>
30
+ export declare function caseTable(ability: Ability): Array<{ action: string; type: string; object: object; can: boolean }>
31
+ export declare const CASES: Array<{ action: string; type: string; object: object }>
package/public.js CHANGED
@@ -1 +1 @@
1
- var P=Object.defineProperty;var Ye=Object.getOwnPropertyDescriptor;var He=Object.getOwnPropertyNames;var We=Object.prototype.hasOwnProperty;var Xe=(t,e)=>{for(var r in e)P(t,r,{get:e[r],enumerable:!0})},Ze=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of He(e))!We.call(t,n)&&n!==r&&P(t,n,{get:()=>e[n],enumerable:!(s=Ye(e,n))||s.enumerable});return t};var et=t=>Ze(P({},"__esModule",{value:!0}),t);var Lt={};Xe(Lt,{CASES:()=>we,PACKAGE_VERSION:()=>be,abilityFor:()=>Je,abilityFromRules:()=>ve,caseTable:()=>Qe,frontendRoleTitles:()=>Dt,publicPing:()=>zt,resolvePlaceholders:()=>v,rulesFor:()=>$e});module.exports=et(Lt);var Ge=require("wix-members-frontend");var w=class{constructor(e,r){this.operator=e,this.value=r,Object.defineProperty(this,"t",{writable:!0})}get notes(){return this.t}addNote(e){this.t=this.t||[],this.t.push(e)}},y=class extends w{},p=class extends y{constructor(e,r){if(!Array.isArray(r))throw new Error(`"${e}" operator expects to receive an array of conditions`);super(e,r)}},l="__itself__",f=class extends w{constructor(e,r,s){super(e,s),this.field=r}},q=new y("__null__",null),R=Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function tt(t,e){return e instanceof p&&e.operator===t}function k(t,e){return e.length===1?e[0]:new p(t,(function r(s,n,o){let i=o||[];for(let a=0,c=n.length;a<c;a++){let u=n[a];tt(s,u)?r(s,u.value,i):i.push(u)}return i})(t,e))}var rt=t=>t,xe=()=>Object.create(null),je=Object.defineProperty(xe(),"__@type@__",{value:"ignore value"});function st(t,e,r=!1){if(!t||t&&t.constructor!==Object)return!1;for(let s in t)if(R(t,s)&&R(e,s)&&(!r||t[s]!==je))return!0;return!1}function nt(t){let e=[];for(let r in t)R(t,r)&&t[r]!==je&&e.push(r);return e}function N(t,e){e!==q&&t.push(e)}var z=t=>k("and",t);var x={compound(t,e,r){let s=(Array.isArray(e)?e:[e]).map(n=>r.parse(n));return new p(t.name,s)},field:(t,e,r)=>new f(t.name,r.field,e),document:(t,e)=>new y(t.name,e)},g=class{constructor(e,r=xe()){this.o=void 0,this.s=void 0,this.i=void 0,this.u=void 0,this.h=void 0,this.parse=this.parse.bind(this),this.u={operatorToConditionName:r.operatorToConditionName||rt,defaultOperatorName:r.defaultOperatorName||"eq",mergeFinalConditions:r.mergeFinalConditions||z},this.o=Object.keys(e).reduce((s,n)=>(s[n]=Object.assign({name:this.u.operatorToConditionName(n)},e[n]),s),{}),this.s=Object.assign({},r.fieldContext,{field:"",query:{},parse:this.parse,hasOperators:s=>st(s,this.o,r.useIgnoreValue)}),this.i=Object.assign({},r.documentContext,{parse:this.parse,query:{}}),this.h=r.useIgnoreValue?nt:Object.keys}setParse(e){this.parse=e,this.s.parse=e,this.i.parse=e}parseField(e,r,s,n){let o=this.o[r];if(!o)throw new Error(`Unsupported operator "${r}"`);if(o.type!=="field")throw new Error(`Unexpected ${o.type} operator "${r}" at field level`);return this.s.field=e,this.s.query=n,this.parseInstruction(o,s,this.s)}parseInstruction(e,r,s){return typeof e.validate=="function"&&e.validate(e,r),(e.parse||x[e.type])(e,r,s)}parseFieldOperators(e,r){let s=[],n=this.h(r);for(let o=0,i=n.length;o<i;o++){let a=n[o];if(!this.o[a])throw new Error(`Field query for "${e}" may contain only operators or a plain object as a value`);N(s,this.parseField(e,a,r[a],r))}return s}parse(e){let r=[],s=this.h(e);this.i.query=e;for(let n=0,o=s.length;n<o;n++){let i=s[n],a=e[i],c=this.o[i];if(c){if(c.type!=="document"&&c.type!=="compound")throw new Error(`Cannot use parsing instruction for operator "${i}" in "document" context as it is supposed to be used in "${c.type}" context`);N(r,this.parseInstruction(c,a,this.i))}else this.s.hasOperators(a)?r.push(...this.parseFieldOperators(i,a)):N(r,this.parseField(i,this.u.defaultOperatorName,a,e))}return this.u.mergeFinalConditions(r)}};function S(t,e){let r=t[e];if(typeof r!="function")throw new Error(`Unable to interpret "${e}" condition. Did you forget to register interpreter for it?`);return r}function ot(t){return t.operator}function Oe(t,e){let r=e,s=r&&r.getInterpreterName||ot,n;switch(r?r.numberOfArguments:0){case 1:n=i=>{let a=s(i,r);return S(t,a)(i,o)};break;case 3:n=(i,a,c)=>{let u=s(i,r);return S(t,u)(i,a,c,o)};break;default:n=(i,a)=>{let c=s(i,r);return S(t,c)(i,a,o)}}let o=Object.assign({},r,{interpret:n});return o.interpret}function Ae(t,e){return(r,...s)=>{let n=t(r,...s),o=e.bind(null,n);return o.ast=n,o}}var Vt=g.prototype.parseInstruction;function Ee(t,e){if(!Array.isArray(e))throw new Error(`"${t.name}" expects value to be an array`)}function Fe(t,e){if(Ee(t,e),!e.length)throw new Error(`"${t.name}" expects to have at least one element in array`)}var D=t=>(e,r)=>{if(typeof r!==t)throw new Error(`"${e.name}" expects value to be a "${t}"`)},Ce={type:"compound",validate:Fe,parse(t,e,{parse:r}){let s=e.map(n=>r(n));return k(t.name,s)}},it=Ce,at={type:"compound",validate:Fe},ct={type:"field",validate(t,e){if(!(e&&(e instanceof RegExp||e.constructor===Object)))throw new Error(`"${t.name}" expects to receive either regular expression or object of field operators`)},parse(t,e,r){let s=e instanceof RegExp?new f("regex",r.field,e):r.parse(e,r);return new p(t.name,[s])}},L={type:"field",validate(t,e){if(!e||e.constructor!==Object)throw new Error(`"${t.name}" expects to receive an object with nested query or field level operators`)},parse(t,e,{parse:r,field:s,hasOperators:n}){let o=n(e)?r(e,{field:l}):r(e);return new f(t.name,s,o)}},U={type:"field",validate:D("number")},m={type:"field",validate:Ee},V=m,B=m,ut={type:"field",validate(t,e){if(!Array.isArray(e)||e.length!==2)throw new Error(`"${t.name}" expects an array with 2 numeric elements`)}},J={type:"field",validate:D("boolean")},O={type:"field",validate:function(t,e){if(!(typeof e=="string"||typeof e=="number"||e instanceof Date))throw new Error(`"${t.name}" expects value to be comparable (i.e., string, number or date)`)}},b=O,Q=b,G=b,A={type:"field"},K=A,Y={type:"field",validate(t,e){if(!(e instanceof RegExp)&&typeof e!="string")throw new Error(`"${t.name}" expects value to be a regular expression or a string that represents regular expression`)},parse(t,e,r){let s=typeof e=="string"?new RegExp(e,r.query.$options||""):e;return new f(t.name,r.field,s)}},H={type:"field",parse:()=>q},lt={type:"document",validate:D("function")},pt=Object.freeze({__proto__:null,$and:Ce,$or:it,$nor:at,$not:ct,$elemMatch:L,$size:U,$in:m,$nin:V,$all:B,$mod:ut,$exists:J,$gte:O,$gt:b,$lt:Q,$lte:G,$eq:A,$ne:K,$regex:Y,$options:H,$where:lt}),j=class extends g{constructor(e){super(e,{defaultOperatorName:"$eq",operatorToConditionName:r=>r.slice(1)})}parse(e,r){return r&&r.field?z(this.parseFieldOperators(r.field,e)):super.parse(e)}},E=pt;function W(t,e,r){for(let s=0,n=t.length;s<n;s++)if(r(t[s],e)===0)return!0;return!1}function X(t,e){return Array.isArray(t)&&Number.isNaN(Number(e))}function Me(t,e,r){if(!X(t,e))return r(t,e);let s=[];for(let n=0;n<t.length;n++){let o=r(t[n],e);o!==void 0&&(s=s.concat(o))}return s}function h(t){return(e,r,s)=>{let n=s.get(r,e.field);return Array.isArray(n)?n.some(o=>t(e,o,s)):t(e,n,s)}}var ft=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty),ht=(t,e)=>t[e];function _e(t,e,r){let s=e.lastIndexOf(".");return s===-1?[t,e]:[r(t,e.slice(0,s)),e.slice(s+1)]}function dt(t,e,r=ht){if(e===l)return t;if(!t)throw new Error(`Unable to get field "${e}" out of ${String(t)}.`);return(function(s,n,o){if(n.indexOf(".")===-1)return Me(s,n,o);let i=n.split("."),a=s;for(let c=0,u=i.length;c<u;c++)if(a=Me(a,i[c],o),!a||typeof a!="object")return c<u-1?void 0:a;return a})(t,e,r)}function Z(t,e){return t===e?0:t>e?1:-1}function ee(t,e={}){return Oe(t,Object.assign({get:dt,compare:Z},e))}var Ie=(t,e,{interpret:r})=>t.value.some(s=>r(s,e)),yt=(t,e,r)=>!Ie(t,e,r),te=(t,e,{interpret:r})=>t.value.every(s=>r(s,e)),gt=(t,e,{interpret:r})=>!r(t.value[0],e),F=(t,e,{compare:r,get:s})=>{let n=s(e,t.field);return Array.isArray(n)&&!Array.isArray(t.value)?W(n,t.value,r):r(n,t.value)===0},re=(t,e,r)=>!F(t,e,r),se=h((t,e,r)=>{let s=r.compare(e,t.value);return s===0||s===-1}),ne=h((t,e,r)=>r.compare(e,t.value)===-1),oe=h((t,e,r)=>r.compare(e,t.value)===1),ie=h((t,e,r)=>{let s=r.compare(e,t.value);return s===0||s===1}),ae=(t,e,{get:r})=>{if(t.field===l)return e!==void 0;let[s,n]=_e(e,t.field,r),o=i=>i==null?!!i===t.value:ft(i,n)===t.value;return X(s,n)?s.some(o):o(s)},mt=h((t,e)=>typeof e=="number"&&e%t.value[0]===t.value[1]),ce=(t,e,{get:r})=>{let[s,n]=_e(e,t.field,r),o=i=>{let a=r(i,n);return Array.isArray(a)&&a.length===t.value};return t.field!==l&&X(s,n)?s.some(o):o(s)},ue=h((t,e)=>typeof e=="string"&&t.value.test(e)),$=h((t,e,{compare:r})=>W(t.value,e,r)),le=(t,e,r)=>!$(t,e,r),pe=(t,e,{compare:r,get:s})=>{let n=s(e,t.field);return Array.isArray(n)&&t.value.every(o=>W(n,o,r))},fe=(t,e,{interpret:r,get:s})=>{let n=s(e,t.field);return Array.isArray(n)&&n.some(o=>r(t.value,o))},bt=(t,e)=>t.value.call(e),$t=Object.freeze({__proto__:null,or:Ie,nor:yt,and:te,not:gt,eq:F,ne:re,lte:se,lt:ne,gt:oe,gte:ie,exists:ae,mod:mt,size:ce,regex:ue,within:$,nin:le,all:pe,elemMatch:fe,where:bt}),C=Object.assign({},$t,{in:$}),Yt=ee(C);function Te(t){return t===null||typeof t!="object"?t:t instanceof Date?t.getTime():t&&typeof t.toJSON=="function"?t.toJSON():t}var vt=(t,e)=>Z(Te(t),Te(e));function M(t,e,r){let s=new j(t),n=ee(e,Object.assign({compare:vt},r));if(r&&r.forPrimitives){let o={field:l},i=s.parse;s.setParse(a=>i(a,o))}return Ae(s.parse,n)}var er=M(E,C),tr=M(["$and","$or"].reduce((t,e)=>(t[e]=Object.assign({},t[e],{type:"field"}),t),Object.assign({},E,{$nor:Object.assign({},E.$nor,{type:"field",parse:x.compound})})),C,{forPrimitives:!0});var ke=Object.hasOwn||((t,e)=>Object.prototype.hasOwnProperty.call(t,e));function he(t){return Array.isArray(t)?t:[t]}var d="__caslSubjectType__";function ze(t,e){if(e){if(!ke(e,d))Object.defineProperty(e,d,{value:t});else if(t!==e[d])throw new Error(`Trying to cast object to subject type ${t} but previously it was casted to ${e[d]}`)}return e}var I=t=>{let e=typeof t;return e==="string"||e==="function"},De=t=>t.modelName||t.name;function wt(t){return typeof t=="string"?t:De(t)}function Le(t){return ke(t,d)?t[d]:De(t.constructor)}var Pe={function:t=>t.constructor,string:Le};function Ne(t,e,r){for(let s=r;s<e.length;s++)t.push(e[s])}function Se(t,e){if(!t||!t.length)return e||[];if(!e||!e.length)return t||[];let r=0,s=0,n=[];for(;r<t.length&&s<e.length;)t[r].priority<e[s].priority?(n.push(t[r]),r++):t[r].priority>e[s].priority?(n.push(e[s]),s++):(n.push(t[r]),r++,s++);return Ne(n,t,r),Ne(n,e,s),n}function _(t,e,r){let s=t.get(e);return s||(s=r(),t.set(e,s)),s}var xt=t=>t;function jt(t,e){let r;for(let s=0;s<t.length;s++){let n=e(t[s]);r&&n&&r.push(t[s]),n||(r??(r=t.slice(0,s)))}return r||t}function Ot(t,e){if(Array.isArray(t.fields)&&!t.fields.length)throw new Error("`rawRule.fields` cannot be an empty array. https://bit.ly/390miLa");if(t.fields&&!e.fieldMatcher)throw new Error('You need to pass "fieldMatcher" option in order to restrict access by fields');if(t.conditions&&!e.conditionsMatcher)throw new Error('You need to pass "conditionsMatcher" option in order to restrict access by conditions')}var de=class{constructor(e,r,s=0){Ot(e,r),this.action=r.resolveAction(e.action),this.subject=e.subject,this.inverted=!!e.inverted,this.conditions=e.conditions,this.reason=e.reason,this.origin=e,this.fields=e.fields?he(e.fields):void 0,this.priority=s,this.t=r}i(){return this.conditions&&!this.o&&(this.o=this.t.conditionsMatcher(this.conditions)),this.o}get ast(){let e=this.i();return e?e.ast:void 0}matchesConditions(e){return this.conditions?!e||I(e)?!this.inverted:this.i()(e):!0}matchesField(e){return this.fields?e?(this.u||(this.u=this.t.fieldMatcher(this.fields)),this.u(e)):!this.inverted:!0}};function At(t,e){let r={value:t,prev:e,next:null};return e&&(e.next=r),r}function Et(t){t.next&&(t.next.prev=t.prev),t.prev&&(t.prev.next=t.next),t.next=t.prev=null}var Re=()=>({rules:[],merged:!1}),qe=()=>new Map,ye=class{constructor(e=[],r={}){this.h=!1,this.l=new Map,this.p={conditionsMatcher:r.conditionsMatcher,fieldMatcher:r.fieldMatcher,resolveAction:r.resolveAction||xt},this.$=r.anyAction||"manage",this.A=r.anySubjectType||"all",this.m=e,this.M=!!r.detectSubjectType,this.j=r.detectSubjectType||Le,this.v(e)}get rules(){return this.m}detectSubjectType(e){return I(e)?e:e?this.j(e):this.A}update(e){let r={rules:e,ability:this,target:this};return this._("update",r),this.m=e,this.v(e),this._("updated",r),this}v(e){let r=new Map,s;for(let n=e.length-1;n>=0;n--){let o=e.length-n-1,i=new de(e[n],this.p,o),a=he(i.action),c=he(i.subject||this.A);!this.h&&i.fields&&(this.h=!0);for(let u=0;u<c.length;u++){let Ke=_(r,c[u],qe);s===void 0&&(s=typeof c[u]),typeof c[u]!==s&&s!=="mixed"&&(s="mixed");for(let T=0;T<a.length;T++)_(Ke,a[T],Re).rules.push(i)}}if(this.l=r,s!=="mixed"&&!this.M){let n=Pe[s]||Pe.string;this.j=n}}possibleRulesFor(e,r=this.A){if(!I(r))throw new Error('"possibleRulesFor" accepts only subject types (i.e., string or class) as the 2nd parameter');let s=_(this.l,r,qe),n=_(s,e,Re);if(n.merged)return n.rules;let o=e!==this.$&&s.has(this.$)?s.get(this.$).rules:void 0,i=Se(n.rules,o);return r!==this.A&&(i=Se(i,this.possibleRulesFor(e,this.A))),n.rules=i,n.merged=!0,i}rulesFor(e,r,s){let n=this.possibleRulesFor(e,r);if(s&&typeof s!="string")throw new Error("The 3rd, `field` parameter is expected to be a string. See https://stalniy.github.io/casl/en/api/casl-ability#can-of-pure-ability for details");return this.h?jt(n,o=>o.matchesField(s)):n}actionsFor(e){if(!I(e))throw new Error('"actionsFor" accepts only subject types (i.e., string or class) as a parameter');let r=new Set,s=this.l.get(e);s&&Array.from(s.keys()).forEach(o=>r.add(o));let n=e!==this.A?this.l.get(this.A):void 0;return n&&Array.from(n.keys()).forEach(o=>r.add(o)),Array.from(r)}on(e,r){this.F=this.F||new Map;let s=this.F,n=s.get(e)||null,o=At(r,n);return s.set(e,o),()=>{let i=s.get(e);!o.next&&!o.prev&&i===o?s.delete(e):o===i&&s.set(e,o.prev),Et(o)}}_(e,r){if(!this.F)return;let s=this.F.get(e)||null,n=[];for(;s!==null;)n.push(s.value),s=s.prev;for(let o=0;o<n.length;o++)n[o](r)}},ge=class extends ye{can(e,r,s){let n=this.relevantRuleFor(e,r,s);return!!n&&!n.inverted}relevantRuleFor(e,r,s){let n=this.detectSubjectType(r),o=this.rulesFor(e,n,s);for(let i=0,a=o.length;i<a;i++)if(o[i].matchesConditions(r))return o[i];return null}cannot(e,r,s){return!this.can(e,r,s)}},Ft={$eq:A,$ne:K,$lt:Q,$lte:G,$gt:b,$gte:O,$in:m,$nin:V,$all:B,$size:U,$regex:Y,$options:H,$elemMatch:L,$exists:J},Ct={eq:F,ne:re,lt:ne,lte:se,gt:oe,gte:ie,in:$,nin:le,all:pe,size:ce,regex:ue,elemMatch:fe,exists:ae,and:te};var Mt=M(Ft,Ct),_t=/[-/\\^$+?.()|[\]{}]/g,It=/\.?\*+\.?/g,Tt=/\*+/,Pt=/\./g;function Nt(t,e,r){let s=r[0]==="*"||t[0]==="."&&t[t.length-1]==="."?"+":"*",n=t.indexOf("**")===-1?"[^.]":".",o=t.replace(Pt,"\\$&").replace(Tt,n+s);return e+t.length===r.length?`(?:${o})?`:o}function St(t,e,r){return t==="."&&(r[e-1]==="*"||r[e+1]==="*")?t:`\\${t}`}function Rt(t){let e=t.map(s=>s.replace(_t,St).replace(It,Nt)),r=e.length>1?`(?:${e.join("|")})`:e[0];return new RegExp(`^${r}$`)}var qt=t=>{let e;return r=>(typeof e>"u"&&(e=t.every(s=>s.indexOf("*")===-1)?null:Rt(t)),e===null?t.indexOf(r)!==-1:e.test(r))};function Ue(t=[],e={}){return new ge(t,Object.assign({conditionsMatcher:Mt,fieldMatcher:qt},e))}var kt=t=>`Cannot execute "${t.action}" on "${t.subjectType}"`,Ve=function(e){this.message=e};Ve.prototype=Object.create(Error.prototype);var me=class extends Ve{static setDefaultMessage(e){this.P=typeof e=="string"?()=>e:e}static from(e){return new this(e)}constructor(e){super(""),this.ability=e,typeof Error.captureStackTrace=="function"&&(this.name="ForbiddenError",Error.captureStackTrace(this,this.constructor))}setMessage(e){return this.message=e,this}throwUnlessCan(e,r,s){let n=this.unlessCan(e,r,s);if(n)throw n}unlessCan(e,r,s){let n=this.ability.relevantRuleFor(e,r,s);if(n&&!n.inverted)return;this.action=e,this.subject=r,this.subjectType=wt(this.ability.detectSubjectType(r)),this.field=s;let o=n?n.reason:"";return this.message=this.message||o||this.constructor.P(this),this}};me.P=kt;var ar=Object.freeze({__proto__:null});var be="0.2.0";function Be(t){return{ok:!0,side:t,version:be}}function v(t,e){if(t==null)return t;if(typeof t=="string")return t.indexOf("$principal.")===0?t.slice(11).split(".").reduce((s,n)=>s==null?s:s[n],e):t;if(Array.isArray(t))return t.map(r=>v(r,e));if(typeof t=="object"){let r={};for(let s of Object.keys(t))r[s]=v(t[s],e);return r}return t}function $e(t,e){let r=new Set(t&&t.subjects||[]);return(e.rules||[]).filter(s=>r.has(s.subject)).map(s=>{let n={action:s.actions,subject:s.resource};return s.where&&(n.conditions=v(s.where,t)),n})}function ve(t){return Ue(t)}function Je(t,e){return ve($e(t,e))}var we=[{action:"read",type:"Booking",object:{customerId:"m-1"}},{action:"read",type:"Booking",object:{customerId:"m-2"}},{action:"cancel",type:"Booking",object:{customerId:"m-1"}},{action:"delete",type:"Booking",object:{customerId:"m-1"}},{action:"manage",type:"Vendor",object:{_id:"v-1"}}];function Qe(t){return we.map(e=>({action:e.action,type:e.type,object:e.object,can:t.can(e.action,ze(e.type,Object.assign({},e.object)))}))}function zt(){return Be("public")}async function Dt(){try{return(await Ge.currentMember.getRoles()).map(e=>e.title)}catch{return[]}}0&&(module.exports={CASES,PACKAGE_VERSION,abilityFor,abilityFromRules,caseTable,frontendRoleTitles,publicPing,resolvePlaceholders,rulesFor});
1
+ var H=Object.defineProperty;var Et=Object.getOwnPropertyDescriptor;var It=Object.getOwnPropertyNames;var Nt=Object.prototype.hasOwnProperty;var Ft=(t,e)=>{for(var r in e)H(t,r,{get:e[r],enumerable:!0})},Mt=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of It(e))!Nt.call(t,s)&&s!==r&&H(t,s,{get:()=>e[s],enumerable:!(n=Et(e,s))||n.enumerable});return t};var Ct=t=>Mt(H({},"__esModule",{value:!0}),t);var Ar={};Ft(Ar,{CASES:()=>Ue,CODES:()=>w,KIND:()=>I,PACKAGE_VERSION:()=>De,PolicyError:()=>g,SCOPE:()=>$,WHEN:()=>y,abilityFor:()=>gt,abilityFromRules:()=>E,anonymous:()=>ze,applyClauses:()=>vt,can:()=>x,caseTable:()=>xt,createAccess:()=>wt,createPrincipal:()=>X,deny:()=>Q,denyOpaque:()=>Ve,filterFor:()=>jt,frontendRoleTitles:()=>wr,hasRole:()=>Ye,isDenial:()=>Be,normaliseRoles:()=>W,ok:()=>Le,permissionFor:()=>Ke,publicPing:()=>$r,resolvePlaceholders:()=>bt,resolveSubjects:()=>T,resolveWhere:()=>J,rulesFor:()=>R,validatePolicy:()=>Je});module.exports=Ct(Ar);var At=require("wix-members-frontend");var w={FORBIDDEN:"FORBIDDEN",UNAUTHENTICATED:"UNAUTHENTICATED",UNVERIFIED:"UNVERIFIED",NOT_FOUND:"NOT_FOUND",INVALID_POLICY:"INVALID_POLICY",INVALID_ARGUMENT:"INVALID_ARGUMENT"},g=class extends Error{constructor(e){super(e),this.name="PolicyError",this.code=w.INVALID_POLICY}};function Le(t){return{ok:!0,data:t===void 0?null:t}}function Q(t,e,r){let n={ok:!1,code:t||w.FORBIDDEN};return e&&(n.action=e),r&&(n.detail=r),n}var Be=t=>!!t&&t.ok===!1;function Ve(t){return Q(w.NOT_FOUND,t)}var I={VISITOR:"visitor",MEMBER:"member",CAPABILITY:"capability",SERVICE:"service"};function W(t){if(!Array.isArray(t))return[];let e=[];for(let r of t){if(typeof r=="string"){e.push(r);continue}if(!r||typeof r!="object")continue;let n=r.title||r.name||r.roleKey;n&&e.push(n)}return e}function X(t){let e=t||{},r=e.memberId||null,n=W(e.roles);return{kind:e.kind||(r?I.MEMBER:I.VISITOR),memberId:r,roles:n,subjects:Array.isArray(e.subjects)?e.subjects.slice():[],domain:e.domain&&typeof e.domain=="object"?e.domain:{},unverified:!!e.unverified}}var ze=()=>X({kind:I.VISITOR}),Ye=(t,e)=>t.roles.indexOf(e)!==-1;var y={ANYONE:"anyone",ANONYMOUS:"anonymous",MEMBER:"member"},h=t=>!!t&&typeof t=="object"&&!Array.isArray(t),St=t=>Array.isArray(t)?t:[t];function l(t,e){throw new g("policy"+t+": "+e)}function Rt(t,e){let r=".subjects."+t;h(e)||l(r,"must be an object");let s=["when","role","domain"].filter(o=>e[o]!==void 0);if(s.length===0&&l(r,'needs exactly one of when/role/domain \u2014 "{}" is ambiguous between a visitor and a member'),s.length>1&&l(r,"has "+s.join(" and ")+"; use exactly one"),e.when!==void 0){let o=[y.ANYONE,y.ANONYMOUS,y.MEMBER];o.indexOf(e.when)===-1&&l(r+".when","must be one of "+o.join(", ")+" (got "+JSON.stringify(e.when)+")")}e.role!==void 0&&typeof e.role!="string"&&l(r+".role","must be a string"),e.domain!==void 0&&typeof e.domain!="string"&&l(r+".domain","must be a string")}function _t(t,e,r){let n=".rules["+e+"]";h(t)||l(n,"must be an object"),typeof t.subject!="string"&&l(n+".subject","must be a string"),r.indexOf(t.subject)===-1&&l(n+".subject",'"'+t.subject+'" is not declared in policy.subjects'),t.actions===void 0&&l(n+".actions","is required");for(let s of St(t.actions))typeof s!="string"&&l(n+".actions","must be a string or an array of strings");typeof t.resource!="string"&&l(n+".resource","must be a string"),t.where!==void 0&&!h(t.where)&&l(n+".where","must be an object")}var Ge=["Anyone","SiteMember","Admin"];function Tt(t,e,r){let n=".api."+t;h(e)||l(n,"must be an object"),Ge.indexOf(e.permission)===-1&&l(n+".permission","must be one of "+Ge.join(", ")+" (got "+JSON.stringify(e.permission)+")"),e.ability!==void 0&&((!Array.isArray(e.ability)||e.ability.length!==2)&&l(n+".ability","must be [action, resource]"),(typeof e.ability[0]!="string"||typeof e.ability[1]!="string")&&l(n+".ability","both entries must be strings")),e.subject!==void 0&&r.indexOf(e.subject)===-1&&l(n+".subject",'"'+e.subject+'" is not declared in policy.subjects')}function Je(t){if(!h(t))throw new g("policy must be an object");h(t.subjects)||l(".subjects","is required and must be an object");let e=Object.keys(t.subjects);e.length===0&&l(".subjects","declares no subjects");for(let r of e)Rt(r,t.subjects[r]);if(Array.isArray(t.rules)||l(".rules","is required and must be an array"),t.rules.forEach((r,n)=>_t(r,n,e)),t.api!==void 0){h(t.api)||l(".api","must be an object");for(let r of Object.keys(t.api))Tt(r,t.api[r],e)}return t.collections!==void 0&&!h(t.collections)&&l(".collections","must be an object"),t}function T(t,e){let r=new Set(t.subjects||[]);for(let n of Object.keys(e.subjects)){let s=e.subjects[n];(s.when===y.ANYONE||s.when===y.ANONYMOUS&&!t.memberId||s.when===y.MEMBER&&t.memberId||s.role!==void 0&&t.roles.indexOf(s.role)!==-1||s.domain!==void 0&&t.domain[s.domain])&&r.add(n)}return Array.from(r)}function Ke(t,e){let r=t.api&&t.api[e];return r?r.permission:null}var P=class{constructor(e,r){this.operator=e,this.value=r,Object.defineProperty(this,"t",{writable:!0})}get notes(){return this.t}addNote(e){this.t=this.t||[],this.t.push(e)}},N=class extends P{},O=class extends N{constructor(e,r){if(!Array.isArray(r))throw new Error(`"${e}" operator expects to receive an array of conditions`);super(e,r)}},m="__itself__",j=class extends P{constructor(e,r,n){super(e,n),this.field=r}},re=new N("__null__",null),te=Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function Pt(t,e){return e instanceof O&&e.operator===t}function ne(t,e){return e.length===1?e[0]:new O(t,(function r(n,s,o){let i=o||[];for(let a=0,u=s.length;a<u;a++){let f=s[a];Pt(n,f)?r(n,f.value,i):i.push(f)}return i})(t,e))}var kt=t=>t,He=()=>Object.create(null),Qe=Object.defineProperty(He(),"__@type@__",{value:"ignore value"});function Dt(t,e,r=!1){if(!t||t&&t.constructor!==Object)return!1;for(let n in t)if(te(t,n)&&te(e,n)&&(!r||t[n]!==Qe))return!0;return!1}function Ut(t){let e=[];for(let r in t)te(t,r)&&t[r]!==Qe&&e.push(r);return e}function Z(t,e){e!==re&&t.push(e)}var se=t=>ne("and",t);var k={compound(t,e,r){let n=(Array.isArray(e)?e:[e]).map(s=>r.parse(s));return new O(t.name,n)},field:(t,e,r)=>new j(t.name,r.field,e),document:(t,e)=>new N(t.name,e)},F=class{constructor(e,r=He()){this.o=void 0,this.s=void 0,this.i=void 0,this.u=void 0,this.h=void 0,this.parse=this.parse.bind(this),this.u={operatorToConditionName:r.operatorToConditionName||kt,defaultOperatorName:r.defaultOperatorName||"eq",mergeFinalConditions:r.mergeFinalConditions||se},this.o=Object.keys(e).reduce((n,s)=>(n[s]=Object.assign({name:this.u.operatorToConditionName(s)},e[s]),n),{}),this.s=Object.assign({},r.fieldContext,{field:"",query:{},parse:this.parse,hasOperators:n=>Dt(n,this.o,r.useIgnoreValue)}),this.i=Object.assign({},r.documentContext,{parse:this.parse,query:{}}),this.h=r.useIgnoreValue?Ut:Object.keys}setParse(e){this.parse=e,this.s.parse=e,this.i.parse=e}parseField(e,r,n,s){let o=this.o[r];if(!o)throw new Error(`Unsupported operator "${r}"`);if(o.type!=="field")throw new Error(`Unexpected ${o.type} operator "${r}" at field level`);return this.s.field=e,this.s.query=s,this.parseInstruction(o,n,this.s)}parseInstruction(e,r,n){return typeof e.validate=="function"&&e.validate(e,r),(e.parse||k[e.type])(e,r,n)}parseFieldOperators(e,r){let n=[],s=this.h(r);for(let o=0,i=s.length;o<i;o++){let a=s[o];if(!this.o[a])throw new Error(`Field query for "${e}" may contain only operators or a plain object as a value`);Z(n,this.parseField(e,a,r[a],r))}return n}parse(e){let r=[],n=this.h(e);this.i.query=e;for(let s=0,o=n.length;s<o;s++){let i=n[s],a=e[i],u=this.o[i];if(u){if(u.type!=="document"&&u.type!=="compound")throw new Error(`Cannot use parsing instruction for operator "${i}" in "document" context as it is supposed to be used in "${u.type}" context`);Z(r,this.parseInstruction(u,a,this.i))}else this.s.hasOperators(a)?r.push(...this.parseFieldOperators(i,a)):Z(r,this.parseField(i,this.u.defaultOperatorName,a,e))}return this.u.mergeFinalConditions(r)}};function ee(t,e){let r=t[e];if(typeof r!="function")throw new Error(`Unable to interpret "${e}" condition. Did you forget to register interpreter for it?`);return r}function qt(t){return t.operator}function We(t,e){let r=e,n=r&&r.getInterpreterName||qt,s;switch(r?r.numberOfArguments:0){case 1:s=i=>{let a=n(i,r);return ee(t,a)(i,o)};break;case 3:s=(i,a,u)=>{let f=n(i,r);return ee(t,f)(i,a,u,o)};break;default:s=(i,a)=>{let u=n(i,r);return ee(t,u)(i,a,o)}}let o=Object.assign({},r,{interpret:s});return o.interpret}function Xe(t,e){return(r,...n)=>{let s=t(r,...n),o=e.bind(null,s);return o.ast=s,o}}var Rr=F.prototype.parseInstruction;function Ze(t,e){if(!Array.isArray(e))throw new Error(`"${t.name}" expects value to be an array`)}function et(t,e){if(Ze(t,e),!e.length)throw new Error(`"${t.name}" expects to have at least one element in array`)}var oe=t=>(e,r)=>{if(typeof r!==t)throw new Error(`"${e.name}" expects value to be a "${t}"`)},tt={type:"compound",validate:et,parse(t,e,{parse:r}){let n=e.map(s=>r(s));return ne(t.name,n)}},Lt=tt,Bt={type:"compound",validate:et},Vt={type:"field",validate(t,e){if(!(e&&(e instanceof RegExp||e.constructor===Object)))throw new Error(`"${t.name}" expects to receive either regular expression or object of field operators`)},parse(t,e,r){let n=e instanceof RegExp?new j("regex",r.field,e):r.parse(e,r);return new O(t.name,[n])}},ie={type:"field",validate(t,e){if(!e||e.constructor!==Object)throw new Error(`"${t.name}" expects to receive an object with nested query or field level operators`)},parse(t,e,{parse:r,field:n,hasOperators:s}){let o=s(e)?r(e,{field:m}):r(e);return new j(t.name,n,o)}},ae={type:"field",validate:oe("number")},M={type:"field",validate:Ze},ce=M,ue=M,zt={type:"field",validate(t,e){if(!Array.isArray(e)||e.length!==2)throw new Error(`"${t.name}" expects an array with 2 numeric elements`)}},le={type:"field",validate:oe("boolean")},U={type:"field",validate:function(t,e){if(!(typeof e=="string"||typeof e=="number"||e instanceof Date))throw new Error(`"${t.name}" expects value to be comparable (i.e., string, number or date)`)}},C=U,fe=C,pe=C,q={type:"field"},de=q,he={type:"field",validate(t,e){if(!(e instanceof RegExp)&&typeof e!="string")throw new Error(`"${t.name}" expects value to be a regular expression or a string that represents regular expression`)},parse(t,e,r){let n=typeof e=="string"?new RegExp(e,r.query.$options||""):e;return new j(t.name,r.field,n)}},ye={type:"field",parse:()=>re},Yt={type:"document",validate:oe("function")},Gt=Object.freeze({__proto__:null,$and:tt,$or:Lt,$nor:Bt,$not:Vt,$elemMatch:ie,$size:ae,$in:M,$nin:ce,$all:ue,$mod:zt,$exists:le,$gte:U,$gt:C,$lt:fe,$lte:pe,$eq:q,$ne:de,$regex:he,$options:ye,$where:Yt}),D=class extends F{constructor(e){super(e,{defaultOperatorName:"$eq",operatorToConditionName:r=>r.slice(1)})}parse(e,r){return r&&r.field?se(this.parseFieldOperators(r.field,e)):super.parse(e)}},L=Gt;function me(t,e,r){for(let n=0,s=t.length;n<s;n++)if(r(t[n],e)===0)return!0;return!1}function be(t,e){return Array.isArray(t)&&Number.isNaN(Number(e))}function rt(t,e,r){if(!be(t,e))return r(t,e);let n=[];for(let s=0;s<t.length;s++){let o=r(t[s],e);o!==void 0&&(n=n.concat(o))}return n}function v(t){return(e,r,n)=>{let s=n.get(r,e.field);return Array.isArray(s)?s.some(o=>t(e,o,n)):t(e,s,n)}}var Jt=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty),Kt=(t,e)=>t[e];function nt(t,e,r){let n=e.lastIndexOf(".");return n===-1?[t,e]:[r(t,e.slice(0,n)),e.slice(n+1)]}function Ht(t,e,r=Kt){if(e===m)return t;if(!t)throw new Error(`Unable to get field "${e}" out of ${String(t)}.`);return(function(n,s,o){if(s.indexOf(".")===-1)return rt(n,s,o);let i=s.split("."),a=n;for(let u=0,f=i.length;u<f;u++)if(a=rt(a,i[u],o),!a||typeof a!="object")return u<f-1?void 0:a;return a})(t,e,r)}function ge(t,e){return t===e?0:t>e?1:-1}function Oe(t,e={}){return We(t,Object.assign({get:Ht,compare:ge},e))}var st=(t,e,{interpret:r})=>t.value.some(n=>r(n,e)),Qt=(t,e,r)=>!st(t,e,r),je=(t,e,{interpret:r})=>t.value.every(n=>r(n,e)),Wt=(t,e,{interpret:r})=>!r(t.value[0],e),B=(t,e,{compare:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&!Array.isArray(t.value)?me(s,t.value,r):r(s,t.value)===0},ve=(t,e,r)=>!B(t,e,r),xe=v((t,e,r)=>{let n=r.compare(e,t.value);return n===0||n===-1}),$e=v((t,e,r)=>r.compare(e,t.value)===-1),we=v((t,e,r)=>r.compare(e,t.value)===1),Ae=v((t,e,r)=>{let n=r.compare(e,t.value);return n===0||n===1}),Ee=(t,e,{get:r})=>{if(t.field===m)return e!==void 0;let[n,s]=nt(e,t.field,r),o=i=>i==null?!!i===t.value:Jt(i,s)===t.value;return be(n,s)?n.some(o):o(n)},Xt=v((t,e)=>typeof e=="number"&&e%t.value[0]===t.value[1]),Ie=(t,e,{get:r})=>{let[n,s]=nt(e,t.field,r),o=i=>{let a=r(i,s);return Array.isArray(a)&&a.length===t.value};return t.field!==m&&be(n,s)?n.some(o):o(n)},Ne=v((t,e)=>typeof e=="string"&&t.value.test(e)),S=v((t,e,{compare:r})=>me(t.value,e,r)),Fe=(t,e,r)=>!S(t,e,r),Me=(t,e,{compare:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&t.value.every(o=>me(s,o,r))},Ce=(t,e,{interpret:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&s.some(o=>r(t.value,o))},Zt=(t,e)=>t.value.call(e),er=Object.freeze({__proto__:null,or:st,nor:Qt,and:je,not:Wt,eq:B,ne:ve,lte:xe,lt:$e,gt:we,gte:Ae,exists:Ee,mod:Xt,size:Ie,regex:Ne,within:S,nin:Fe,all:Me,elemMatch:Ce,where:Zt}),V=Object.assign({},er,{in:S}),Ur=Oe(V);function ot(t){return t===null||typeof t!="object"?t:t instanceof Date?t.getTime():t&&typeof t.toJSON=="function"?t.toJSON():t}var tr=(t,e)=>ge(ot(t),ot(e));function z(t,e,r){let n=new D(t),s=Oe(e,Object.assign({compare:tr},r));if(r&&r.forPrimitives){let o={field:m},i=n.parse;n.setParse(a=>i(a,o))}return Xe(n.parse,s)}var zr=z(L,V),Yr=z(["$and","$or"].reduce((t,e)=>(t[e]=Object.assign({},t[e],{type:"field"}),t),Object.assign({},L,{$nor:Object.assign({},L.$nor,{type:"field",parse:k.compound})})),V,{forPrimitives:!0});var ft=Object.hasOwn||((t,e)=>Object.prototype.hasOwnProperty.call(t,e));function Se(t){return Array.isArray(t)?t:[t]}var A="__caslSubjectType__";function pt(t,e){if(e){if(!ft(e,A))Object.defineProperty(e,A,{value:t});else if(t!==e[A])throw new Error(`Trying to cast object to subject type ${t} but previously it was casted to ${e[A]}`)}return e}var G=t=>{let e=typeof t;return e==="string"||e==="function"},dt=t=>t.modelName||t.name;function rr(t){return typeof t=="string"?t:dt(t)}function ht(t){return ft(t,A)?t[A]:dt(t.constructor)}var it={function:t=>t.constructor,string:ht};function at(t,e,r){for(let n=r;n<e.length;n++)t.push(e[n])}function ct(t,e){if(!t||!t.length)return e||[];if(!e||!e.length)return t||[];let r=0,n=0,s=[];for(;r<t.length&&n<e.length;)t[r].priority<e[n].priority?(s.push(t[r]),r++):t[r].priority>e[n].priority?(s.push(e[n]),n++):(s.push(t[r]),r++,n++);return at(s,t,r),at(s,e,n),s}function Y(t,e,r){let n=t.get(e);return n||(n=r(),t.set(e,n)),n}var nr=t=>t;function sr(t,e){let r;for(let n=0;n<t.length;n++){let s=e(t[n]);r&&s&&r.push(t[n]),s||(r??(r=t.slice(0,n)))}return r||t}function or(t,e){if(Array.isArray(t.fields)&&!t.fields.length)throw new Error("`rawRule.fields` cannot be an empty array. https://bit.ly/390miLa");if(t.fields&&!e.fieldMatcher)throw new Error('You need to pass "fieldMatcher" option in order to restrict access by fields');if(t.conditions&&!e.conditionsMatcher)throw new Error('You need to pass "conditionsMatcher" option in order to restrict access by conditions')}var Re=class{constructor(e,r,n=0){or(e,r),this.action=r.resolveAction(e.action),this.subject=e.subject,this.inverted=!!e.inverted,this.conditions=e.conditions,this.reason=e.reason,this.origin=e,this.fields=e.fields?Se(e.fields):void 0,this.priority=n,this.t=r}i(){return this.conditions&&!this.o&&(this.o=this.t.conditionsMatcher(this.conditions)),this.o}get ast(){let e=this.i();return e?e.ast:void 0}matchesConditions(e){return this.conditions?!e||G(e)?!this.inverted:this.i()(e):!0}matchesField(e){return this.fields?e?(this.u||(this.u=this.t.fieldMatcher(this.fields)),this.u(e)):!this.inverted:!0}};function ir(t,e){let r={value:t,prev:e,next:null};return e&&(e.next=r),r}function ar(t){t.next&&(t.next.prev=t.prev),t.prev&&(t.prev.next=t.next),t.next=t.prev=null}var ut=()=>({rules:[],merged:!1}),lt=()=>new Map,_e=class{constructor(e=[],r={}){this.h=!1,this.l=new Map,this.p={conditionsMatcher:r.conditionsMatcher,fieldMatcher:r.fieldMatcher,resolveAction:r.resolveAction||nr},this.$=r.anyAction||"manage",this.A=r.anySubjectType||"all",this.m=e,this.M=!!r.detectSubjectType,this.j=r.detectSubjectType||ht,this.v(e)}get rules(){return this.m}detectSubjectType(e){return G(e)?e:e?this.j(e):this.A}update(e){let r={rules:e,ability:this,target:this};return this._("update",r),this.m=e,this.v(e),this._("updated",r),this}v(e){let r=new Map,n;for(let s=e.length-1;s>=0;s--){let o=e.length-s-1,i=new Re(e[s],this.p,o),a=Se(i.action),u=Se(i.subject||this.A);!this.h&&i.fields&&(this.h=!0);for(let f=0;f<u.length;f++){let d=Y(r,u[f],lt);n===void 0&&(n=typeof u[f]),typeof u[f]!==n&&n!=="mixed"&&(n="mixed");for(let c=0;c<a.length;c++)Y(d,a[c],ut).rules.push(i)}}if(this.l=r,n!=="mixed"&&!this.M){let s=it[n]||it.string;this.j=s}}possibleRulesFor(e,r=this.A){if(!G(r))throw new Error('"possibleRulesFor" accepts only subject types (i.e., string or class) as the 2nd parameter');let n=Y(this.l,r,lt),s=Y(n,e,ut);if(s.merged)return s.rules;let o=e!==this.$&&n.has(this.$)?n.get(this.$).rules:void 0,i=ct(s.rules,o);return r!==this.A&&(i=ct(i,this.possibleRulesFor(e,this.A))),s.rules=i,s.merged=!0,i}rulesFor(e,r,n){let s=this.possibleRulesFor(e,r);if(n&&typeof n!="string")throw new Error("The 3rd, `field` parameter is expected to be a string. See https://stalniy.github.io/casl/en/api/casl-ability#can-of-pure-ability for details");return this.h?sr(s,o=>o.matchesField(n)):s}actionsFor(e){if(!G(e))throw new Error('"actionsFor" accepts only subject types (i.e., string or class) as a parameter');let r=new Set,n=this.l.get(e);n&&Array.from(n.keys()).forEach(o=>r.add(o));let s=e!==this.A?this.l.get(this.A):void 0;return s&&Array.from(s.keys()).forEach(o=>r.add(o)),Array.from(r)}on(e,r){this.F=this.F||new Map;let n=this.F,s=n.get(e)||null,o=ir(r,s);return n.set(e,o),()=>{let i=n.get(e);!o.next&&!o.prev&&i===o?n.delete(e):o===i&&n.set(e,o.prev),ar(o)}}_(e,r){if(!this.F)return;let n=this.F.get(e)||null,s=[];for(;n!==null;)s.push(n.value),n=n.prev;for(let o=0;o<s.length;o++)s[o](r)}},Te=class extends _e{can(e,r,n){let s=this.relevantRuleFor(e,r,n);return!!s&&!s.inverted}relevantRuleFor(e,r,n){let s=this.detectSubjectType(r),o=this.rulesFor(e,s,n);for(let i=0,a=o.length;i<a;i++)if(o[i].matchesConditions(r))return o[i];return null}cannot(e,r,n){return!this.can(e,r,n)}},cr={$eq:q,$ne:de,$lt:fe,$lte:pe,$gt:C,$gte:U,$in:M,$nin:ce,$all:ue,$size:ae,$regex:he,$options:ye,$elemMatch:ie,$exists:le},ur={eq:B,ne:ve,lt:$e,lte:xe,gt:we,gte:Ae,in:S,nin:Fe,all:Me,size:Ie,regex:Ne,elemMatch:Ce,exists:Ee,and:je};var lr=z(cr,ur),fr=/[-/\\^$+?.()|[\]{}]/g,pr=/\.?\*+\.?/g,dr=/\*+/,hr=/\./g;function yr(t,e,r){let n=r[0]==="*"||t[0]==="."&&t[t.length-1]==="."?"+":"*",s=t.indexOf("**")===-1?"[^.]":".",o=t.replace(hr,"\\$&").replace(dr,s+n);return e+t.length===r.length?`(?:${o})?`:o}function mr(t,e,r){return t==="."&&(r[e-1]==="*"||r[e+1]==="*")?t:`\\${t}`}function br(t){let e=t.map(n=>n.replace(fr,mr).replace(pr,yr)),r=e.length>1?`(?:${e.join("|")})`:e[0];return new RegExp(`^${r}$`)}var gr=t=>{let e;return r=>(typeof e>"u"&&(e=t.every(n=>n.indexOf("*")===-1)?null:br(t)),e===null?t.indexOf(r)!==-1:e.test(r))};function yt(t=[],e={}){return new Te(t,Object.assign({conditionsMatcher:lr,fieldMatcher:gr},e))}var Or=t=>`Cannot execute "${t.action}" on "${t.subjectType}"`,mt=function(e){this.message=e};mt.prototype=Object.create(Error.prototype);var Pe=class extends mt{static setDefaultMessage(e){this.P=typeof e=="string"?()=>e:e}static from(e){return new this(e)}constructor(e){super(""),this.ability=e,typeof Error.captureStackTrace=="function"&&(this.name="ForbiddenError",Error.captureStackTrace(this,this.constructor))}setMessage(e){return this.message=e,this}throwUnlessCan(e,r,n){let s=this.unlessCan(e,r,n);if(s)throw s}unlessCan(e,r,n){let s=this.ability.relevantRuleFor(e,r,n);if(s&&!s.inverted)return;this.action=e,this.subject=r,this.subjectType=rr(this.ability.detectSubjectType(r)),this.field=n;let o=s?s.reason:"";return this.message=this.message||o||this.constructor.P(this),this}};Pe.P=Or;var Wr=Object.freeze({__proto__:null});function ke(t,e,r){if(t==null)return t;if(typeof t=="string"){if(t.indexOf("$principal.")!==0)return t;let s=t.slice(11).split(".").reduce((o,i)=>o==null?o:o[i],e);return s==null&&(r.unresolved=!0),s}if(Array.isArray(t))return t.map(n=>ke(n,e,r));if(typeof t=="object"){let n={};for(let s of Object.keys(t))n[s]=ke(t[s],e,r);return n}return t}function J(t,e){let r={unresolved:!1};return{conditions:ke(t,e,r),unresolved:r.unresolved}}function bt(t,e){return J(t,e).conditions}function R(t,e){let r=T(t,e),n=[];for(let s of e.rules){if(r.indexOf(s.subject)===-1)continue;let o={action:s.actions,subject:s.resource};if(s.where){let{conditions:i,unresolved:a}=J(s.where,t);if(a)continue;o.conditions=i}n.push(o)}return n}function E(t){return yt(Array.isArray(t)?t:[])}function gt(t,e){return E(R(t,e))}function x(t,e,r,n){return n==null?t.can(e,r):t.can(e,pt(r,Object.assign({},n)))}var $={ALL:"all",NONE:"none",FIELDS:"fields",AMBIGUOUS:"ambiguous"},Ot={$in:"in",$nin:"nin",$ne:"ne",$gt:"gt",$gte:"gte",$lt:"lt",$lte:"lte"};function jr(t){let e=[];for(let r of Object.keys(t)){let n=t[r];if(n===null||typeof n!="object"||Array.isArray(n)){e.push({field:r,op:"eq",value:n});continue}let s=Object.keys(n);if(s.length!==1||!Ot[s[0]])return null;e.push({field:r,op:Ot[s[0]],value:n[s[0]]})}return e}var vr=(t,e)=>t==="manage"||t===e||Array.isArray(t)&&(t.indexOf(e)!==-1||t.indexOf("manage")!==-1),xr=(t,e)=>t==="all"||t===e;function jt(t,e,r,n){let s=R(t,e).filter(i=>vr(i.action,r)&&xr(i.subject,n));if(s.length===0)return{scope:$.NONE,clauses:[]};if(s.some(i=>!i.conditions))return{scope:$.ALL,clauses:[]};if(s.length>1)return{scope:$.AMBIGUOUS,clauses:[]};let o=jr(s[0].conditions);return o?{scope:$.FIELDS,clauses:o}:{scope:$.AMBIGUOUS,clauses:[]}}function vt(t,e){let r=t;for(let n of e)n.op==="in"?r=r.hasSome(n.field,n.value):n.op==="nin"?r=r.not(r.hasSome(n.field,n.value)):r=r[n.op](n.field,n.value);return r}var De="0.3.0";var Ue=[{action:"read",type:"Booking",object:{customerId:"m-1"}},{action:"read",type:"Booking",object:{customerId:"m-2"}},{action:"cancel",type:"Booking",object:{customerId:"m-1"}},{action:"delete",type:"Booking",object:{customerId:"m-1"}},{action:"manage",type:"Vendor",object:{_id:"v-1"}}];function xt(t){return Ue.map(e=>({action:e.action,type:e.type,object:e.object,can:x(t,e.action,e.type,e.object)}))}var $t=E([]);function wt(t){let e=t||{},r=e.fetchRules;if(typeof r!="function")throw new Error("wix-access: createAccess({ fetchRules }) needs your web method, e.g. import { getMyAbilities } from 'backend/access.web'. The package cannot import it for you \u2014 that specifier only resolves inside your project.");let n=e.onError||null,s=$t,o=[],i=!1,a=!1,u=null;async function f(){try{let c=await r();o=Array.isArray(c)?c:[],s=E(o),a=!1}catch(c){o=[],s=$t,a=!0,n&&n(c)}return i=!0,d}let d={ready(){return i?Promise.resolve(d):(u||(u=f().then(c=>(u=null,c))),u)},refresh(){return i=!1,u=null,d.ready()},can:(c,p,b)=>x(s,c,p,b),cannot:(c,p,b)=>!x(s,c,p,b),rules:()=>o.slice(),get loaded(){return i},get failed(){return a},guard(c,p,b,_,K){let qe=d.can(p,b,_);return d.apply(c,qe,K),qe},apply(c,p,b){if(!c)return p;let _=b||"hide";try{_==="disable"?p&&c.enable?c.enable():!p&&c.disable&&c.disable():_==="collapse"?p&&c.expand?c.expand():!p&&c.collapse&&c.collapse():p&&c.show?c.show():!p&&c.hide&&c.hide()}catch(K){n&&n(K)}return p}};return d}function $r(){return{ok:!0,side:"public",version:De}}async function wr(){try{return(await At.currentMember.getRoles()).map(e=>e.title)}catch{return[]}}0&&(module.exports={CASES,CODES,KIND,PACKAGE_VERSION,PolicyError,SCOPE,WHEN,abilityFor,abilityFromRules,anonymous,applyClauses,can,caseTable,createAccess,createPrincipal,deny,denyOpaque,filterFor,frontendRoleTitles,hasRole,isDenial,normaliseRoles,ok,permissionFor,publicPing,resolvePlaceholders,resolveSubjects,resolveWhere,rulesFor,validatePolicy});
package/types.d.ts CHANGED
@@ -1,38 +1,99 @@
1
+ // @liquisio/wix-access
2
+ //
3
+ // Import from '@liquisio/wix-access/backend' in backend code and from
4
+ // '@liquisio/wix-access/public' in page code. Nothing should import the package
5
+ // root: it exists only so npm's "main" resolves.
6
+
7
+ // ---------------------------------------------------------------- policy
1
8
  export type Permission = 'Anyone' | 'SiteMember' | 'Admin'
9
+ export type When = 'anyone' | 'anonymous' | 'member'
10
+
11
+ /** How a caller comes to hold a subject. Exactly one key, never zero. */
12
+ export type SubjectSpec = { when: When } | { role: string } | { domain: string }
2
13
 
3
14
  export interface Rule {
4
15
  subject: string
5
16
  actions: string | string[]
6
17
  resource: string
18
+ /** Values may be `'$principal.<path>'`; a path resolving to null/undefined drops the rule. */
7
19
  where?: Record<string, unknown>
8
20
  }
9
21
 
22
+ export interface CollectionSpec {
23
+ /** Resource name used in rules. Defaults to the collection id. */
24
+ resource?: string
25
+ /** Field the gateway stamps with the caller's member id — `_owner` is unusable. */
26
+ owner?: string
27
+ tenant?: string
28
+ profile?: string
29
+ }
30
+
31
+ export interface ApiEntry {
32
+ permission: Permission
33
+ ability?: [string, string]
34
+ subject?: string
35
+ }
36
+
10
37
  export interface Policy {
11
- version: number
12
- subjects: Record<string, { from?: string; roles?: string[]; wixRole?: string }>
13
- collections: Record<string, { profile: string; owner?: string; tenant?: string }>
38
+ version?: number
39
+ subjects: Record<string, SubjectSpec>
14
40
  rules: Rule[]
15
- api: Record<string, { permission: Permission; ability?: [string, string] }>
41
+ collections?: Record<string, CollectionSpec>
42
+ api?: Record<string, ApiEntry>
16
43
  }
17
44
 
45
+ // ---------------------------------------------------------------- principal
46
+ export type Kind = 'visitor' | 'member' | 'capability' | 'service'
47
+
18
48
  export interface Principal {
49
+ kind: Kind
50
+ memberId: string | null
51
+ roles: string[]
19
52
  subjects: string[]
20
- memberId?: string | null
21
- [key: string]: unknown
53
+ domain: Record<string, unknown>
54
+ /** Identity resolution itself failed. Distinct from "not logged in". */
55
+ unverified: boolean
56
+ loggedIn?: boolean
22
57
  }
23
58
 
24
- export interface AbilityLike {
25
- can(action: string, subject: unknown): boolean
26
- }
59
+ // ---------------------------------------------------------------- envelopes
60
+ export type Code = 'FORBIDDEN' | 'UNAUTHENTICATED' | 'UNVERIFIED' | 'NOT_FOUND' | 'INVALID_POLICY' | 'INVALID_ARGUMENT'
61
+ export interface Ok<T> { ok: true; data: T }
62
+ export interface Denial { ok: false; code: Code; action?: string; detail?: unknown }
63
+ export type Result<T> = Ok<T> | Denial
64
+
65
+ export declare const CODES: Record<string, Code>
66
+ export declare class PolicyError extends Error { code: 'INVALID_POLICY' }
67
+ export declare function ok<T>(data?: T): Ok<T>
68
+ export declare function deny(code: Code, action?: string, detail?: unknown): Denial
69
+ export declare function denyOpaque(action?: string): Denial
70
+ export declare function isDenial(value: unknown): value is Denial
71
+
72
+ // ---------------------------------------------------------------- core
73
+ export interface Ability { can(action: string, subject: unknown): boolean }
74
+ export interface SerialisedRule { action: string | string[]; subject: string; conditions?: Record<string, unknown> }
75
+
76
+ export declare const WHEN: { ANYONE: 'anyone'; ANONYMOUS: 'anonymous'; MEMBER: 'member' }
77
+ export declare const KIND: { VISITOR: 'visitor'; MEMBER: 'member'; CAPABILITY: 'capability'; SERVICE: 'service' }
78
+ export declare const PACKAGE_VERSION: string
79
+
80
+ export declare function validatePolicy(policy: Policy): Policy
81
+ export declare function resolveSubjects(principal: Principal, policy: Policy): string[]
82
+ export declare function permissionFor(policy: Policy, methodName: string): Permission | null
83
+ export declare function createPrincipal(input?: Partial<Principal>): Principal
84
+ export declare function anonymous(): Principal
85
+ export declare function hasRole(principal: Principal, role: string): boolean
86
+ export declare function normaliseRoles(roles: unknown[]): string[]
87
+ export declare function rulesFor(principal: Principal, policy: Policy): SerialisedRule[]
88
+ export declare function abilityFor(principal: Principal, policy: Policy): Ability
89
+ export declare function abilityFromRules(rules: SerialisedRule[]): Ability
90
+ export declare function can(ability: Ability, action: string, resource: string, object?: unknown): boolean
91
+ export declare function resolvePlaceholders<T>(where: T, principal: Principal): T
92
+ export declare function resolveWhere<T>(where: T, principal: Principal): { conditions: T; unresolved: boolean }
27
93
 
28
- export const PACKAGE_VERSION: string
29
- export function rulesFor(principal: Principal, policy: Policy): object[]
30
- export function abilityFor(principal: Principal, policy: Policy): AbilityLike
31
- export function abilityFromRules(rules: object[]): AbilityLike
32
- export function caseTable(ability: AbilityLike): Array<{ action: string; type: string; object: object; can: boolean }>
33
- export const CASES: Array<{ action: string; type: string; object: object }>
34
- export function resolvePlaceholders<T>(where: T, principal: Principal): T
35
- export function backendPing(): { ok: boolean; side: string; version: string }
36
- export function backendMemberId(): Promise<string | null>
37
- export function publicPing(): { ok: boolean; side: string; version: string }
38
- export function frontendRoleTitles(): Promise<string[]>
94
+ // ---------------------------------------------------------------- filters
95
+ export type Scope = 'all' | 'none' | 'fields' | 'ambiguous'
96
+ export interface Clause { field: string; op: string; value: unknown }
97
+ export declare const SCOPE: { ALL: 'all'; NONE: 'none'; FIELDS: 'fields'; AMBIGUOUS: 'ambiguous' }
98
+ export declare function filterFor(principal: Principal, policy: Policy, action: string, resource: string): { scope: Scope; clauses: Clause[] }
99
+ export declare function applyClauses<Q>(query: Q, clauses: Clause[]): Q