@liquisio/wix-access 0.2.0 → 0.3.1

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,208 @@
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
+ }
10
50
  ```
11
- npm install
12
- npm run verify # build + node --test
13
- npm publish
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 { guard, gateFor, 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** — you write the export line, the package decides the call.
76
+
77
+ Wix only ever hands page code a web method written in exactly this form, so the
78
+ `webMethod` call and the permission literal have to be yours:
79
+
80
+ ```js
81
+ // backend/api.web.js
82
+ import { webMethod, Permissions } from 'wix-web-module'
83
+ import { guard } from 'backend/access'
84
+ import { cancelBooking as _cancelBooking, getBooking } from 'backend/booking-service'
85
+
86
+ const _cancel = guard(
87
+ 'cancelBooking',
88
+ async ({ principal, subject }, id, options) =>
89
+ _cancelBooking(id, { ...options, cancelledBy: principal.memberId }),
90
+ {
91
+ load: (id) => getBooking(id),
92
+ // Keys the server decides for itself. Without this a caller can smuggle
93
+ // a fee waiver past the check.
94
+ strip: ['deductFees', 'processRefund']
95
+ }
96
+ )
97
+
98
+ export const cancelBooking = webMethod(Permissions.SiteMember, async (...args) => await _cancel(...args))
99
+ ```
100
+
101
+ Three rules, and breaking any of them makes the export arrive in the browser as
102
+ `undefined` rather than failing loudly:
103
+
104
+ - the `webMethod(...)` call and the `export const` are one statement;
105
+ - the permission is written out as `Permissions.LEVEL`, never computed, aliased
106
+ or bracketed;
107
+ - the second argument is a function written in place. Passing `_cancel` straight
108
+ in does not work; calling it from inside the arrow does.
109
+
110
+ Because you type the gate, it can drift from the policy. Two things stop that.
111
+ `guard` re-checks the declared level at request time, so a method the policy
112
+ calls `Admin` refuses a caller without the Admin role even if the export says
113
+ `Anyone`. And `assertGates` reads the file and compares:
114
+
115
+ ```js
116
+ // tests/gates.test.js
117
+ import { readFileSync } from 'fs'
118
+ import { assertGates } from '@liquisio/wix-access/backend'
119
+ import policy from '../src/public/access-policy.js'
120
+
121
+ assertGates(readFileSync('src/backend/api.web.js', 'utf8'), policy, { complete: true })
122
+ ```
123
+
124
+ It also flags the unreachable export shapes above, which is the failure worth
125
+ catching early: a mis-typed gate is a bug, but a dropped export is a call site
126
+ that throws "is not a function" with nothing to point at.
127
+
128
+ A method missing from `policy.api` throws at construction, so an undocumented
129
+ gate fails the build. `gateFor(name)` returns the level to type, for a test —
130
+ never at the call site, where it would be a computed permission.
131
+
132
+ **Data** — elevation and authorization together, so neither is used without the other.
133
+
134
+ ```js
135
+ import { db, resolveCaller } from 'backend/access'
136
+
137
+ const principal = await resolveCaller()
138
+ const { data: mine } = await db.query('Bookings', { principal }) // filtered to this caller
139
+ const result = await db.get('Bookings', id, { principal }) // opaque refusal if not theirs
140
+ await db.insert('Bookings', row, { principal, action: 'create' }) // stamps the owner field
141
+ ```
142
+
143
+ **Page code** — the same rules, so the UI agrees with the server.
144
+
145
+ ```js
146
+ // backend/access.web.js
147
+ import { webMethod, Permissions } from 'wix-web-module'
148
+ import { rulesForCaller } from 'backend/access'
149
+ export const getMyAbilities = webMethod(Permissions.Anyone, () => rulesForCaller())
150
+ ```
151
+
152
+ ```js
153
+ // pages/MyBookings.js
154
+ import { createAccess } from '@liquisio/wix-access/public'
155
+ import { getMyAbilities } from 'backend/access.web'
156
+
157
+ // Build it INSIDE onReady, and pass an arrow rather than the imported name.
158
+ // Run 11: at module scope a `.web.js` import was not yet a function and
159
+ // createAccess threw at import time, taking the whole page with it.
160
+ $w.onReady(async () => {
161
+ const access = createAccess({ fetchRules: (...args) => getMyAbilities(...args) })
162
+ await access.ready()
163
+ access.guard($w('#cancelBtn'), 'cancel', 'Booking', booking)
164
+ })
165
+ ```
166
+
167
+ > **Known defect (v0.3.0).** `createAccess` throws when `fetchRules` is not a
168
+ > function, which on a page means throwing at import. It should fail soft and
169
+ > deny by default instead. Until that ships, do not call it at module scope.
170
+
171
+ ## Things worth knowing
172
+
173
+ Each is measured, and each will bite otherwise.
174
+
175
+ - **Refusals are returned, never thrown.** A thrown backend error reaches the
176
+ browser as "Unable to handle the request" with the reason discarded. Check
177
+ `result.ok`.
178
+ - **A refusal on a caller-supplied id is opaque.** Forbidden and not-found return
179
+ the same code, so refusals cannot be used to enumerate ids.
180
+ - **`_owner` is unusable.** Every elevated write stores `_owner: null`, and the
181
+ app must write elevated. Declare `owner` on the collection and the gateway
182
+ stamps it explicitly.
183
+ - **`update` is checked against the stored row**, never the submitted one, so a
184
+ caller cannot authorise themselves by sending an owner field they do not own.
185
+ - **"Could not verify" is not "not allowed".** A failed roles read or enricher
186
+ yields `UNVERIFIED`, which a caller may retry. Do not collapse the two.
187
+ - **Two different admins.** `Permissions.Admin` means a site member holding the
188
+ Admin role. A collection ACL's `ADMIN` means a Wix user. They do not line up.
189
+ - **Elevation wraps SDK method references only.** `auth.elevate(items.query)`
190
+ works; `auth.elevate(() => q.find())` throws.
191
+
192
+ ## Not in this version
193
+
194
+ Measured as impossible from an installed app, rather than merely unbuilt:
195
+ collection ACLs cannot be written from code, member roles cannot be created or
196
+ assigned from code, and data hooks never fire for app-namespaced collections.
197
+ Set ACLs and roles in the CMS and dashboard. Guest capability tokens and
198
+ custom-role end-to-end flows are simply untested.
199
+
200
+ ## Development
201
+
202
+ ```bash
203
+ npm install && npm run verify # build both bundles, then 60 tests
14
204
  ```
15
205
 
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.
206
+ `backend.js` and `public.js` are the two real bundles; `index.js` is a one-line
207
+ alias so npm's `main` resolves. The core is bundled into both and must stay
208
+ pure — the purity test enforces it.
package/backend.d.ts ADDED
@@ -0,0 +1,88 @@
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
+ /**
49
+ * Wraps a handler. It does NOT create a web method: Wix only delivers an
50
+ * export written as `export const x = webMethod(Permissions.LEVEL, fn)` in
51
+ * your own file, so you write that line and call the result inside it.
52
+ */
53
+ guard<A extends unknown[], R>(
54
+ name: string,
55
+ handler: (ctx: { principal: Principal; subject: unknown }, ...args: A) => Promise<R>,
56
+ config?: GuardConfig<A>
57
+ ): (...args: A) => Promise<R | { ok: false; code: string }>
58
+ /** The permission level to type into your own webMethod() call. For tests. */
59
+ gateFor(name: string): string | null
60
+ db: Db
61
+ /** Hand these to page code from a web method. Plain JSON. */
62
+ rulesForCaller(): Promise<SerialisedRule[]>
63
+ }
64
+
65
+ export declare function createAccess(policy: Policy, options?: CreateAccessOptions): Access
66
+ /** Fails the build when an exported web method is missing from policy.api. */
67
+ export declare function assertDeclared(policy: Policy, exportedNames: string[]): true
68
+
69
+ export interface GateReport {
70
+ ok: boolean
71
+ found: Record<string, string>
72
+ mismatched: { name: string; declared: string; written: string }[]
73
+ undeclared: { name: string; gate: string }[]
74
+ missing: string[]
75
+ suspect: string[]
76
+ }
77
+
78
+ /** Reads the gates out of a .web.js file's source text. */
79
+ export declare function parseGates(source: string): Record<string, string>
80
+ /** Compares a .web.js file's typed gates against policy.api. */
81
+ export declare function verifyGates(source: string, policy: Policy, options?: { complete?: boolean }): GateReport
82
+ /** verifyGates, throwing with every problem in the message. For a test. */
83
+ export declare function assertGates(source: string, policy: Policy, options?: { complete?: boolean }): true
84
+
85
+ export declare function backendPing(): { ok: boolean; side: string; version: string }
86
+ export declare function backendMemberId(): Promise<string | null>
87
+ export declare function caseTable(ability: Ability): Array<{ action: string; type: string; object: object; can: boolean }>
88
+ export declare const CASES: Array<{ action: string; type: string; object: object }>
package/backend.js CHANGED
@@ -1 +1,3 @@
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 Yt=Object.create;var Y=Object.defineProperty;var Jt=Object.getOwnPropertyDescriptor;var Kt=Object.getOwnPropertyNames;var Zt=Object.getPrototypeOf,Ht=Object.prototype.hasOwnProperty;var Qt=(t,e)=>{for(var r in e)Y(t,r,{get:e[r],enumerable:!0})},st=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Kt(e))!Ht.call(t,s)&&s!==r&&Y(t,s,{get:()=>e[s],enumerable:!(n=Jt(e,s))||n.enumerable});return t};var Wt=(t,e,r)=>(r=t!=null?Yt(Zt(t)):{},st(e||!t||!t.__esModule?Y(r,"default",{value:t,enumerable:!0}):r,t)),Xt=t=>st(Y({},"__esModule",{value:!0}),t);var Qr={};Qt(Qr,{CASES:()=>rt,CODES:()=>O,KIND:()=>$,PACKAGE_VERSION:()=>tt,PolicyError:()=>M,SCOPE:()=>w,WHEN:()=>I,abilityFor:()=>ce,abilityFromRules:()=>Qe,anonymous:()=>at,applyClauses:()=>le,assertDeclared:()=>Tt,assertGates:()=>Rt,backendMemberId:()=>Hr,backendPing:()=>Zr,can:()=>v,caseTable:()=>kt,createAccess:()=>Kr,createPrincipal:()=>q,deny:()=>C,denyOpaque:()=>j,filterFor:()=>ue,hasRole:()=>J,isDenial:()=>it,normaliseRoles:()=>fe,ok:()=>ot,parseGates:()=>Xe,permissionFor:()=>ut,resolvePlaceholders:()=>St,resolveSubjects:()=>Z,resolveWhere:()=>ae,rulesFor:()=>k,validatePolicy:()=>K,verifyGates:()=>et});module.exports=Xt(Qr);var nt=require("wix-members-backend"),Bt=Wt(require("wix-users-backend"),1),zt=require("@wix/data"),Gt=require("@wix/essentials");var O={FORBIDDEN:"FORBIDDEN",UNAUTHENTICATED:"UNAUTHENTICATED",UNVERIFIED:"UNVERIFIED",NOT_FOUND:"NOT_FOUND",INVALID_POLICY:"INVALID_POLICY",INVALID_ARGUMENT:"INVALID_ARGUMENT"},M=class extends Error{constructor(e){super(e),this.name="PolicyError",this.code=O.INVALID_POLICY}};function ot(t){return{ok:!0,data:t===void 0?null:t}}function C(t,e,r){let n={ok:!1,code:t||O.FORBIDDEN};return e&&(n.action=e),r&&(n.detail=r),n}var it=t=>!!t&&t.ok===!1;function j(t){return C(O.NOT_FOUND,t)}var $={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?$.MEMBER:$.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 at=()=>q({kind:$.VISITOR}),J=(t,e)=>t.roles.indexOf(e)!==-1;var I={ANYONE:"anyone",ANONYMOUS:"anonymous",MEMBER:"member"},E=t=>!!t&&typeof t=="object"&&!Array.isArray(t),er=t=>Array.isArray(t)?t:[t];function h(t,e){throw new M("policy"+t+": "+e)}function tr(t,e){let r=".subjects."+t;E(e)||h(r,"must be an object");let s=["when","role","domain"].filter(o=>e[o]!==void 0);if(s.length===0&&h(r,'needs exactly one of when/role/domain \u2014 "{}" is ambiguous between a visitor and a member'),s.length>1&&h(r,"has "+s.join(" and ")+"; use exactly one"),e.when!==void 0){let o=[I.ANYONE,I.ANONYMOUS,I.MEMBER];o.indexOf(e.when)===-1&&h(r+".when","must be one of "+o.join(", ")+" (got "+JSON.stringify(e.when)+")")}e.role!==void 0&&typeof e.role!="string"&&h(r+".role","must be a string"),e.domain!==void 0&&typeof e.domain!="string"&&h(r+".domain","must be a string")}function rr(t,e,r){let n=".rules["+e+"]";E(t)||h(n,"must be an object"),typeof t.subject!="string"&&h(n+".subject","must be a string"),r.indexOf(t.subject)===-1&&h(n+".subject",'"'+t.subject+'" is not declared in policy.subjects'),t.actions===void 0&&h(n+".actions","is required");for(let s of er(t.actions))typeof s!="string"&&h(n+".actions","must be a string or an array of strings");typeof t.resource!="string"&&h(n+".resource","must be a string"),t.where!==void 0&&!E(t.where)&&h(n+".where","must be an object")}var ct=["Anyone","SiteMember","Admin"];function nr(t,e,r){let n=".api."+t;E(e)||h(n,"must be an object"),ct.indexOf(e.permission)===-1&&h(n+".permission","must be one of "+ct.join(", ")+" (got "+JSON.stringify(e.permission)+")"),e.ability!==void 0&&((!Array.isArray(e.ability)||e.ability.length!==2)&&h(n+".ability","must be [action, resource]"),(typeof e.ability[0]!="string"||typeof e.ability[1]!="string")&&h(n+".ability","both entries must be strings")),e.subject!==void 0&&r.indexOf(e.subject)===-1&&h(n+".subject",'"'+e.subject+'" is not declared in policy.subjects')}function K(t){if(!E(t))throw new M("policy must be an object");E(t.subjects)||h(".subjects","is required and must be an object");let e=Object.keys(t.subjects);e.length===0&&h(".subjects","declares no subjects");for(let r of e)tr(r,t.subjects[r]);if(Array.isArray(t.rules)||h(".rules","is required and must be an array"),t.rules.forEach((r,n)=>rr(r,n,e)),t.api!==void 0){E(t.api)||h(".api","must be an object");for(let r of Object.keys(t.api))nr(r,t.api[r],e)}return t.collections!==void 0&&!E(t.collections)&&h(".collections","must be an object"),t}function Z(t,e){let r=new Set(t.subjects||[]);for(let n of Object.keys(e.subjects)){let s=e.subjects[n];(s.when===I.ANYONE||s.when===I.ANONYMOUS&&!t.memberId||s.when===I.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 ut(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)}},L=class extends H{},S=class extends L{constructor(e,r){if(!Array.isArray(r))throw new Error(`"${e}" operator expects to receive an array of conditions`);super(e,r)}},N="__itself__",_=class extends H{constructor(e,r,n){super(e,n),this.field=r}},me=new L("__null__",null),he=Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function sr(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,c=s.length;a<c;a++){let l=s[a];sr(n,l)?r(n,l.value,i):i.push(l)}return i})(t,e))}var or=t=>t,lt=()=>Object.create(null),ft=Object.defineProperty(lt(),"__@type@__",{value:"ignore value"});function ir(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]!==ft))return!0;return!1}function ar(t){let e=[];for(let r in t)he(t,r)&&t[r]!==ft&&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 _(t.name,r.field,e),document:(t,e)=>new L(t.name,e)},B=class{constructor(e,r=lt()){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||or,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=>ir(n,this.o,r.useIgnoreValue)}),this.i=Object.assign({},r.documentContext,{parse:this.parse,query:{}}),this.h=r.useIgnoreValue?ar: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],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`);de(r,this.parseInstruction(c,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 cr(t){return t.operator}function dt(t,e){let r=e,n=r&&r.getInterpreterName||cr,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,c)=>{let l=n(i,r);return pe(t,l)(i,a,c,o)};break;default:s=(i,a)=>{let c=n(i,r);return pe(t,c)(i,a,o)}}let o=Object.assign({},r,{interpret:s});return o.interpret}function pt(t,e){return(r,...n)=>{let s=t(r,...n),o=e.bind(null,s);return o.ast=s,o}}var on=B.prototype.parseInstruction;function ht(t,e){if(!Array.isArray(e))throw new Error(`"${t.name}" expects value to be an array`)}function mt(t,e){if(ht(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}"`)},yt={type:"compound",validate:mt,parse(t,e,{parse:r}){let n=e.map(s=>r(s));return ye(t.name,n)}},ur=yt,lr={type:"compound",validate:mt},fr={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 _("regex",r.field,e):r.parse(e,r);return new S(t.name,[n])}},xe={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:N}):r(e);return new _(t.name,n,o)}},Oe={type:"field",validate:ge("number")},z={type:"field",validate:ht},ve=z,we=z,dr={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)`)}},G=X,Ae=G,$e=G,ee={type:"field"},Ee=ee,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 _(t.name,r.field,n)}},Ne={type:"field",parse:()=>me},pr={type:"document",validate:ge("function")},hr=Object.freeze({__proto__:null,$and:yt,$or:ur,$nor:lr,$not:fr,$elemMatch:xe,$size:Oe,$in:z,$nin:ve,$all:we,$mod:dr,$exists:je,$gte:X,$gt:G,$lt:Ae,$lte:$e,$eq:ee,$ne:Ee,$regex:Ie,$options:Ne,$where:pr}),W=class extends B{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)}},te=hr;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 Me(t,e){return Array.isArray(t)&&Number.isNaN(Number(e))}function bt(t,e,r){if(!Me(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 R(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 mr=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty),yr=(t,e)=>t[e];function gt(t,e,r){let n=e.lastIndexOf(".");return n===-1?[t,e]:[r(t,e.slice(0,n)),e.slice(n+1)]}function br(t,e,r=yr){if(e===N)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 bt(n,s,o);let i=s.split("."),a=n;for(let c=0,l=i.length;c<l;c++)if(a=bt(a,i[c],o),!a||typeof a!="object")return c<l-1?void 0:a;return a})(t,e,r)}function Ce(t,e){return t===e?0:t>e?1:-1}function Se(t,e={}){return dt(t,Object.assign({get:br,compare:Ce},e))}var xt=(t,e,{interpret:r})=>t.value.some(n=>r(n,e)),gr=(t,e,r)=>!xt(t,e,r),_e=(t,e,{interpret:r})=>t.value.every(n=>r(n,e)),xr=(t,e,{interpret:r})=>!r(t.value[0],e),re=(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},Re=(t,e,r)=>!re(t,e,r),ke=R((t,e,r)=>{let n=r.compare(e,t.value);return n===0||n===-1}),De=R((t,e,r)=>r.compare(e,t.value)===-1),Pe=R((t,e,r)=>r.compare(e,t.value)===1),Te=R((t,e,r)=>{let n=r.compare(e,t.value);return n===0||n===1}),Ue=(t,e,{get:r})=>{if(t.field===N)return e!==void 0;let[n,s]=gt(e,t.field,r),o=i=>i==null?!!i===t.value:mr(i,s)===t.value;return Me(n,s)?n.some(o):o(n)},Or=R((t,e)=>typeof e=="number"&&e%t.value[0]===t.value[1]),qe=(t,e,{get:r})=>{let[n,s]=gt(e,t.field,r),o=i=>{let a=r(i,s);return Array.isArray(a)&&a.length===t.value};return t.field!==N&&Me(n,s)?n.some(o):o(n)},Le=R((t,e)=>typeof e=="string"&&t.value.test(e)),V=R((t,e,{compare:r})=>Fe(t.value,e,r)),Be=(t,e,r)=>!V(t,e,r),ze=(t,e,{compare:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&t.value.every(o=>Fe(s,o,r))},Ge=(t,e,{interpret:r,get:n})=>{let s=n(e,t.field);return Array.isArray(s)&&s.some(o=>r(t.value,o))},vr=(t,e)=>t.value.call(e),wr=Object.freeze({__proto__:null,or:xt,nor:gr,and:_e,not:xr,eq:re,ne:Re,lte:ke,lt:De,gt:Pe,gte:Te,exists:Ue,mod:Or,size:qe,regex:Le,within:V,nin:Be,all:ze,elemMatch:Ge,where:vr}),ne=Object.assign({},wr,{in:V}),dn=Se(ne);function Ot(t){return t===null||typeof t!="object"?t:t instanceof Date?t.getTime():t&&typeof t.toJSON=="function"?t.toJSON():t}var jr=(t,e)=>Ce(Ot(t),Ot(e));function se(t,e,r){let n=new W(t),s=Se(e,Object.assign({compare:jr},r));if(r&&r.forPrimitives){let o={field:N},i=n.parse;n.setParse(a=>i(a,o))}return pt(n.parse,s)}var bn=se(te,ne),gn=se(["$and","$or"].reduce((t,e)=>(t[e]=Object.assign({},t[e],{type:"field"}),t),Object.assign({},te,{$nor:Object.assign({},te.$nor,{type:"field",parse:Q.compound})})),ne,{forPrimitives:!0});var Et=Object.hasOwn||((t,e)=>Object.prototype.hasOwnProperty.call(t,e));function Ve(t){return Array.isArray(t)?t:[t]}var P="__caslSubjectType__";function It(t,e){if(e){if(!Et(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 ie=t=>{let e=typeof t;return e==="string"||e==="function"},Nt=t=>t.modelName||t.name;function Ar(t){return typeof t=="string"?t:Nt(t)}function Ft(t){return Et(t,P)?t[P]:Nt(t.constructor)}var vt={function:t=>t.constructor,string:Ft};function wt(t,e,r){for(let n=r;n<e.length;n++)t.push(e[n])}function jt(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 wt(s,t,r),wt(s,e,n),s}function oe(t,e,r){let n=t.get(e);return n||(n=r(),t.set(e,n)),n}var $r=t=>t;function Er(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 Ir(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){Ir(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?Ve(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||ie(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 Nr(t,e){let r={value:t,prev:e,next:null};return e&&(e.next=r),r}function Fr(t){t.next&&(t.next.prev=t.prev),t.prev&&(t.prev.next=t.next),t.next=t.prev=null}var At=()=>({rules:[],merged:!1}),$t=()=>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||$r},this.$=r.anyAction||"manage",this.A=r.anySubjectType||"all",this.m=e,this.M=!!r.detectSubjectType,this.j=r.detectSubjectType||Ft,this.v(e)}get rules(){return this.m}detectSubjectType(e){return ie(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=Ve(i.action),c=Ve(i.subject||this.A);!this.h&&i.fields&&(this.h=!0);for(let l=0;l<c.length;l++){let u=oe(r,c[l],$t);n===void 0&&(n=typeof c[l]),typeof c[l]!==n&&n!=="mixed"&&(n="mixed");for(let d=0;d<a.length;d++)oe(u,a[d],At).rules.push(i)}}if(this.l=r,n!=="mixed"&&!this.M){let s=vt[n]||vt.string;this.j=s}}possibleRulesFor(e,r=this.A){if(!ie(r))throw new Error('"possibleRulesFor" accepts only subject types (i.e., string or class) as the 2nd parameter');let n=oe(this.l,r,$t),s=oe(n,e,At);if(s.merged)return s.rules;let o=e!==this.$&&n.has(this.$)?n.get(this.$).rules:void 0,i=jt(s.rules,o);return r!==this.A&&(i=jt(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?Er(s,o=>o.matchesField(n)):s}actionsFor(e){if(!ie(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=Nr(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),Fr(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)}},Mr={$eq:ee,$ne:Ee,$lt:Ae,$lte:$e,$gt:G,$gte:X,$in:z,$nin:ve,$all:we,$size:Oe,$regex:Ie,$options:Ne,$elemMatch:xe,$exists:je},Cr={eq:re,ne:Re,lt:De,lte:ke,gt:Pe,gte:Te,in:V,nin:Be,all:ze,size:qe,regex:Le,elemMatch:Ge,exists:Ue,and:_e};var Sr=se(Mr,Cr),_r=/[-/\\^$+?.()|[\]{}]/g,Rr=/\.?\*+\.?/g,kr=/\*+/,Dr=/\./g;function Pr(t,e,r){let n=r[0]==="*"||t[0]==="."&&t[t.length-1]==="."?"+":"*",s=t.indexOf("**")===-1?"[^.]":".",o=t.replace(Dr,"\\$&").replace(kr,s+n);return e+t.length===r.length?`(?:${o})?`:o}function Tr(t,e,r){return t==="."&&(r[e-1]==="*"||r[e+1]==="*")?t:`\\${t}`}function Ur(t){let e=t.map(n=>n.replace(_r,Tr).replace(Rr,Pr)),r=e.length>1?`(?:${e.join("|")})`:e[0];return new RegExp(`^${r}$`)}var qr=t=>{let e;return r=>(typeof e>"u"&&(e=t.every(n=>n.indexOf("*")===-1)?null:Ur(t)),e===null?t.indexOf(r)!==-1:e.test(r))};function Mt(t=[],e={}){return new Ke(t,Object.assign({conditionsMatcher:Sr,fieldMatcher:qr},e))}var Lr=t=>`Cannot execute "${t.action}" on "${t.subjectType}"`,Ct=function(e){this.message=e};Ct.prototype=Object.create(Error.prototype);var Ze=class extends Ct{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=Ar(this.ability.detectSubjectType(r)),this.field=n;let o=s?s.reason:"";return this.message=this.message||o||this.constructor.P(this),this}};Ze.P=Lr;var An=Object.freeze({__proto__:null});function He(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=>He(n,e,r));if(typeof t=="object"){let n={};for(let s of Object.keys(t))n[s]=He(t[s],e,r);return n}return t}function ae(t,e){let r={unresolved:!1};return{conditions:He(t,e,r),unresolved:r.unresolved}}function St(t,e){return ae(t,e).conditions}function k(t,e){let r=Z(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}=ae(s.where,t);if(a)continue;o.conditions=i}n.push(o)}return n}function Qe(t){return Mt(Array.isArray(t)?t:[])}function ce(t,e){return Qe(k(t,e))}function v(t,e,r,n){return n==null?t.can(e,r):t.can(e,It(r,Object.assign({},n)))}var w={ALL:"all",NONE:"none",FIELDS:"fields",AMBIGUOUS:"ambiguous"},_t={$in:"in",$nin:"nin",$ne:"ne",$gt:"gt",$gte:"gte",$lt:"lt",$lte:"lte"};function Br(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||!_t[s[0]])return null;e.push({field:r,op:_t[s[0]],value:n[s[0]]})}return e}var zr=(t,e)=>t==="manage"||t===e||Array.isArray(t)&&(t.indexOf(e)!==-1||t.indexOf("manage")!==-1),Gr=(t,e)=>t==="all"||t===e;function ue(t,e,r,n){let s=k(t,e).filter(i=>zr(i.action,r)&&Gr(i.subject,n));if(s.length===0)return{scope:w.NONE,clauses:[]};if(s.some(i=>!i.conditions))return{scope:w.ALL,clauses:[]};if(s.length>1)return{scope:w.AMBIGUOUS,clauses:[]};let o=Br(s[0].conditions);return o?{scope:w.FIELDS,clauses:o}:{scope:w.AMBIGUOUS,clauses:[]}}function le(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 We=/export\s+const\s+([A-Za-z0-9_$]+)\s*=\s*webMethod\s*\(\s*Permissions\s*\.\s*([A-Za-z0-9_$]+)/g,Vr=[[/export\s*{\s*[A-Za-z0-9_$,\s]+}/,"export { x } \u2014 the call and the export must be one statement"],[/export\s+const\s+[A-Za-z0-9_$]+\s*=\s*webMethod\s*\(\s*Permissions\s*\[/,"Permissions['X'] \u2014 the property must be dotted and literal"],[/export\s+const\s+[A-Za-z0-9_$]+\s*=\s*webMethod\s*\(\s*[A-Za-z0-9_$]+\s*\(/,"a computed permission \u2014 it must be written out as Permissions.LEVEL"]];function Xe(t){let e={},r=String(t||"");We.lastIndex=0;let n=We.exec(r);for(;n;)e[n[1]]=n[2],n=We.exec(r);return e}function et(t,e,r){let n=r||{},s=e&&e.api||{},o=Xe(t),i=String(t||""),a=[],c=[];for(let f of Object.keys(o)){let p=s[f];p?p.permission!==o[f]&&a.push({name:f,declared:p.permission,written:o[f]}):c.push({name:f,gate:o[f]})}let l=n.complete?Object.keys(s).filter(f=>!(f in o)):[],u=[];for(let[f,p]of Vr)f.test(i)&&u.push(p);return{ok:a.length+c.length+l.length+u.length===0,found:o,mismatched:a,undeclared:c,missing:l,suspect:u}}function Rt(t,e,r){let n=et(t,e,r);if(n.ok)return!0;let s=[];for(let o of n.mismatched)s.push(o.name+": policy says "+o.declared+", the export says "+o.written);for(let o of n.undeclared)s.push(o.name+": gated "+o.gate+" but missing from policy.api");for(let o of n.missing)s.push(o+": declared in policy.api but not exported here");for(let o of n.suspect)s.push("unreachable export shape \u2014 "+o);throw new Error(`wix-access: web-method gates do not match the policy:
2
+ `+s.join(`
3
+ `))}var tt="0.3.1";var rt=[{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 kt(t){return rt.map(e=>({action:e.action,type:e.type,object:e.object,can:v(t,e.action,e.type,e.object)}))}function Dt(t,e){let{wixUsers:r,currentMember:n}=t,s=e&&e.enrich||null,o=e&&e.onError||null;return async function(){let a=null,c=!1,l=!1;try{a=r.currentUser&&r.currentUser.id||null,c=!!(r.currentUser&&r.currentUser.loggedIn)}catch(f){l=!0,o&&o("resolveCaller.id",f)}let u=[];if(a)try{u=await n.getRoles()}catch(f){l=!0,o&&o("resolveCaller.roles",f)}let d=q({kind:a?$.MEMBER:$.VISITOR,memberId:a,roles:u,unverified:l});if(d.loggedIn=c,s)try{let f=await s(d);f&&typeof f=="object"&&(d.domain=f)}catch(f){d.unverified=!0,o&&o("resolveCaller.enrich",f)}return d}}var Yr="Admin";function Pt(t,e,r){let n=r.resolveCaller,s=r.abilityFor,o=r.audit||null;function i(c,l,u,d){return o&&o({event:"access.denied",action:c,code:l,caller:u?u.memberId:null,detail:d||null}),C(l,c)}function a(c,l,u){return l==="Anyone"?null:u.memberId?l==="Admin"&&!J(u,Yr)?i(c,O.FORBIDDEN,u,{gate:l}):null:i(c,O.UNAUTHENTICATED,u)}return function(l,u,d){let f=t.api&&t.api[l]||null;if(!f)throw new Error('wix-access: web method "'+l+'" is not declared in policy.api. Add it, or the gate it runs behind is undocumented.');let p=d||{},y=f.permission,b=f.ability||null,m=p.strip||[];return async function(...x){let g=await n();if(g.unverified)return i(l,O.UNVERIFIED,g);let F=a(l,y,g);if(F)return F;let T=x.map(A=>{if(!A||typeof A!="object"||Array.isArray(A))return A;let U=Object.assign({},A);for(let Vt of m)delete U[Vt];return U}),D=null;if(b){let[A,U]=b;if(p.load){if(D=await p.load(...T),!D)return i(l,O.NOT_FOUND,g);if(!v(s(g),A,U,D))return j(l)}else if(!v(s(g),A,U))return i(l,O.FORBIDDEN,g)}return u({principal:g,subject:D},...T)}}}function Tt(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 Ut=100,Jr=100;function qt(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=u=>{let d=t.collections&&t.collections[u]||null;return d&&d.owner?d.owner:null},c=u=>{let d=t.collections&&t.collections[u]||null;return d&&d.resource||u};async function l(u,d){let f=[],p=await u.limit(Math.min(d||Ut,Ut)).find(),y=0;for(;p;){for(let b of p.items)f.push(b);if(d&&f.length>=d)return f.slice(0,d);if(!p.hasNext||!p.hasNext()||++y>=Jr)break;p=await p.next()}return f}return{async query(u,d){let{principal:f,action:p="read",limit:y}=d,b=c(u),m=ue(f,t,p,b);if(m.scope===w.NONE)return{ok:!0,data:[],scope:m.scope};let x=i.query(u);m.scope===w.FIELDS&&(x=le(x,m.clauses));let g=await l(x,m.scope===w.AMBIGUOUS?null:y);if(m.scope!==w.AMBIGUOUS)return{ok:!0,data:g,scope:m.scope};let F=o(f),T=g.filter(D=>v(F,p,b,D));return{ok:!0,data:y?T.slice(0,y):T,scope:m.scope}},async get(u,d,f){let{principal:p,action:y="read"}=f,b=c(u),m=await i.get(u,d);return m?v(o(p),y,b,m)?{ok:!0,data:m}:j(y):j(y)},async insert(u,d,f){let{principal:p,action:y="create"}=f,b=c(u),m=a(u),x=Object.assign({},d);return m&&p.memberId&&(x[m]=p.memberId),v(o(p),y,b,x)?{ok:!0,data:await i.insert(u,x)}:C(O.FORBIDDEN,y)},async update(u,d,f,p){let{principal:y,action:b="update"}=p,m=c(u),x=await i.get(u,d);if(!x)return j(b);if(!v(o(y),b,m,x))return j(b);let g=a(u),F=Object.assign({},x,f,{_id:d});return g&&(F[g]=x[g]),{ok:!0,data:await i.update(u,F)}},async remove(u,d,f){let{principal:p,action:y="delete"}=f,b=c(u),m=await i.get(u,d);return m?v(o(p),y,b,m)?{ok:!0,data:await i.remove(u,d)}:j(y):j(y)}}}function Lt(t,e,r){K(t);let n=r||{},s=Dt(e,{enrich:n.enrich,onError:n.onError}),o=c=>ce(c,t),i=Pt(t,e,{resolveCaller:s,abilityFor:o,audit:n.audit}),a=qt(t,e,{abilityFor:o});return{policy:t,resolveCaller:s,abilityFor:o,guard:i,db:a,gateFor:c=>{let l=t.api&&t.api[c]||null;return l?l.permission:null},rulesForCaller:async()=>k(await s(),t)}}function Kr(t,e){let r=e||{},n=Object.assign({wixUsers:Bt.default,currentMember:nt.currentMember,items:zt.items,auth:Gt.auth},r.deps||{});return Lt(t,n,r)}function Zr(){return{ok:!0,side:"backend",version:tt}}async function Hr(){try{let t=await nt.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,assertGates,backendMemberId,backendPing,can,caseTable,createAccess,createPrincipal,deny,denyOpaque,filterFor,hasRole,isDenial,normaliseRoles,ok,parseGates,permissionFor,resolvePlaceholders,resolveSubjects,resolveWhere,rulesFor,validatePolicy,verifyGates});
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.1",
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,38 @@
1
+ export * from './types'
2
+ import { Ability, SerialisedRule } from './types'
3
+
4
+ export type GuardMode = 'hide' | 'disable' | 'collapse'
5
+
6
+ export interface FrontendAccessOptions {
7
+ /**
8
+ * YOUR web method returning this caller's rules. The package cannot import it.
9
+ * Build the kit inside onReady and pass an arrow — a `.web.js` binding read
10
+ * at module scope may not be a function yet, and a missing one makes the kit
11
+ * deny everything rather than throw.
12
+ */
13
+ fetchRules: () => Promise<SerialisedRule[]>
14
+ onError?: (error: unknown) => void
15
+ }
16
+
17
+ export interface FrontendAccess {
18
+ /** Fetches once. Safe to call from several widgets concurrently. */
19
+ ready(): Promise<FrontendAccess>
20
+ /** Re-fetches. Call after a login. */
21
+ refresh(): Promise<FrontendAccess>
22
+ can(action: string, resource: string, object?: unknown): boolean
23
+ cannot(action: string, resource: string, object?: unknown): boolean
24
+ rules(): SerialisedRule[]
25
+ readonly loaded: boolean
26
+ /** True when the rules could not be fetched: "unavailable", not "not allowed". */
27
+ readonly failed: boolean
28
+ /** Why it failed, or null. */
29
+ readonly reason: string | null
30
+ guard(element: unknown, action: string, resource: string, object?: unknown, mode?: GuardMode): boolean
31
+ apply(element: unknown, allowed: boolean, mode?: GuardMode): boolean
32
+ }
33
+
34
+ export declare function createAccess(options: FrontendAccessOptions): FrontendAccess
35
+ export declare function publicPing(): { ok: boolean; side: string; version: string }
36
+ export declare function frontendRoleTitles(): Promise<string[]>
37
+ export declare function caseTable(ability: Ability): Array<{ action: string; type: string; object: object; can: boolean }>
38
+ export declare const CASES: Array<{ action: string; type: string; object: object }>
package/public.js CHANGED
@@ -1 +1,3 @@
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 Q=Object.defineProperty;var _t=Object.getOwnPropertyDescriptor;var Rt=Object.getOwnPropertyNames;var Pt=Object.prototype.hasOwnProperty;var Tt=(t,e)=>{for(var s in e)Q(t,s,{get:e[s],enumerable:!0})},kt=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Rt(e))!Pt.call(t,r)&&r!==s&&Q(t,r,{get:()=>e[r],enumerable:!(n=_t(e,r))||n.enumerable});return t};var Dt=t=>kt(Q({},"__esModule",{value:!0}),t);var _s={};Tt(_s,{CASES:()=>Ve,CODES:()=>E,KIND:()=>F,PACKAGE_VERSION:()=>Be,PolicyError:()=>x,SCOPE:()=>w,WHEN:()=>y,abilityFor:()=>wt,abilityFromRules:()=>N,anonymous:()=>Ke,applyClauses:()=>It,assertGates:()=>Nt,can:()=>$,caseTable:()=>Ft,createAccess:()=>St,createPrincipal:()=>ee,deny:()=>W,denyOpaque:()=>He,filterFor:()=>Et,frontendRoleTitles:()=>Cs,hasRole:()=>Qe,isDenial:()=>Ze,normaliseRoles:()=>X,ok:()=>Je,parseGates:()=>qe,permissionFor:()=>et,publicPing:()=>Ss,resolvePlaceholders:()=>$t,resolveSubjects:()=>k,resolveWhere:()=>H,rulesFor:()=>P,validatePolicy:()=>Xe,verifyGates:()=>ze});module.exports=Dt(_s);var Ct=require("wix-members-frontend");var E={FORBIDDEN:"FORBIDDEN",UNAUTHENTICATED:"UNAUTHENTICATED",UNVERIFIED:"UNVERIFIED",NOT_FOUND:"NOT_FOUND",INVALID_POLICY:"INVALID_POLICY",INVALID_ARGUMENT:"INVALID_ARGUMENT"},x=class extends Error{constructor(e){super(e),this.name="PolicyError",this.code=E.INVALID_POLICY}};function Je(t){return{ok:!0,data:t===void 0?null:t}}function W(t,e,s){let n={ok:!1,code:t||E.FORBIDDEN};return e&&(n.action=e),s&&(n.detail=s),n}var Ze=t=>!!t&&t.ok===!1;function He(t){return W(E.NOT_FOUND,t)}var F={VISITOR:"visitor",MEMBER:"member",CAPABILITY:"capability",SERVICE:"service"};function X(t){if(!Array.isArray(t))return[];let e=[];for(let s of t){if(typeof s=="string"){e.push(s);continue}if(!s||typeof s!="object")continue;let n=s.title||s.name||s.roleKey;n&&e.push(n)}return e}function ee(t){let e=t||{},s=e.memberId||null,n=X(e.roles);return{kind:e.kind||(s?F.MEMBER:F.VISITOR),memberId:s,roles:n,subjects:Array.isArray(e.subjects)?e.subjects.slice():[],domain:e.domain&&typeof e.domain=="object"?e.domain:{},unverified:!!e.unverified}}var Ke=()=>ee({kind:F.VISITOR}),Qe=(t,e)=>t.roles.indexOf(e)!==-1;var y={ANYONE:"anyone",ANONYMOUS:"anonymous",MEMBER:"member"},m=t=>!!t&&typeof t=="object"&&!Array.isArray(t),Ut=t=>Array.isArray(t)?t:[t];function l(t,e){throw new x("policy"+t+": "+e)}function Lt(t,e){let s=".subjects."+t;m(e)||l(s,"must be an object");let r=["when","role","domain"].filter(o=>e[o]!==void 0);if(r.length===0&&l(s,'needs exactly one of when/role/domain \u2014 "{}" is ambiguous between a visitor and a member'),r.length>1&&l(s,"has "+r.join(" and ")+"; use exactly one"),e.when!==void 0){let o=[y.ANYONE,y.ANONYMOUS,y.MEMBER];o.indexOf(e.when)===-1&&l(s+".when","must be one of "+o.join(", ")+" (got "+JSON.stringify(e.when)+")")}e.role!==void 0&&typeof e.role!="string"&&l(s+".role","must be a string"),e.domain!==void 0&&typeof e.domain!="string"&&l(s+".domain","must be a string")}function qt(t,e,s){let n=".rules["+e+"]";m(t)||l(n,"must be an object"),typeof t.subject!="string"&&l(n+".subject","must be a string"),s.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 r of Ut(t.actions))typeof r!="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&&!m(t.where)&&l(n+".where","must be an object")}var We=["Anyone","SiteMember","Admin"];function zt(t,e,s){let n=".api."+t;m(e)||l(n,"must be an object"),We.indexOf(e.permission)===-1&&l(n+".permission","must be one of "+We.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&&s.indexOf(e.subject)===-1&&l(n+".subject",'"'+e.subject+'" is not declared in policy.subjects')}function Xe(t){if(!m(t))throw new x("policy must be an object");m(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 s of e)Lt(s,t.subjects[s]);if(Array.isArray(t.rules)||l(".rules","is required and must be an array"),t.rules.forEach((s,n)=>qt(s,n,e)),t.api!==void 0){m(t.api)||l(".api","must be an object");for(let s of Object.keys(t.api))zt(s,t.api[s],e)}return t.collections!==void 0&&!m(t.collections)&&l(".collections","must be an object"),t}function k(t,e){let s=new Set(t.subjects||[]);for(let n of Object.keys(e.subjects)){let r=e.subjects[n];(r.when===y.ANYONE||r.when===y.ANONYMOUS&&!t.memberId||r.when===y.MEMBER&&t.memberId||r.role!==void 0&&t.roles.indexOf(r.role)!==-1||r.domain!==void 0&&t.domain[r.domain])&&s.add(n)}return Array.from(s)}function et(t,e){let s=t.api&&t.api[e];return s?s.permission:null}var D=class{constructor(e,s){this.operator=e,this.value=s,Object.defineProperty(this,"t",{writable:!0})}get notes(){return this.t}addNote(e){this.t=this.t||[],this.t.push(e)}},M=class extends D{},O=class extends M{constructor(e,s){if(!Array.isArray(s))throw new Error(`"${e}" operator expects to receive an array of conditions`);super(e,s)}},b="__itself__",j=class extends D{constructor(e,s,n){super(e,n),this.field=s}},re=new M("__null__",null),ne=Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function Bt(t,e){return e instanceof O&&e.operator===t}function oe(t,e){return e.length===1?e[0]:new O(t,(function s(n,r,o){let i=o||[];for(let a=0,u=r.length;a<u;a++){let f=r[a];Bt(n,f)?s(n,f.value,i):i.push(f)}return i})(t,e))}var Vt=t=>t,tt=()=>Object.create(null),st=Object.defineProperty(tt(),"__@type@__",{value:"ignore value"});function Gt(t,e,s=!1){if(!t||t&&t.constructor!==Object)return!1;for(let n in t)if(ne(t,n)&&ne(e,n)&&(!s||t[n]!==st))return!0;return!1}function Yt(t){let e=[];for(let s in t)ne(t,s)&&t[s]!==st&&e.push(s);return e}function te(t,e){e!==re&&t.push(e)}var ie=t=>oe("and",t);var U={compound(t,e,s){let n=(Array.isArray(e)?e:[e]).map(r=>s.parse(r));return new O(t.name,n)},field:(t,e,s)=>new j(t.name,s.field,e),document:(t,e)=>new M(t.name,e)},S=class{constructor(e,s=tt()){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:s.operatorToConditionName||Vt,defaultOperatorName:s.defaultOperatorName||"eq",mergeFinalConditions:s.mergeFinalConditions||ie},this.o=Object.keys(e).reduce((n,r)=>(n[r]=Object.assign({name:this.u.operatorToConditionName(r)},e[r]),n),{}),this.s=Object.assign({},s.fieldContext,{field:"",query:{},parse:this.parse,hasOperators:n=>Gt(n,this.o,s.useIgnoreValue)}),this.i=Object.assign({},s.documentContext,{parse:this.parse,query:{}}),this.h=s.useIgnoreValue?Yt:Object.keys}setParse(e){this.parse=e,this.s.parse=e,this.i.parse=e}parseField(e,s,n,r){let o=this.o[s];if(!o)throw new Error(`Unsupported operator "${s}"`);if(o.type!=="field")throw new Error(`Unexpected ${o.type} operator "${s}" at field level`);return this.s.field=e,this.s.query=r,this.parseInstruction(o,n,this.s)}parseInstruction(e,s,n){return typeof e.validate=="function"&&e.validate(e,s),(e.parse||U[e.type])(e,s,n)}parseFieldOperators(e,s){let n=[],r=this.h(s);for(let o=0,i=r.length;o<i;o++){let a=r[o];if(!this.o[a])throw new Error(`Field query for "${e}" may contain only operators or a plain object as a value`);te(n,this.parseField(e,a,s[a],s))}return n}parse(e){let s=[],n=this.h(e);this.i.query=e;for(let r=0,o=n.length;r<o;r++){let i=n[r],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`);te(s,this.parseInstruction(u,a,this.i))}else this.s.hasOperators(a)?s.push(...this.parseFieldOperators(i,a)):te(s,this.parseField(i,this.u.defaultOperatorName,a,e))}return this.u.mergeFinalConditions(s)}};function se(t,e){let s=t[e];if(typeof s!="function")throw new Error(`Unable to interpret "${e}" condition. Did you forget to register interpreter for it?`);return s}function Jt(t){return t.operator}function nt(t,e){let s=e,n=s&&s.getInterpreterName||Jt,r;switch(s?s.numberOfArguments:0){case 1:r=i=>{let a=n(i,s);return se(t,a)(i,o)};break;case 3:r=(i,a,u)=>{let f=n(i,s);return se(t,f)(i,a,u,o)};break;default:r=(i,a)=>{let u=n(i,s);return se(t,u)(i,a,o)}}let o=Object.assign({},s,{interpret:r});return o.interpret}function rt(t,e){return(s,...n)=>{let r=t(s,...n),o=e.bind(null,r);return o.ast=r,o}}var qs=S.prototype.parseInstruction;function ot(t,e){if(!Array.isArray(e))throw new Error(`"${t.name}" expects value to be an array`)}function it(t,e){if(ot(t,e),!e.length)throw new Error(`"${t.name}" expects to have at least one element in array`)}var ae=t=>(e,s)=>{if(typeof s!==t)throw new Error(`"${e.name}" expects value to be a "${t}"`)},at={type:"compound",validate:it,parse(t,e,{parse:s}){let n=e.map(r=>s(r));return oe(t.name,n)}},Zt=at,Ht={type:"compound",validate:it},Kt={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,s){let n=e instanceof RegExp?new j("regex",s.field,e):s.parse(e,s);return new O(t.name,[n])}},ce={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:s,field:n,hasOperators:r}){let o=r(e)?s(e,{field:b}):s(e);return new j(t.name,n,o)}},ue={type:"field",validate:ae("number")},C={type:"field",validate:ot},le=C,fe=C,Qt={type:"field",validate(t,e){if(!Array.isArray(e)||e.length!==2)throw new Error(`"${t.name}" expects an array with 2 numeric elements`)}},pe={type:"field",validate:ae("boolean")},q={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)`)}},_=q,de=_,he=_,z={type:"field"},me=z,ye={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,s){let n=typeof e=="string"?new RegExp(e,s.query.$options||""):e;return new j(t.name,s.field,n)}},be={type:"field",parse:()=>re},Wt={type:"document",validate:ae("function")},Xt=Object.freeze({__proto__:null,$and:at,$or:Zt,$nor:Ht,$not:Kt,$elemMatch:ce,$size:ue,$in:C,$nin:le,$all:fe,$mod:Qt,$exists:pe,$gte:q,$gt:_,$lt:de,$lte:he,$eq:z,$ne:me,$regex:ye,$options:be,$where:Wt}),L=class extends S{constructor(e){super(e,{defaultOperatorName:"$eq",operatorToConditionName:s=>s.slice(1)})}parse(e,s){return s&&s.field?ie(this.parseFieldOperators(s.field,e)):super.parse(e)}},B=Xt;function ge(t,e,s){for(let n=0,r=t.length;n<r;n++)if(s(t[n],e)===0)return!0;return!1}function xe(t,e){return Array.isArray(t)&&Number.isNaN(Number(e))}function ct(t,e,s){if(!xe(t,e))return s(t,e);let n=[];for(let r=0;r<t.length;r++){let o=s(t[r],e);o!==void 0&&(n=n.concat(o))}return n}function v(t){return(e,s,n)=>{let r=n.get(s,e.field);return Array.isArray(r)?r.some(o=>t(e,o,n)):t(e,r,n)}}var es=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty),ts=(t,e)=>t[e];function ut(t,e,s){let n=e.lastIndexOf(".");return n===-1?[t,e]:[s(t,e.slice(0,n)),e.slice(n+1)]}function ss(t,e,s=ts){if(e===b)return t;if(!t)throw new Error(`Unable to get field "${e}" out of ${String(t)}.`);return(function(n,r,o){if(r.indexOf(".")===-1)return ct(n,r,o);let i=r.split("."),a=n;for(let u=0,f=i.length;u<f;u++)if(a=ct(a,i[u],o),!a||typeof a!="object")return u<f-1?void 0:a;return a})(t,e,s)}function Oe(t,e){return t===e?0:t>e?1:-1}function je(t,e={}){return nt(t,Object.assign({get:ss,compare:Oe},e))}var lt=(t,e,{interpret:s})=>t.value.some(n=>s(n,e)),ns=(t,e,s)=>!lt(t,e,s),ve=(t,e,{interpret:s})=>t.value.every(n=>s(n,e)),rs=(t,e,{interpret:s})=>!s(t.value[0],e),V=(t,e,{compare:s,get:n})=>{let r=n(e,t.field);return Array.isArray(r)&&!Array.isArray(t.value)?ge(r,t.value,s):s(r,t.value)===0},$e=(t,e,s)=>!V(t,e,s),we=v((t,e,s)=>{let n=s.compare(e,t.value);return n===0||n===-1}),Ae=v((t,e,s)=>s.compare(e,t.value)===-1),Ee=v((t,e,s)=>s.compare(e,t.value)===1),Ie=v((t,e,s)=>{let n=s.compare(e,t.value);return n===0||n===1}),Ne=(t,e,{get:s})=>{if(t.field===b)return e!==void 0;let[n,r]=ut(e,t.field,s),o=i=>i==null?!!i===t.value:es(i,r)===t.value;return xe(n,r)?n.some(o):o(n)},os=v((t,e)=>typeof e=="number"&&e%t.value[0]===t.value[1]),Fe=(t,e,{get:s})=>{let[n,r]=ut(e,t.field,s),o=i=>{let a=s(i,r);return Array.isArray(a)&&a.length===t.value};return t.field!==b&&xe(n,r)?n.some(o):o(n)},Me=v((t,e)=>typeof e=="string"&&t.value.test(e)),R=v((t,e,{compare:s})=>ge(t.value,e,s)),Se=(t,e,s)=>!R(t,e,s),Ce=(t,e,{compare:s,get:n})=>{let r=n(e,t.field);return Array.isArray(r)&&t.value.every(o=>ge(r,o,s))},_e=(t,e,{interpret:s,get:n})=>{let r=n(e,t.field);return Array.isArray(r)&&r.some(o=>s(t.value,o))},is=(t,e)=>t.value.call(e),as=Object.freeze({__proto__:null,or:lt,nor:ns,and:ve,not:rs,eq:V,ne:$e,lte:we,lt:Ae,gt:Ee,gte:Ie,exists:Ne,mod:os,size:Fe,regex:Me,within:R,nin:Se,all:Ce,elemMatch:_e,where:is}),G=Object.assign({},as,{in:R}),Js=je(G);function ft(t){return t===null||typeof t!="object"?t:t instanceof Date?t.getTime():t&&typeof t.toJSON=="function"?t.toJSON():t}var cs=(t,e)=>Oe(ft(t),ft(e));function Y(t,e,s){let n=new L(t),r=je(e,Object.assign({compare:cs},s));if(s&&s.forPrimitives){let o={field:b},i=n.parse;n.setParse(a=>i(a,o))}return rt(n.parse,r)}var Ws=Y(B,G),Xs=Y(["$and","$or"].reduce((t,e)=>(t[e]=Object.assign({},t[e],{type:"field"}),t),Object.assign({},B,{$nor:Object.assign({},B.$nor,{type:"field",parse:U.compound})})),G,{forPrimitives:!0});var bt=Object.hasOwn||((t,e)=>Object.prototype.hasOwnProperty.call(t,e));function Re(t){return Array.isArray(t)?t:[t]}var I="__caslSubjectType__";function gt(t,e){if(e){if(!bt(e,I))Object.defineProperty(e,I,{value:t});else if(t!==e[I])throw new Error(`Trying to cast object to subject type ${t} but previously it was casted to ${e[I]}`)}return e}var Z=t=>{let e=typeof t;return e==="string"||e==="function"},xt=t=>t.modelName||t.name;function us(t){return typeof t=="string"?t:xt(t)}function Ot(t){return bt(t,I)?t[I]:xt(t.constructor)}var pt={function:t=>t.constructor,string:Ot};function dt(t,e,s){for(let n=s;n<e.length;n++)t.push(e[n])}function ht(t,e){if(!t||!t.length)return e||[];if(!e||!e.length)return t||[];let s=0,n=0,r=[];for(;s<t.length&&n<e.length;)t[s].priority<e[n].priority?(r.push(t[s]),s++):t[s].priority>e[n].priority?(r.push(e[n]),n++):(r.push(t[s]),s++,n++);return dt(r,t,s),dt(r,e,n),r}function J(t,e,s){let n=t.get(e);return n||(n=s(),t.set(e,n)),n}var ls=t=>t;function fs(t,e){let s;for(let n=0;n<t.length;n++){let r=e(t[n]);s&&r&&s.push(t[n]),r||(s??(s=t.slice(0,n)))}return s||t}function ps(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 Pe=class{constructor(e,s,n=0){ps(e,s),this.action=s.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?Re(e.fields):void 0,this.priority=n,this.t=s}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||Z(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 ds(t,e){let s={value:t,prev:e,next:null};return e&&(e.next=s),s}function hs(t){t.next&&(t.next.prev=t.prev),t.prev&&(t.prev.next=t.next),t.next=t.prev=null}var mt=()=>({rules:[],merged:!1}),yt=()=>new Map,Te=class{constructor(e=[],s={}){this.h=!1,this.l=new Map,this.p={conditionsMatcher:s.conditionsMatcher,fieldMatcher:s.fieldMatcher,resolveAction:s.resolveAction||ls},this.$=s.anyAction||"manage",this.A=s.anySubjectType||"all",this.m=e,this.M=!!s.detectSubjectType,this.j=s.detectSubjectType||Ot,this.v(e)}get rules(){return this.m}detectSubjectType(e){return Z(e)?e:e?this.j(e):this.A}update(e){let s={rules:e,ability:this,target:this};return this._("update",s),this.m=e,this.v(e),this._("updated",s),this}v(e){let s=new Map,n;for(let r=e.length-1;r>=0;r--){let o=e.length-r-1,i=new Pe(e[r],this.p,o),a=Re(i.action),u=Re(i.subject||this.A);!this.h&&i.fields&&(this.h=!0);for(let f=0;f<u.length;f++){let h=J(s,u[f],yt);n===void 0&&(n=typeof u[f]),typeof u[f]!==n&&n!=="mixed"&&(n="mixed");for(let A=0;A<a.length;A++)J(h,a[A],mt).rules.push(i)}}if(this.l=s,n!=="mixed"&&!this.M){let r=pt[n]||pt.string;this.j=r}}possibleRulesFor(e,s=this.A){if(!Z(s))throw new Error('"possibleRulesFor" accepts only subject types (i.e., string or class) as the 2nd parameter');let n=J(this.l,s,yt),r=J(n,e,mt);if(r.merged)return r.rules;let o=e!==this.$&&n.has(this.$)?n.get(this.$).rules:void 0,i=ht(r.rules,o);return s!==this.A&&(i=ht(i,this.possibleRulesFor(e,this.A))),r.rules=i,r.merged=!0,i}rulesFor(e,s,n){let r=this.possibleRulesFor(e,s);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?fs(r,o=>o.matchesField(n)):r}actionsFor(e){if(!Z(e))throw new Error('"actionsFor" accepts only subject types (i.e., string or class) as a parameter');let s=new Set,n=this.l.get(e);n&&Array.from(n.keys()).forEach(o=>s.add(o));let r=e!==this.A?this.l.get(this.A):void 0;return r&&Array.from(r.keys()).forEach(o=>s.add(o)),Array.from(s)}on(e,s){this.F=this.F||new Map;let n=this.F,r=n.get(e)||null,o=ds(s,r);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),hs(o)}}_(e,s){if(!this.F)return;let n=this.F.get(e)||null,r=[];for(;n!==null;)r.push(n.value),n=n.prev;for(let o=0;o<r.length;o++)r[o](s)}},ke=class extends Te{can(e,s,n){let r=this.relevantRuleFor(e,s,n);return!!r&&!r.inverted}relevantRuleFor(e,s,n){let r=this.detectSubjectType(s),o=this.rulesFor(e,r,n);for(let i=0,a=o.length;i<a;i++)if(o[i].matchesConditions(s))return o[i];return null}cannot(e,s,n){return!this.can(e,s,n)}},ms={$eq:z,$ne:me,$lt:de,$lte:he,$gt:_,$gte:q,$in:C,$nin:le,$all:fe,$size:ue,$regex:ye,$options:be,$elemMatch:ce,$exists:pe},ys={eq:V,ne:$e,lt:Ae,lte:we,gt:Ee,gte:Ie,in:R,nin:Se,all:Ce,size:Fe,regex:Me,elemMatch:_e,exists:Ne,and:ve};var bs=Y(ms,ys),gs=/[-/\\^$+?.()|[\]{}]/g,xs=/\.?\*+\.?/g,Os=/\*+/,js=/\./g;function vs(t,e,s){let n=s[0]==="*"||t[0]==="."&&t[t.length-1]==="."?"+":"*",r=t.indexOf("**")===-1?"[^.]":".",o=t.replace(js,"\\$&").replace(Os,r+n);return e+t.length===s.length?`(?:${o})?`:o}function $s(t,e,s){return t==="."&&(s[e-1]==="*"||s[e+1]==="*")?t:`\\${t}`}function ws(t){let e=t.map(n=>n.replace(gs,$s).replace(xs,vs)),s=e.length>1?`(?:${e.join("|")})`:e[0];return new RegExp(`^${s}$`)}var As=t=>{let e;return s=>(typeof e>"u"&&(e=t.every(n=>n.indexOf("*")===-1)?null:ws(t)),e===null?t.indexOf(s)!==-1:e.test(s))};function jt(t=[],e={}){return new ke(t,Object.assign({conditionsMatcher:bs,fieldMatcher:As},e))}var Es=t=>`Cannot execute "${t.action}" on "${t.subjectType}"`,vt=function(e){this.message=e};vt.prototype=Object.create(Error.prototype);var De=class extends vt{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,s,n){let r=this.unlessCan(e,s,n);if(r)throw r}unlessCan(e,s,n){let r=this.ability.relevantRuleFor(e,s,n);if(r&&!r.inverted)return;this.action=e,this.subject=s,this.subjectType=us(this.ability.detectSubjectType(s)),this.field=n;let o=r?r.reason:"";return this.message=this.message||o||this.constructor.P(this),this}};De.P=Es;var on=Object.freeze({__proto__:null});function Ue(t,e,s){if(t==null)return t;if(typeof t=="string"){if(t.indexOf("$principal.")!==0)return t;let r=t.slice(11).split(".").reduce((o,i)=>o==null?o:o[i],e);return r==null&&(s.unresolved=!0),r}if(Array.isArray(t))return t.map(n=>Ue(n,e,s));if(typeof t=="object"){let n={};for(let r of Object.keys(t))n[r]=Ue(t[r],e,s);return n}return t}function H(t,e){let s={unresolved:!1};return{conditions:Ue(t,e,s),unresolved:s.unresolved}}function $t(t,e){return H(t,e).conditions}function P(t,e){let s=k(t,e),n=[];for(let r of e.rules){if(s.indexOf(r.subject)===-1)continue;let o={action:r.actions,subject:r.resource};if(r.where){let{conditions:i,unresolved:a}=H(r.where,t);if(a)continue;o.conditions=i}n.push(o)}return n}function N(t){return jt(Array.isArray(t)?t:[])}function wt(t,e){return N(P(t,e))}function $(t,e,s,n){return n==null?t.can(e,s):t.can(e,gt(s,Object.assign({},n)))}var w={ALL:"all",NONE:"none",FIELDS:"fields",AMBIGUOUS:"ambiguous"},At={$in:"in",$nin:"nin",$ne:"ne",$gt:"gt",$gte:"gte",$lt:"lt",$lte:"lte"};function Is(t){let e=[];for(let s of Object.keys(t)){let n=t[s];if(n===null||typeof n!="object"||Array.isArray(n)){e.push({field:s,op:"eq",value:n});continue}let r=Object.keys(n);if(r.length!==1||!At[r[0]])return null;e.push({field:s,op:At[r[0]],value:n[r[0]]})}return e}var Ns=(t,e)=>t==="manage"||t===e||Array.isArray(t)&&(t.indexOf(e)!==-1||t.indexOf("manage")!==-1),Fs=(t,e)=>t==="all"||t===e;function Et(t,e,s,n){let r=P(t,e).filter(i=>Ns(i.action,s)&&Fs(i.subject,n));if(r.length===0)return{scope:w.NONE,clauses:[]};if(r.some(i=>!i.conditions))return{scope:w.ALL,clauses:[]};if(r.length>1)return{scope:w.AMBIGUOUS,clauses:[]};let o=Is(r[0].conditions);return o?{scope:w.FIELDS,clauses:o}:{scope:w.AMBIGUOUS,clauses:[]}}function It(t,e){let s=t;for(let n of e)n.op==="in"?s=s.hasSome(n.field,n.value):n.op==="nin"?s=s.not(s.hasSome(n.field,n.value)):s=s[n.op](n.field,n.value);return s}var Le=/export\s+const\s+([A-Za-z0-9_$]+)\s*=\s*webMethod\s*\(\s*Permissions\s*\.\s*([A-Za-z0-9_$]+)/g,Ms=[[/export\s*{\s*[A-Za-z0-9_$,\s]+}/,"export { x } \u2014 the call and the export must be one statement"],[/export\s+const\s+[A-Za-z0-9_$]+\s*=\s*webMethod\s*\(\s*Permissions\s*\[/,"Permissions['X'] \u2014 the property must be dotted and literal"],[/export\s+const\s+[A-Za-z0-9_$]+\s*=\s*webMethod\s*\(\s*[A-Za-z0-9_$]+\s*\(/,"a computed permission \u2014 it must be written out as Permissions.LEVEL"]];function qe(t){let e={},s=String(t||"");Le.lastIndex=0;let n=Le.exec(s);for(;n;)e[n[1]]=n[2],n=Le.exec(s);return e}function ze(t,e,s){let n=s||{},r=e&&e.api||{},o=qe(t),i=String(t||""),a=[],u=[];for(let p of Object.keys(o)){let c=r[p];c?c.permission!==o[p]&&a.push({name:p,declared:c.permission,written:o[p]}):u.push({name:p,gate:o[p]})}let f=n.complete?Object.keys(r).filter(p=>!(p in o)):[],h=[];for(let[p,c]of Ms)p.test(i)&&h.push(c);return{ok:a.length+u.length+f.length+h.length===0,found:o,mismatched:a,undeclared:u,missing:f,suspect:h}}function Nt(t,e,s){let n=ze(t,e,s);if(n.ok)return!0;let r=[];for(let o of n.mismatched)r.push(o.name+": policy says "+o.declared+", the export says "+o.written);for(let o of n.undeclared)r.push(o.name+": gated "+o.gate+" but missing from policy.api");for(let o of n.missing)r.push(o+": declared in policy.api but not exported here");for(let o of n.suspect)r.push("unreachable export shape \u2014 "+o);throw new Error(`wix-access: web-method gates do not match the policy:
2
+ `+r.join(`
3
+ `))}var Be="0.3.1";var Ve=[{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 Ft(t){return Ve.map(e=>({action:e.action,type:e.type,object:e.object,can:$(t,e.action,e.type,e.object)}))}var Ge=N([]),Mt="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. If it is imported and still not a function, build the kit inside onReady and pass an arrow: fetchRules: (...a) => getMyAbilities(...a).";function St(t){let e=t||{},s=e.fetchRules,n=e.onError||null,r=typeof s!="function",o=Ge,i=[],a=!1,u=!1,f=null,h=null;async function A(){if(r)return i=[],o=Ge,u=!0,f=Mt,a=!0,n&&n(new Error(Mt)),p;try{let c=await s();i=Array.isArray(c)?c:[],o=N(i),u=!1}catch(c){i=[],o=Ge,u=!0,f=String(c&&c.message||c),n&&n(c)}return a=!0,p}let p={ready(){return a?Promise.resolve(p):(h||(h=A().then(c=>(h=null,c))),h)},refresh(){return a=!1,u=!1,f=null,h=null,p.ready()},can:(c,d,g)=>$(o,c,d,g),cannot:(c,d,g)=>!$(o,c,d,g),rules:()=>i.slice(),get loaded(){return a},get failed(){return u},get reason(){return f},guard(c,d,g,T,K){let Ye=p.can(d,g,T);return p.apply(c,Ye,K),Ye},apply(c,d,g){if(!c)return d;let T=g||"hide";try{T==="disable"?d&&c.enable?c.enable():!d&&c.disable&&c.disable():T==="collapse"?d&&c.expand?c.expand():!d&&c.collapse&&c.collapse():d&&c.show?c.show():!d&&c.hide&&c.hide()}catch(K){n&&n(K)}return d}};return p}function Ss(){return{ok:!0,side:"public",version:Be}}async function Cs(){try{return(await Ct.currentMember.getRoles()).map(e=>e.title)}catch{return[]}}0&&(module.exports={CASES,CODES,KIND,PACKAGE_VERSION,PolicyError,SCOPE,WHEN,abilityFor,abilityFromRules,anonymous,applyClauses,assertGates,can,caseTable,createAccess,createPrincipal,deny,denyOpaque,filterFor,frontendRoleTitles,hasRole,isDenial,normaliseRoles,ok,parseGates,permissionFor,publicPing,resolvePlaceholders,resolveSubjects,resolveWhere,rulesFor,validatePolicy,verifyGates});
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