@adminiumjs/manifest 0.3.42 → 0.3.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/automations.js +1 -1
- package/dist/automations.js.map +1 -1
- package/dist/change-guards.js +1 -1
- package/dist/change-guards.js.map +1 -1
- package/dist/check.d.ts +81 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +130 -0
- package/dist/check.js.map +1 -0
- package/dist/expire.d.ts +46 -0
- package/dist/expire.d.ts.map +1 -0
- package/dist/expire.js +59 -0
- package/dist/expire.js.map +1 -0
- package/dist/formula.d.ts +6 -1
- package/dist/formula.d.ts.map +1 -1
- package/dist/formula.js +34 -6
- package/dist/formula.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/page-config.d.ts +10 -1
- package/dist/page-config.d.ts.map +1 -1
- package/dist/page-config.js +81 -1
- package/dist/page-config.js.map +1 -1
- package/dist/people.d.ts +55 -4
- package/dist/people.d.ts.map +1 -1
- package/dist/people.js +88 -8
- package/dist/people.js.map +1 -1
- package/dist/public-access.d.ts +24 -1
- package/dist/public-access.d.ts.map +1 -1
- package/dist/public-access.js +201 -8
- package/dist/public-access.js.map +1 -1
- package/dist/roles.d.ts +4 -0
- package/dist/roles.d.ts.map +1 -1
- package/dist/roles.js +5 -0
- package/dist/roles.js.map +1 -1
- package/dist/schema.d.ts +822 -5
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +456 -20
- package/dist/schema.js.map +1 -1
- package/dist/validate.js +1 -1
- package/dist/validate.js.map +1 -1
- package/dist/words.d.ts +3 -1
- package/dist/words.d.ts.map +1 -1
- package/dist/words.js +167 -0
- package/dist/words.js.map +1 -1
- package/package.json +2 -2
package/dist/public-access.d.ts
CHANGED
|
@@ -181,11 +181,15 @@ export declare const codeWhereSchema: z.ZodArray<z.ZodUnion<readonly [z.ZodObjec
|
|
|
181
181
|
* A value of the row that must agree with another: `column` (followed along
|
|
182
182
|
* `path` through foreign keys) equals, is at most, or is at least the target.
|
|
183
183
|
* `when` applies it only to rows whose value (along its own `path`) is one of
|
|
184
|
-
* `in`.
|
|
184
|
+
* `in`. `length: true` compares how many characters a text value has, with
|
|
185
|
+
* `lte` alone: a line's lettering no longer than its product allows
|
|
186
|
+
* (`{ "column": "lettering", "length": true, "lte": { "via": "product_id",
|
|
187
|
+
* "column": "lettering_limit" } }`), refused as `too-long`.
|
|
185
188
|
*/
|
|
186
189
|
export declare const agreeSchema: z.ZodObject<{
|
|
187
190
|
column: z.ZodString;
|
|
188
191
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
192
|
+
length: z.ZodOptional<z.ZodLiteral<true>>;
|
|
189
193
|
when: z.ZodOptional<z.ZodObject<{
|
|
190
194
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
191
195
|
in: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
@@ -253,6 +257,7 @@ export declare const childEntrySchema: z.ZodObject<{
|
|
|
253
257
|
agrees: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
254
258
|
column: z.ZodString;
|
|
255
259
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
260
|
+
length: z.ZodOptional<z.ZodLiteral<true>>;
|
|
256
261
|
when: z.ZodOptional<z.ZodObject<{
|
|
257
262
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
258
263
|
in: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
@@ -308,6 +313,7 @@ export declare const childEntrySchema: z.ZodObject<{
|
|
|
308
313
|
column: z.ZodString;
|
|
309
314
|
}, z.core.$strict>]>;
|
|
310
315
|
}, z.core.$strict>>;
|
|
316
|
+
uploads: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
311
317
|
}, z.core.$strict>>>;
|
|
312
318
|
via: z.ZodString;
|
|
313
319
|
writable: z.ZodArray<z.ZodString>;
|
|
@@ -321,6 +327,7 @@ export declare const childEntrySchema: z.ZodObject<{
|
|
|
321
327
|
agrees: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
322
328
|
column: z.ZodString;
|
|
323
329
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
330
|
+
length: z.ZodOptional<z.ZodLiteral<true>>;
|
|
324
331
|
when: z.ZodOptional<z.ZodObject<{
|
|
325
332
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
326
333
|
in: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
@@ -376,6 +383,7 @@ export declare const childEntrySchema: z.ZodObject<{
|
|
|
376
383
|
column: z.ZodString;
|
|
377
384
|
}, z.core.$strict>]>;
|
|
378
385
|
}, z.core.$strict>>;
|
|
386
|
+
uploads: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
379
387
|
}, z.core.$strict>;
|
|
380
388
|
export type ChildEntry = z.infer<typeof childEntrySchema>;
|
|
381
389
|
export declare const publicAccessSchema: z.ZodObject<{
|
|
@@ -388,6 +396,7 @@ export declare const publicAccessSchema: z.ZodObject<{
|
|
|
388
396
|
POST: "POST";
|
|
389
397
|
PATCH: "PATCH";
|
|
390
398
|
GET: "GET";
|
|
399
|
+
DELETE: "DELETE";
|
|
391
400
|
}>>;
|
|
392
401
|
select: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
393
402
|
writable: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -460,6 +469,7 @@ export declare const publicAccessSchema: z.ZodObject<{
|
|
|
460
469
|
text: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
461
470
|
}, z.core.$strict>;
|
|
462
471
|
}, z.core.$strict>>;
|
|
472
|
+
appColumn: z.ZodOptional<z.ZodString>;
|
|
463
473
|
newLink: z.ZodOptional<z.ZodObject<{
|
|
464
474
|
column: z.ZodString;
|
|
465
475
|
kind: z.ZodString;
|
|
@@ -481,6 +491,7 @@ export declare const publicAccessSchema: z.ZodObject<{
|
|
|
481
491
|
via: z.ZodString;
|
|
482
492
|
}, z.core.$strict>>;
|
|
483
493
|
files: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
494
|
+
uploads: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
484
495
|
documents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
485
496
|
sensitive: z.ZodOptional<z.ZodBoolean>;
|
|
486
497
|
reason: z.ZodOptional<z.ZodString>;
|
|
@@ -533,6 +544,7 @@ export declare const publicAccessSchema: z.ZodObject<{
|
|
|
533
544
|
agrees: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
534
545
|
column: z.ZodString;
|
|
535
546
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
547
|
+
length: z.ZodOptional<z.ZodLiteral<true>>;
|
|
536
548
|
when: z.ZodOptional<z.ZodObject<{
|
|
537
549
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
538
550
|
in: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
@@ -588,6 +600,7 @@ export declare const publicAccessSchema: z.ZodObject<{
|
|
|
588
600
|
column: z.ZodString;
|
|
589
601
|
}, z.core.$strict>]>;
|
|
590
602
|
}, z.core.$strict>>;
|
|
603
|
+
uploads: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
591
604
|
}, z.core.$strict>>>;
|
|
592
605
|
via: z.ZodString;
|
|
593
606
|
writable: z.ZodArray<z.ZodString>;
|
|
@@ -601,6 +614,7 @@ export declare const publicAccessSchema: z.ZodObject<{
|
|
|
601
614
|
agrees: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
602
615
|
column: z.ZodString;
|
|
603
616
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
617
|
+
length: z.ZodOptional<z.ZodLiteral<true>>;
|
|
604
618
|
when: z.ZodOptional<z.ZodObject<{
|
|
605
619
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
606
620
|
in: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
@@ -656,10 +670,12 @@ export declare const publicAccessSchema: z.ZodObject<{
|
|
|
656
670
|
column: z.ZodString;
|
|
657
671
|
}, z.core.$strict>]>;
|
|
658
672
|
}, z.core.$strict>>;
|
|
673
|
+
uploads: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
659
674
|
}, z.core.$strict>>>;
|
|
660
675
|
agrees: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
661
676
|
column: z.ZodString;
|
|
662
677
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
678
|
+
length: z.ZodOptional<z.ZodLiteral<true>>;
|
|
663
679
|
when: z.ZodOptional<z.ZodObject<{
|
|
664
680
|
path: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
665
681
|
in: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
@@ -812,6 +828,7 @@ export declare const publicAccessSchema: z.ZodObject<{
|
|
|
812
828
|
}, z.core.$strict>]>>>;
|
|
813
829
|
}, z.core.$strict>]>>;
|
|
814
830
|
pictures: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
831
|
+
assets: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
815
832
|
withhold: z.ZodOptional<z.ZodObject<{
|
|
816
833
|
columns: z.ZodArray<z.ZodString>;
|
|
817
834
|
unlessHolder: z.ZodOptional<z.ZodString>;
|
|
@@ -891,6 +908,12 @@ interface PublicAccessContext {
|
|
|
891
908
|
answersAvailability: (table: string) => boolean;
|
|
892
909
|
/** The add-ons whose stock words an entry may be answered by: the ones the manifest names, and itself when it is one. Absent: not checked. */
|
|
893
910
|
addOns?: ReadonlySet<string> | undefined;
|
|
911
|
+
/**
|
|
912
|
+
* The manifest is an add-on's: its entries with no key ride the `customer`
|
|
913
|
+
* key of each app it is attached to, whose own sign-in opens the sessions
|
|
914
|
+
* they are read with.
|
|
915
|
+
*/
|
|
916
|
+
ridesAppKeys?: boolean | undefined;
|
|
894
917
|
/** The table's limits, as it declares them (absent: the caller does not say). */
|
|
895
918
|
capacityOf?: (table: string) => Capacity | undefined;
|
|
896
919
|
publicKeys: Readonly<Record<string, PublicKey>> | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-access.d.ts","sourceRoot":"","sources":["../src/public-access.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE/D,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,WAAW,CAAC;AAKnB,mGAAmG;AACnG,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,wDAAwD;AACxD,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,UAAU,CAAC;AAEjC;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,yJAA0J,CAAC;AAEzL,mFAAmF;AACnF,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,iHAAiH;AACjH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AACxC,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC;;;GAGG;AACH,QAAA,MAAM,qBAAqB;;;;oBASzB,CAAC;AAGH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEvE,2CAA2C;AAC3C,eAAO,MAAM,YAAY,GAAI,OAAO,kBAAkB,KAAG,MAA4D,CAAC;AAEtH,4CAA4C;AAC5C,eAAO,MAAM,YAAY,GAAI,OAAO,kBAAkB,KAAG,MAAsF,CAAC;AAsEhJ,eAAO,MAAM,WAAW;;;;;;;;;;;;;;oBAAkE,CAAC;AAC3F,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAInE;AAED,4HAA4H;AAC5H,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,SAAS;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,CAAA;SAAE,EAAE,CAAA;KAAE,GAAG,SAAS,CAAC;CAC1F;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CAAE,EAAE,GAAG,UAAU,CAEjI;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,EAAE,CAW/G;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAC;IAAC,cAAc,EAAE;QAAE,MAAM,EAAE,SAAS;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,SAAS;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;aAAE,EAAE,CAAA;SAAE,EAAE,CAAA;KAAE,CAAA;CAAE,EACnM,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAWf;AA8BD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;KAAE,EAAE,CAAA;CAAE,EACtH,MAAM,EAAE,MAAM,GACb,QAAQ,GAAG,SAAS,GAAG,IAAI,CAiB7B;AA0CD;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;qBAQnB,CAAC;AAwBV
|
|
1
|
+
{"version":3,"file":"public-access.d.ts","sourceRoot":"","sources":["../src/public-access.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE/D,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,WAAW,CAAC;AAKnB,mGAAmG;AACnG,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,wDAAwD;AACxD,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,UAAU,CAAC;AAEjC;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,yJAA0J,CAAC;AAEzL,mFAAmF;AACnF,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,iHAAiH;AACjH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AACxC,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC;;;GAGG;AACH,QAAA,MAAM,qBAAqB;;;;oBASzB,CAAC;AAGH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEvE,2CAA2C;AAC3C,eAAO,MAAM,YAAY,GAAI,OAAO,kBAAkB,KAAG,MAA4D,CAAC;AAEtH,4CAA4C;AAC5C,eAAO,MAAM,YAAY,GAAI,OAAO,kBAAkB,KAAG,MAAsF,CAAC;AAsEhJ,eAAO,MAAM,WAAW;;;;;;;;;;;;;;oBAAkE,CAAC;AAC3F,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAInE;AAED,4HAA4H;AAC5H,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,SAAS;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,CAAA;SAAE,EAAE,CAAA;KAAE,GAAG,SAAS,CAAC;CAC1F;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CAAE,EAAE,GAAG,UAAU,CAEjI;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,EAAE,CAW/G;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAC;IAAC,cAAc,EAAE;QAAE,MAAM,EAAE,SAAS;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,SAAS;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;aAAE,EAAE,CAAA;SAAE,EAAE,CAAA;KAAE,CAAA;CAAE,EACnM,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAWf;AA8BD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;KAAE,EAAE,CAAA;CAAE,EACtH,MAAM,EAAE,MAAM,GACb,QAAQ,GAAG,SAAS,GAAG,IAAI,CAiB7B;AA0CD;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;qBAQnB,CAAC;AAwBV;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAUb,CAAC;AACZ,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD;;;;;;GAMG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;kBAOd,CAAC;AACZ,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAyClD,uFAAuF;AACvF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAA2G,CAAC;AACzI,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAiE1D,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqQpB,CAAC;AACZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;kBAkBjB,CAAC;AACZ,eAAO,MAAM,gBAAgB;;;;;;;;;;;;mBAOzB,CAAC;AACL,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,UAAU,mBAAmB;IAC3B,KAAK,EAAE,UAAU,CAAC;IAClB,sHAAsH;IACtH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,2EAA2E;IAC3E,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;IAChD,4GAA4G;IAC5G,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;IACjD,oFAAoF;IACpF,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3C,0FAA0F;IAC1F,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAChD,8IAA8I;IAC9I,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IACzC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,iFAAiF;IACjF,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAC;IACrD,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,GAAG,SAAS,CAAC;IAC5D,KAAK,EAAE,SAAS;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC/B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;QAC5C,+FAA+F;QAC/F,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;YAAE,IAAI,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,CAAC;KAC/E,EAAE,CAAC;IACJ,6EAA6E;IAC7E,MAAM,CAAC,EACH;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAAC,OAAO,EAAE;YAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,CAAA;KAAE,GACvP,SAAS,CAAC;CACf;AAED,qIAAqI;AACrI,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,aAAa,EAAE,CAezG;AAED,mHAAmH;AACnH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAA;KAAE,CAAC;IAChH,SAAS,CAAC,EACN,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,GAAG;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,GAAG,SAAS,CAAA;KAAE,EAAE,GACjO,SAAS,CAAC;CACf;AAED,wJAAwJ;AACxJ,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,SAAS,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAC;IACrG,+DAA+D;IAC/D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,qGAAqG;IACrG,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;CACxD;AAED,wGAAwG;AACxG,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,GAAG,SAAS,CAAC;AAElH;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,aAAa,GAAG,IAAI,CAsBjI;AAmFD,uGAAuG;AACvG,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,EAAE,GAAG,EAAE,mBAAmB,GAAG,cAAc,EAAE,CAumB/G;AAipCD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,SAAS,YAAY,EAAE,EACrC,MAAM,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,EAAE,CAAA;CAAE,EAAE,GACpH;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CA8BrC"}
|
package/dist/public-access.js
CHANGED
|
@@ -338,12 +338,16 @@ const agreeTargetSchema = z.union([
|
|
|
338
338
|
* A value of the row that must agree with another: `column` (followed along
|
|
339
339
|
* `path` through foreign keys) equals, is at most, or is at least the target.
|
|
340
340
|
* `when` applies it only to rows whose value (along its own `path`) is one of
|
|
341
|
-
* `in`.
|
|
341
|
+
* `in`. `length: true` compares how many characters a text value has, with
|
|
342
|
+
* `lte` alone: a line's lettering no longer than its product allows
|
|
343
|
+
* (`{ "column": "lettering", "length": true, "lte": { "via": "product_id",
|
|
344
|
+
* "column": "lettering_limit" } }`), refused as `too-long`.
|
|
342
345
|
*/
|
|
343
346
|
export const agreeSchema = z
|
|
344
347
|
.object({
|
|
345
348
|
column: refSchema,
|
|
346
349
|
path: pathSchema.optional(),
|
|
350
|
+
length: z.literal(true).optional(),
|
|
347
351
|
when: z.object({ path: pathSchema.optional(), in: z.array(scalarSchema).min(1).max(32) }).strict().optional(),
|
|
348
352
|
eq: agreeTargetSchema.optional(),
|
|
349
353
|
lte: agreeTargetSchema.optional(),
|
|
@@ -390,6 +394,8 @@ const childEntryShape = {
|
|
|
390
394
|
plainText: plainTextSchema.optional(),
|
|
391
395
|
/** The most a column may add up to across the rows of one write (a dozen items to an order). */
|
|
392
396
|
sumMax: sumMaxSchema.optional(),
|
|
397
|
+
/** File columns of the child a guest may upload into (`POST /public/uploads`), as on the entry itself. */
|
|
398
|
+
uploads: z.array(refSchema).min(1).max(8).optional(),
|
|
393
399
|
};
|
|
394
400
|
const childTablesSchema = (entry) => z.record(refSchema, entry).refine((children) => {
|
|
395
401
|
const count = Object.keys(children).length;
|
|
@@ -462,7 +468,8 @@ export const publicAccessSchema = z
|
|
|
462
468
|
.object({
|
|
463
469
|
table: refSchema,
|
|
464
470
|
kind: z.enum(['records', 'availability']).optional(),
|
|
465
|
-
|
|
471
|
+
/** `DELETE` only on an add-on's own link: its holder removes their own row while it is in a state the entry names. */
|
|
472
|
+
methods: z.array(z.enum(['GET', 'POST', 'PATCH', 'DELETE'])).min(1),
|
|
466
473
|
select: z.array(refSchema).optional(),
|
|
467
474
|
writable: z.array(refSchema).optional(),
|
|
468
475
|
filters: z.array(z.union([valueFilterSchema, relativeFilterSchema])).optional(),
|
|
@@ -494,6 +501,14 @@ export const publicAccessSchema = z
|
|
|
494
501
|
* unticked writes nothing: it takes back no earlier yes.
|
|
495
502
|
*/
|
|
496
503
|
consent: publicConsentSchema.optional(),
|
|
504
|
+
/**
|
|
505
|
+
* On an add-on's entry, which rides the key of every app it is attached
|
|
506
|
+
* to: a text column of the table that holds the key of the app a row is
|
|
507
|
+
* for (`app`). Through an app's key the entry reads only the rows whose
|
|
508
|
+
* column holds that app's key, a create writes that key there (the
|
|
509
|
+
* browser cannot choose it), and a change never moves it.
|
|
510
|
+
*/
|
|
511
|
+
appColumn: refSchema.optional(),
|
|
497
512
|
/** On a signed-in person's rows: "Make a new link" for a row's own link. */
|
|
498
513
|
newLink: newLinkSchema.optional(),
|
|
499
514
|
/**
|
|
@@ -504,6 +519,14 @@ export const publicAccessSchema = z
|
|
|
504
519
|
visibleWith: z.object({ table: refSchema, via: refSchema }).strict().optional(),
|
|
505
520
|
/** File columns a claimed person may download (the file the row names, never by its id). */
|
|
506
521
|
files: z.array(refSchema).min(1).max(8).optional(),
|
|
522
|
+
/**
|
|
523
|
+
* File columns a guest may upload into (`POST /public/uploads`): each a
|
|
524
|
+
* `writable` file column whose rule says what a guest may send
|
|
525
|
+
* (`rules.file.upload`). The upload is kept for a day; the guest's next
|
|
526
|
+
* create or change through this entry names it in the column, and it
|
|
527
|
+
* becomes the row's own file.
|
|
528
|
+
*/
|
|
529
|
+
uploads: z.array(refSchema).min(1).max(8).optional(),
|
|
507
530
|
/** The kinds of document a claimed person may list and open for these rows. */
|
|
508
531
|
documents: z.array(z.string().regex(/^[a-z][a-z0-9-]*$/, 'a document kind')).min(1).max(8).optional(),
|
|
509
532
|
/**
|
|
@@ -685,6 +708,13 @@ export const publicAccessSchema = z
|
|
|
685
708
|
.optional(),
|
|
686
709
|
/** Image columns any visitor may see, through the rows this entry reads. */
|
|
687
710
|
pictures: z.array(refSchema).min(1).max(4).optional(),
|
|
711
|
+
/**
|
|
712
|
+
* File columns of product assets every visitor's browser may load,
|
|
713
|
+
* through the rows this entry reads (`GET /public/assets`): a preview
|
|
714
|
+
* model (GLB), a print model (STL, 3MF), a web font (WOFF2), an SVG piece.
|
|
715
|
+
* Each column holds files by a `file` rule that takes only those kinds.
|
|
716
|
+
*/
|
|
717
|
+
assets: z.array(refSchema).min(1).max(8).optional(),
|
|
688
718
|
/**
|
|
689
719
|
* On rows reached through a parent: `columns` are left out unless
|
|
690
720
|
* `unlessHolder` is empty or names the session's own person (a ticket
|
|
@@ -851,11 +881,40 @@ function formsEntryIssues(entry, i, entries, appKey, index) {
|
|
|
851
881
|
}
|
|
852
882
|
return out;
|
|
853
883
|
}
|
|
884
|
+
/**
|
|
885
|
+
* An entry held to the app whose key serves it (`appColumn`): a text column
|
|
886
|
+
* of its table, never one a browser writes or a value the entry sets, and
|
|
887
|
+
* only on an entry that rides each app's own key (no key of the add-on's,
|
|
888
|
+
* no sign-in of its own).
|
|
889
|
+
*/
|
|
890
|
+
function appColumnIssues(entries, index) {
|
|
891
|
+
const out = [];
|
|
892
|
+
entries.forEach((entry, i) => {
|
|
893
|
+
const column = entry.appColumn;
|
|
894
|
+
if (column === undefined)
|
|
895
|
+
return;
|
|
896
|
+
const at = ['publicAccess', i, 'appColumn'];
|
|
897
|
+
const found = index.column(entry.table, column);
|
|
898
|
+
if (found === undefined)
|
|
899
|
+
out.push({ path: at, message: `"${entry.table}" has no column "${column}"` });
|
|
900
|
+
else if (found.type !== 'text')
|
|
901
|
+
out.push({ path: at, message: `"${entry.table}.${column}" is not a text column, so it cannot hold an app's key` });
|
|
902
|
+
if ((entry.writable ?? []).includes(column) || Object.prototype.hasOwnProperty.call(entry.defaults ?? {}, column)) {
|
|
903
|
+
out.push({ path: at, message: `"${column}" holds the app whose key serves the entry: Adminium writes it, so it is neither writable nor a default` });
|
|
904
|
+
}
|
|
905
|
+
if ((entry.key ?? CUSTOMER_KEY) !== CUSTOMER_KEY)
|
|
906
|
+
out.push({ path: at, message: `an entry on "${String(entry.key)}" is served by no app's key, so it has no app to be held to` });
|
|
907
|
+
if (entry.claim !== undefined || entry.identity !== undefined)
|
|
908
|
+
out.push({ path: at, message: 'a sign-in entry is the key\'s own, and is held to no app' });
|
|
909
|
+
});
|
|
910
|
+
return out;
|
|
911
|
+
}
|
|
854
912
|
/** Everything in `publicAccess` and `publicKeys` that names something undeclared, or breaks a rule. */
|
|
855
913
|
export function publicAccessIssues(entries, ctx) {
|
|
856
914
|
const out = [];
|
|
857
915
|
const { index } = ctx;
|
|
858
916
|
const has = index.has;
|
|
917
|
+
out.push(...appColumnIssues(entries, index));
|
|
859
918
|
for (const [name, key] of Object.entries(ctx.publicKeys ?? {})) {
|
|
860
919
|
const at = ['publicKeys', name];
|
|
861
920
|
// The app's own key, named only for its peak: nothing more to check.
|
|
@@ -1030,14 +1089,25 @@ export function publicAccessIssues(entries, ctx) {
|
|
|
1030
1089
|
if (patches && entry.claim === undefined && entry.visibleWith === undefined && (entry.claimedBy === undefined || entry.claimedBy.optional === true)) {
|
|
1031
1090
|
out.push({ path: at('methods'), message: 'PATCH is allowed only with a claim' });
|
|
1032
1091
|
}
|
|
1092
|
+
/*
|
|
1093
|
+
* A removal from a browser: only through an add-on's own link (a shopper
|
|
1094
|
+
* deleting their own saved draft), on the entry that opens the row by it.
|
|
1095
|
+
* Nothing else a guest holds removes a row.
|
|
1096
|
+
*/
|
|
1097
|
+
if (entry.methods.includes('DELETE')) {
|
|
1098
|
+
const ownLink = ctx.ridesAppKeys === true && entry.key !== undefined && entry.claim !== undefined && 'by' in entry.claim && entry.claim.own === true;
|
|
1099
|
+
if (!ownLink)
|
|
1100
|
+
out.push({ path: at('methods'), message: "DELETE is allowed only on an add-on's own link, the entry that opens the row by it (claim by token, own)" });
|
|
1101
|
+
}
|
|
1033
1102
|
// Nothing a server decides may be written by a browser.
|
|
1034
1103
|
const decided = ctx.decided(entry.table);
|
|
1035
1104
|
for (const ref of writable) {
|
|
1036
1105
|
if (decided.has(ref))
|
|
1037
1106
|
out.push({ path: at('writable'), message: `"${ref}" is decided by Adminium and cannot be written publicly` });
|
|
1038
1107
|
}
|
|
1039
|
-
// A file column names a file a signed-in staff member uploaded: a browser's key uploads nothing, so it names none
|
|
1040
|
-
|
|
1108
|
+
// A file column names a file a signed-in staff member uploaded: a browser's key uploads nothing, so it names none —
|
|
1109
|
+
// but a guest's own upload, in a column the entry lets them upload into (`uploads`).
|
|
1110
|
+
for (const [list, refs] of [['writable', [...writable].filter((ref) => !(entry.uploads ?? []).includes(ref))], ['defaults', Object.keys(entry.defaults ?? {})]]) {
|
|
1041
1111
|
for (const ref of refs) {
|
|
1042
1112
|
const found = ctx.index.column(entry.table, ref);
|
|
1043
1113
|
if (found?.rules?.file !== undefined)
|
|
@@ -1220,7 +1290,8 @@ export function publicAccessIssues(entries, ctx) {
|
|
|
1220
1290
|
out.push({ path: at('visibleWith'), message: 'the entries it is visible with lead to no claimed person' });
|
|
1221
1291
|
}
|
|
1222
1292
|
for (const ref of entry.files ?? []) {
|
|
1223
|
-
|
|
1293
|
+
// A guest's own upload is written by naming it, and only a file they uploaded for the column is taken there.
|
|
1294
|
+
if (writable.has(ref) && !(entry.uploads ?? []).includes(ref))
|
|
1224
1295
|
out.push({ path: at('files'), message: `"${ref}" is offered for download, so a browser never writes it` });
|
|
1225
1296
|
const found = column(ref);
|
|
1226
1297
|
if (found === undefined)
|
|
@@ -1325,7 +1396,7 @@ export function publicAccessIssues(entries, ctx) {
|
|
|
1325
1396
|
!('within' in when) &&
|
|
1326
1397
|
[when.after, when.before].some((end) => end !== undefined) &&
|
|
1327
1398
|
[when.after, when.before].every((end) => end === undefined || end.column !== undefined));
|
|
1328
|
-
if (entry.writableWhen !== undefined && !patches && !createWindow) {
|
|
1399
|
+
if (entry.writableWhen !== undefined && !patches && !entry.methods.includes('DELETE') && !createWindow) {
|
|
1329
1400
|
out.push({ path: at('writableWhen'), message: "writableWhen limits a change, and this entry changes nothing (a child's create takes a window read from its parent, keyed by the link)" });
|
|
1330
1401
|
}
|
|
1331
1402
|
for (const [ref, when] of Object.entries(entry.writableWhen ?? {})) {
|
|
@@ -1505,6 +1576,13 @@ export function publicAccessIssues(entries, ctx) {
|
|
|
1505
1576
|
out.push(...unlockIssues(entry, entry.unlockBy, entries, ctx, at));
|
|
1506
1577
|
if (entry.pictures !== undefined)
|
|
1507
1578
|
out.push(...pictureIssues(entry, entry.pictures, entries, ctx, at));
|
|
1579
|
+
if (entry.uploads !== undefined) {
|
|
1580
|
+
if (!entry.methods.includes('POST') && !entry.methods.includes('PATCH'))
|
|
1581
|
+
out.push({ path: at('uploads'), message: "a guest's upload is named by a create or a change, and this entry makes neither" });
|
|
1582
|
+
out.push(...uploadIssues(ctx.index, entry.table, entry.uploads, entry.writable ?? [], at('uploads')));
|
|
1583
|
+
}
|
|
1584
|
+
if (entry.assets !== undefined)
|
|
1585
|
+
out.push(...assetIssues(entry, entry.assets, entries, ctx, at));
|
|
1508
1586
|
});
|
|
1509
1587
|
out.push(...treeIssues(entries, ctx, identities, shareCodes));
|
|
1510
1588
|
out.push(...personIssues(entries, ctx, identities));
|
|
@@ -1686,6 +1764,105 @@ function pictureIssues(entry, pictures, entries, ctx, at) {
|
|
|
1686
1764
|
}
|
|
1687
1765
|
return out;
|
|
1688
1766
|
}
|
|
1767
|
+
/** The kinds of file a product asset may be (`ASSET_FILE_KINDS` in `schema.ts`, which imports this file). */
|
|
1768
|
+
const ASSET_KINDS = ['svg', 'glb', 'stl', '3mf', 'woff2'];
|
|
1769
|
+
/**
|
|
1770
|
+
* Product assets every visitor's browser loads: file columns the entry shows,
|
|
1771
|
+
* held to a model's, a font's or an SVG's kinds, which no browser writes. The
|
|
1772
|
+
* same shape as pictures: a viewer `fetch`es a model and `@font-face` loads a
|
|
1773
|
+
* font with no session, so the rows are read by every visitor alike.
|
|
1774
|
+
*/
|
|
1775
|
+
function assetIssues(entry, assets, entries, ctx, at) {
|
|
1776
|
+
const out = [];
|
|
1777
|
+
if (entry.methods.length !== 1 || entry.methods[0] !== 'GET' || entry.kind === 'availability') {
|
|
1778
|
+
out.push({ path: at('assets'), message: 'assets are served through an entry that only reads rows' });
|
|
1779
|
+
}
|
|
1780
|
+
if (entry.claim !== undefined || entry.claimedBy !== undefined || entry.visibleWith !== undefined) {
|
|
1781
|
+
out.push({ path: at('assets'), message: "assets are for every visitor; a signed-in person's own files are `files`" });
|
|
1782
|
+
}
|
|
1783
|
+
if (entry.unlockBy !== undefined)
|
|
1784
|
+
out.push({ path: at('assets'), message: 'assets are for every visitor; rows a code unlocks are read only by whoever gave the code' });
|
|
1785
|
+
if (entry.level !== undefined && entry.claim === undefined && entry.claimedBy === undefined && entry.visibleWith === undefined) {
|
|
1786
|
+
out.push({ path: at('assets'), message: 'assets are for every visitor; rows read by a signed-in session alone are no asset a page loads for anyone' });
|
|
1787
|
+
}
|
|
1788
|
+
if ((entry.key ?? CUSTOMER_KEY) !== CUSTOMER_KEY)
|
|
1789
|
+
out.push({ path: at('key'), message: "assets are served through the app's customer key" });
|
|
1790
|
+
const writes = new Set([...(entry.writable ?? []), ...Object.keys(entry.defaults ?? {})]);
|
|
1791
|
+
const shareCodes = shareCodeColumns(entries, entry.table, ctx.index);
|
|
1792
|
+
const guests = guestUploadColumns(entries, entry.table);
|
|
1793
|
+
if (new Set(assets).size !== assets.length)
|
|
1794
|
+
out.push({ path: at('assets'), message: 'an asset column is named twice' });
|
|
1795
|
+
for (const ref of assets) {
|
|
1796
|
+
const found = ctx.index.column(entry.table, ref);
|
|
1797
|
+
if (found === undefined) {
|
|
1798
|
+
out.push({ path: at('assets'), message: `"${entry.table}" has no column "${ref}"` });
|
|
1799
|
+
continue;
|
|
1800
|
+
}
|
|
1801
|
+
const accept = found.rules?.file?.accept;
|
|
1802
|
+
if (accept === undefined || accept.length === 0 || accept.some((kind) => !ASSET_KINDS.includes(kind))) {
|
|
1803
|
+
out.push({ path: at('assets'), message: `"${entry.table}.${ref}" is not a column of assets: a file rule that takes only ${ASSET_KINDS.join(', ')}` });
|
|
1804
|
+
}
|
|
1805
|
+
if (writes.has(ref))
|
|
1806
|
+
out.push({ path: at('assets'), message: `"${ref}" is an asset every visitor loads, so a browser never writes it` });
|
|
1807
|
+
if (entry.select !== undefined && !entry.select.includes(ref))
|
|
1808
|
+
out.push({ path: at('assets'), message: `"${ref}" is not one of the columns the entry shows` });
|
|
1809
|
+
if ((entry.files ?? []).includes(ref))
|
|
1810
|
+
out.push({ path: at('assets'), message: `"${ref}" is a signed-in person's file, not an asset for everyone` });
|
|
1811
|
+
if ((entry.pictures ?? []).includes(ref))
|
|
1812
|
+
out.push({ path: at('assets'), message: `"${ref}" is a picture already; a column is one or the other` });
|
|
1813
|
+
if (found.rules?.secret === true || found.rules?.code !== undefined || shareCodes.includes(ref)) {
|
|
1814
|
+
out.push({ path: at('assets'), message: `"${entry.table}.${ref}" is kept from readers, so it is no asset for everyone` });
|
|
1815
|
+
}
|
|
1816
|
+
if (found.rules?.personal === true)
|
|
1817
|
+
out.push({ path: at('assets'), message: `"${entry.table}.${ref}" is personal data, so it is no asset for everyone` });
|
|
1818
|
+
if (guests.has(ref))
|
|
1819
|
+
out.push({ path: at('assets'), message: `guests upload into "${entry.table}.${ref}", and a guest's file is kept private, so it is no asset for everyone` });
|
|
1820
|
+
}
|
|
1821
|
+
return out;
|
|
1822
|
+
}
|
|
1823
|
+
/** The columns of `table` any entry lets a guest upload into, on the entry itself or on a level of its child rows. */
|
|
1824
|
+
function guestUploadColumns(entries, table) {
|
|
1825
|
+
const out = new Set();
|
|
1826
|
+
const walk = (children) => {
|
|
1827
|
+
for (const [name, child] of Object.entries(children ?? {})) {
|
|
1828
|
+
if (name === table)
|
|
1829
|
+
for (const ref of child.uploads ?? [])
|
|
1830
|
+
out.add(ref);
|
|
1831
|
+
walk(child.children);
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
for (const entry of entries) {
|
|
1835
|
+
if (entry.table === table)
|
|
1836
|
+
for (const ref of entry.uploads ?? [])
|
|
1837
|
+
out.add(ref);
|
|
1838
|
+
walk(entry.children);
|
|
1839
|
+
}
|
|
1840
|
+
return out;
|
|
1841
|
+
}
|
|
1842
|
+
/**
|
|
1843
|
+
* The file columns a guest may upload into, at one level of an entry: each a
|
|
1844
|
+
* column of the table, written there, whose file rule says what a guest may
|
|
1845
|
+
* send (`rules.file.upload`). Named once each.
|
|
1846
|
+
*/
|
|
1847
|
+
function uploadIssues(index, table, uploads, writable, path) {
|
|
1848
|
+
const out = [];
|
|
1849
|
+
if (new Set(uploads).size !== uploads.length)
|
|
1850
|
+
out.push({ path, message: 'each column is named once' });
|
|
1851
|
+
for (const ref of uploads) {
|
|
1852
|
+
const found = ruledColumn(index, table, ref);
|
|
1853
|
+
if (found === undefined) {
|
|
1854
|
+
out.push({ path, message: `"${table}" has no column "${ref}"` });
|
|
1855
|
+
continue;
|
|
1856
|
+
}
|
|
1857
|
+
if (found.rules?.file === undefined)
|
|
1858
|
+
out.push({ path, message: `"${table}.${ref}" holds no files: give it a file rule (rules.file)` });
|
|
1859
|
+
else if (found.rules.file.upload === undefined)
|
|
1860
|
+
out.push({ path, message: `"${table}.${ref}" does not say what a guest may upload: give its file rule an upload (kinds, maxBytes)` });
|
|
1861
|
+
if (!writable.includes(ref))
|
|
1862
|
+
out.push({ path, message: `"${ref}" is filled by naming the upload, so it is writable` });
|
|
1863
|
+
}
|
|
1864
|
+
return out;
|
|
1865
|
+
}
|
|
1689
1866
|
/**
|
|
1690
1867
|
* Whether an entry reads a table's rows: a GET that is not an availability
|
|
1691
1868
|
* answer (free or full per slot, never a row), so it can be a child's parent.
|
|
@@ -1850,9 +2027,21 @@ function agreeIssues(index, table, parent, agree, at) {
|
|
|
1850
2027
|
out.push({ path: at(test, 'column'), message: `"${via.references}" has no column "${target.column}"` });
|
|
1851
2028
|
}
|
|
1852
2029
|
}
|
|
1853
|
-
else if (typeof reached !== 'string' && !agreeValueFits(reached.column, target.value)) {
|
|
2030
|
+
else if (agree.length !== true && typeof reached !== 'string' && !agreeValueFits(reached.column, target.value)) {
|
|
1854
2031
|
out.push({ path: at(test, 'value'), message: `${JSON.stringify(target.value)} is not a value of "${reached.table}.${reached.column.ref}"` });
|
|
1855
2032
|
}
|
|
2033
|
+
if (agree.length === true) {
|
|
2034
|
+
// How many characters a text has, at most a number: the text is the row's, the most is a number.
|
|
2035
|
+
if (test !== 'lte')
|
|
2036
|
+
out.push({ path: at(test), message: 'a length is compared with lte (at most so many characters)' });
|
|
2037
|
+
if (typeof reached !== 'string' && reached.column.type !== 'text')
|
|
2038
|
+
out.push({ path: at('length'), message: `"${reached.table}.${reached.column.ref}" is not text, so it has no length` });
|
|
2039
|
+
if (other !== undefined && !NUMBERS.includes(other.type))
|
|
2040
|
+
out.push({ path: at(test), message: `"${other.ref}" is not a number, so it is no most characters` });
|
|
2041
|
+
if ('value' in target && (typeof target.value !== 'number' || !Number.isInteger(target.value) || target.value < 0))
|
|
2042
|
+
out.push({ path: at(test, 'value'), message: 'the most characters is a whole number' });
|
|
2043
|
+
return out;
|
|
2044
|
+
}
|
|
1856
2045
|
if (typeof reached !== 'string') {
|
|
1857
2046
|
if (test !== 'eq' && !NUMBERS.includes(reached.column.type)) {
|
|
1858
2047
|
out.push({ path: at(test), message: `"${reached.table}.${reached.column.ref}" is not a number, so it is not at most or at least another` });
|
|
@@ -2093,6 +2282,8 @@ function treeIssues(entries, ctx, identities, shareCodes) {
|
|
|
2093
2282
|
}
|
|
2094
2283
|
}
|
|
2095
2284
|
out.push(...boundIssues(index, ctx, name, child.writable, here('writable')));
|
|
2285
|
+
if (child.uploads !== undefined)
|
|
2286
|
+
out.push(...uploadIssues(index, name, child.uploads, child.writable, here('uploads')));
|
|
2096
2287
|
(child.agrees ?? []).forEach((agree, a) => out.push(...agreeIssues(index, name, parent, agree, (...rest) => here('agrees', a, ...rest))));
|
|
2097
2288
|
(child.counts ?? []).forEach((counts, c) => out.push(...countsIssues(index, name, parent, counts, (...rest) => here('counts', c, ...rest))));
|
|
2098
2289
|
if (child.children !== undefined) {
|
|
@@ -2429,7 +2620,9 @@ function personIssues(entries, ctx, identities) {
|
|
|
2429
2620
|
if (entry.level !== undefined && entry.claim === undefined && entry.claimedBy === undefined && entry.visibleWith === undefined) {
|
|
2430
2621
|
if (entry.methods.length !== 1 || entry.methods[0] !== 'GET')
|
|
2431
2622
|
out.push({ path: at('methods'), message: 'a read for a signed-in guest alone only reads' });
|
|
2432
|
-
|
|
2623
|
+
// An add-on's entry on an app's key is read with a session the app's own sign-in opened (a guest who found their order).
|
|
2624
|
+
const appSignsIn = ctx.ridesAppKeys === true && key === CUSTOMER_KEY;
|
|
2625
|
+
if (!identities.has(key) && !appSignsIn)
|
|
2433
2626
|
out.push({ path: at('level'), message: `the "${key}" key signs nobody in, so no session could read this` });
|
|
2434
2627
|
if (entry.select === undefined)
|
|
2435
2628
|
out.push({ path: at('select'), message: 'a read for a signed-in guest lists what it shows; without select it would show every column' });
|