@wix/himalaya-cli 0.1430.0 → 0.1431.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/data-resources/src/base44/ownership.d.ts +38 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/data-resources/src/base44/schema.d.ts +65 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/data-resources/src/schema.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/base44-entities.d.ts +8 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +12 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +209 -26
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/data-resources.mjs +184 -1
- package/dist/cli.mjs +1245 -620
- package/guides/base44-app-to-himi-app.md +19 -1
- package/guides/base44-entities.md +150 -0
- package/guides/himi-json-output.md +30 -0
- package/guides/index.json +6 -0
- package/package.json +2 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ownership and validation for an app's declared Base44 entities and functions — the Base44
|
|
3
|
+
* sibling of `../ownership.ts` (#4557).
|
|
4
|
+
*
|
|
5
|
+
* An entity is OWNED (declared by `name`, physically `Himi<AppPascal><name>`, himi's to create
|
|
6
|
+
* and seed) or ADOPTED (declared by `base44Name`, the Base44 app's own entity, read-only to
|
|
7
|
+
* himi). The CMS `himi_<app>_` prefix cannot work here: Base44 entity names are alphanumeric
|
|
8
|
+
* only, so the namespace is a PascalCase prefix instead.
|
|
9
|
+
*/
|
|
10
|
+
import { BASE44_BUILTIN_FIELDS, BASE44_FIELD_TYPES, BASE44_STRING_FORMATS, type Base44EntitiesConfig, type Base44EntitySpec, type Base44FunctionSpec } from "./schema.js";
|
|
11
|
+
export { BASE44_BUILTIN_FIELDS, BASE44_FIELD_TYPES, BASE44_STRING_FORMATS };
|
|
12
|
+
export type { Base44EntitiesConfig, Base44EntitySpec, Base44FieldSpec, Base44FieldType, Base44FunctionSpec, Base44StringFormat, } from "./schema.js";
|
|
13
|
+
/** The stable machine codes `validateBase44Entities` emits. Never rename one: callers branch on it. */
|
|
14
|
+
export type Base44RuleCode = "shape-invalid" | "entity-name-invalid" | "entity-owned-and-adopted" | "entity-neither-owned-nor-adopted" | "entity-duplicate" | "field-builtin" | "field-duplicate" | "field-type-unsupported" | "field-format-invalid" | "display-field-unknown" | "required-unknown" | "seed-on-adopted" | "seed-key-unknown" | "function-name-invalid" | "function-owned-and-adopted" | "function-neither-owned-nor-adopted" | "function-duplicate" | "adopted-in-owned-namespace" | "read-rule-user-scoped";
|
|
15
|
+
export interface Base44Issue {
|
|
16
|
+
severity: "error" | "warning";
|
|
17
|
+
message: string;
|
|
18
|
+
ruleCode: Base44RuleCode;
|
|
19
|
+
/** The entity (or function) the issue is about, as declared. Absent for block-level issues. */
|
|
20
|
+
entity?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `Himi` + the app slug in PascalCase: each `[A-Za-z0-9]+` run gets an upper-case first letter
|
|
24
|
+
* (`video-courses` → `HimiVideoCourses`, `com.acme.todo` → `HimiComAcmeTodo`). Everything else
|
|
25
|
+
* is dropped, so the prefix is always alphanumeric.
|
|
26
|
+
*/
|
|
27
|
+
export declare function base44Prefix(app: string): string;
|
|
28
|
+
export declare function isAdoptedEntity(spec: Base44EntitySpec): boolean;
|
|
29
|
+
export declare function isOwnedEntity(spec: Base44EntitySpec): boolean;
|
|
30
|
+
/** The entity name the Base44 app actually stores: `base44Name` verbatim, or the prefixed owned name. */
|
|
31
|
+
export declare function physicalEntityName(spec: Base44EntitySpec, app: string): string;
|
|
32
|
+
export declare function isOwnedFunction(spec: Base44FunctionSpec): boolean;
|
|
33
|
+
export declare function physicalFunctionName(spec: Base44FunctionSpec): string;
|
|
34
|
+
/**
|
|
35
|
+
* Lint a `base44` block. Non-throwing: every finding is returned, each with a stable `ruleCode`.
|
|
36
|
+
* `defineApp` throws on the first `error`; `himi validate` reports them all.
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateBase44Entities(cfg: Base44EntitiesConfig | undefined, app: string): Base44Issue[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarations for the Base44 entities and backend functions an app depends on — the Base44
|
|
3
|
+
* sibling of the CMS block in `../schema.ts` (#4557).
|
|
4
|
+
*
|
|
5
|
+
* A sibling, not a union: Base44 entities are JSON Schema objects (`string`/`number`/… with a
|
|
6
|
+
* `format`), their access rules are verbatim Base44 RLS documents, and names are alphanumeric
|
|
7
|
+
* only. Folding them into `cms` would make every CMS check branch on the backend.
|
|
8
|
+
*/
|
|
9
|
+
export declare const BASE44_FIELD_TYPES: readonly ["string", "number", "integer", "boolean", "array", "object"];
|
|
10
|
+
export type Base44FieldType = (typeof BASE44_FIELD_TYPES)[number];
|
|
11
|
+
export declare const BASE44_STRING_FORMATS: readonly ["date", "date-time", "time", "email", "uri", "uuid", "file", "richtext"];
|
|
12
|
+
export type Base44StringFormat = (typeof BASE44_STRING_FORMATS)[number];
|
|
13
|
+
/** Fields Base44 adds to every row. Declaring one is refused: the platform owns them. */
|
|
14
|
+
export declare const BASE44_BUILTIN_FIELDS: readonly ["id", "created_date", "updated_date", "created_by", "created_by_id"];
|
|
15
|
+
export interface Base44FieldSpec {
|
|
16
|
+
/** The JSON Schema property name. */
|
|
17
|
+
key: string;
|
|
18
|
+
type: Base44FieldType;
|
|
19
|
+
/** Strings only. */
|
|
20
|
+
format?: Base44StringFormat;
|
|
21
|
+
enum?: (string | number)[];
|
|
22
|
+
default?: unknown;
|
|
23
|
+
/** Arrays only. */
|
|
24
|
+
items?: {
|
|
25
|
+
type: Base44FieldType;
|
|
26
|
+
};
|
|
27
|
+
description?: string;
|
|
28
|
+
/** Field-level security, the verbatim Base44 rule. */
|
|
29
|
+
rls?: {
|
|
30
|
+
read?: unknown;
|
|
31
|
+
write?: unknown;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface Base44EntitySpec {
|
|
35
|
+
/** OWNED: a logical PascalCase name. The physical entity is `Himi<AppPascal><name>`. */
|
|
36
|
+
name?: string;
|
|
37
|
+
/** ADOPTED: the Base44 app's own entity, verbatim. Read-only to himi. */
|
|
38
|
+
base44Name?: string;
|
|
39
|
+
title?: string;
|
|
40
|
+
displayField?: string;
|
|
41
|
+
fields: Base44FieldSpec[];
|
|
42
|
+
required?: string[];
|
|
43
|
+
/** Row-level security, the verbatim Base44 rule. */
|
|
44
|
+
rls?: {
|
|
45
|
+
create?: unknown;
|
|
46
|
+
read?: unknown;
|
|
47
|
+
update?: unknown;
|
|
48
|
+
delete?: unknown;
|
|
49
|
+
write?: unknown;
|
|
50
|
+
};
|
|
51
|
+
/** Owned entities only. Consumed by provisioning (seed) and hermetic mocks. */
|
|
52
|
+
seed?: Record<string, unknown>[];
|
|
53
|
+
}
|
|
54
|
+
export interface Base44FunctionSpec {
|
|
55
|
+
/** OWNED: source under `base44/functions/<name>/`. */
|
|
56
|
+
name?: string;
|
|
57
|
+
/** ADOPTED: an existing backend function, invoke-only. */
|
|
58
|
+
base44Name?: string;
|
|
59
|
+
description?: string;
|
|
60
|
+
}
|
|
61
|
+
/** The declarative half of `defineApp({ base44 })`. */
|
|
62
|
+
export interface Base44EntitiesConfig {
|
|
63
|
+
entities?: Base44EntitySpec[];
|
|
64
|
+
functions?: Base44FunctionSpec[];
|
|
65
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base44 entity + function declarations for `defineApp({ base44: { entities, functions } })`.
|
|
3
|
+
*
|
|
4
|
+
* The ownership and validation contract lives in @himalaya/data-resources/base44 so the
|
|
5
|
+
* authoring CLI (`himi validate`, `himi base44 adopt|entities`) and `defineApp` enforce the
|
|
6
|
+
* same rules. See docs/base44-entities.md.
|
|
7
|
+
*/
|
|
8
|
+
export { BASE44_BUILTIN_FIELDS, BASE44_FIELD_TYPES, BASE44_STRING_FORMATS, base44Prefix, isAdoptedEntity, isOwnedEntity, physicalEntityName, validateBase44Entities, type Base44EntitySpec, type Base44FieldSpec, type Base44FieldType, type Base44FunctionSpec, type Base44Issue, type Base44RuleCode, type Base44StringFormat, } from "@wix/himalaya/data-resources";
|
package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts
CHANGED
|
@@ -6,11 +6,14 @@ import { type LocaleConfig } from "./locale.js";
|
|
|
6
6
|
import { type DistributionConfig } from "./distribution.js";
|
|
7
7
|
import type { CmsConfig } from "./cms.js";
|
|
8
8
|
import { type DataResourcesConfig } from "@wix/himalaya/data-resources";
|
|
9
|
+
import { type Base44EntitySpec, type Base44FunctionSpec } from "./base44-entities.js";
|
|
9
10
|
import type { FunctionDefinition, FunctionScheduleRecord } from "@himalaya/functions";
|
|
10
11
|
export type { CmsConfig, CmsCollectionSpec, CmsFieldSpec, WixFieldType } from "./cms.js";
|
|
11
12
|
export type { PushRoute, PushPayloadAdapter, PushScreenMapEntry };
|
|
12
13
|
export type { DataResourcesConfig, KvSpec, ResourceEnvironment, ResourceScope } from "@wix/himalaya/data-resources";
|
|
13
14
|
export { WIX_FIELD_TYPES } from "./cms.js";
|
|
15
|
+
export type { Base44EntitySpec, Base44FieldSpec, Base44FieldType, Base44FunctionSpec, Base44Issue, Base44RuleCode, Base44StringFormat } from "./base44-entities.js";
|
|
16
|
+
export { BASE44_BUILTIN_FIELDS, BASE44_FIELD_TYPES, BASE44_STRING_FORMATS, physicalEntityName, validateBase44Entities } from "./base44-entities.js";
|
|
14
17
|
/** Wix site/environment binding used by the server-function surface. */
|
|
15
18
|
export interface SiteBindingConfig {
|
|
16
19
|
siteId: string;
|
|
@@ -776,6 +779,15 @@ export interface Base44Config {
|
|
|
776
779
|
appId: string;
|
|
777
780
|
/** Base44 API origin. Absent ⇒ `https://base44.app`. */
|
|
778
781
|
serverUrl?: string;
|
|
782
|
+
/**
|
|
783
|
+
* The Base44 entities this app depends on (#4557). Each is OWNED (`name`, physically
|
|
784
|
+
* `Himi<AppPascal><name>`) or ADOPTED (`base44Name`, the Base44 app's own entity, read-only to
|
|
785
|
+
* himi). Linted by `himi validate`; `himi base44 adopt` writes adopted entries from a book.
|
|
786
|
+
* See docs/base44-entities.md.
|
|
787
|
+
*/
|
|
788
|
+
entities?: Base44EntitySpec[];
|
|
789
|
+
/** The backend functions this app invokes — owned (`name`) or adopted (`base44Name`). */
|
|
790
|
+
functions?: Base44FunctionSpec[];
|
|
779
791
|
}
|
|
780
792
|
export interface ServerUrls {
|
|
781
793
|
screen: string;
|
|
@@ -445,9 +445,9 @@ var require_codegen = __commonJS({
|
|
|
445
445
|
}
|
|
446
446
|
};
|
|
447
447
|
var Label = class extends Node {
|
|
448
|
-
constructor(
|
|
448
|
+
constructor(label2) {
|
|
449
449
|
super();
|
|
450
|
-
this.label =
|
|
450
|
+
this.label = label2;
|
|
451
451
|
this.names = {};
|
|
452
452
|
}
|
|
453
453
|
render({ _n }) {
|
|
@@ -455,14 +455,14 @@ var require_codegen = __commonJS({
|
|
|
455
455
|
}
|
|
456
456
|
};
|
|
457
457
|
var Break = class extends Node {
|
|
458
|
-
constructor(
|
|
458
|
+
constructor(label2) {
|
|
459
459
|
super();
|
|
460
|
-
this.label =
|
|
460
|
+
this.label = label2;
|
|
461
461
|
this.names = {};
|
|
462
462
|
}
|
|
463
463
|
render({ _n }) {
|
|
464
|
-
const
|
|
465
|
-
return `break${
|
|
464
|
+
const label2 = this.label ? ` ${this.label}` : "";
|
|
465
|
+
return `break${label2};` + _n;
|
|
466
466
|
}
|
|
467
467
|
};
|
|
468
468
|
var Throw = class extends Node {
|
|
@@ -874,12 +874,12 @@ var require_codegen = __commonJS({
|
|
|
874
874
|
return this._endBlockNode(For);
|
|
875
875
|
}
|
|
876
876
|
// `label` statement
|
|
877
|
-
label(
|
|
878
|
-
return this._leafNode(new Label(
|
|
877
|
+
label(label2) {
|
|
878
|
+
return this._leafNode(new Label(label2));
|
|
879
879
|
}
|
|
880
880
|
// `break` statement
|
|
881
|
-
break(
|
|
882
|
-
return this._leafNode(new Break(
|
|
881
|
+
break(label2) {
|
|
882
|
+
return this._leafNode(new Break(label2));
|
|
883
883
|
}
|
|
884
884
|
// `return` statement
|
|
885
885
|
return(value) {
|
|
@@ -7143,6 +7143,170 @@ function validateDistribution(d, where = "distribution") {
|
|
|
7143
7143
|
}
|
|
7144
7144
|
}
|
|
7145
7145
|
|
|
7146
|
+
// ../../core/data-resources/src/base44/schema.ts
|
|
7147
|
+
var BASE44_FIELD_TYPES = ["string", "number", "integer", "boolean", "array", "object"];
|
|
7148
|
+
var BASE44_STRING_FORMATS = ["date", "date-time", "time", "email", "uri", "uuid", "file", "richtext"];
|
|
7149
|
+
var BASE44_BUILTIN_FIELDS = ["id", "created_date", "updated_date", "created_by", "created_by_id"];
|
|
7150
|
+
|
|
7151
|
+
// ../../core/data-resources/src/base44/ownership.ts
|
|
7152
|
+
function base44Prefix(app) {
|
|
7153
|
+
const runs = app.match(/[A-Za-z0-9]+/g) ?? [];
|
|
7154
|
+
return `Himi${runs.map((r) => r.charAt(0).toUpperCase() + r.slice(1)).join("")}`;
|
|
7155
|
+
}
|
|
7156
|
+
function nonEmpty(value) {
|
|
7157
|
+
return typeof value === "string" && value.trim() !== "";
|
|
7158
|
+
}
|
|
7159
|
+
function isAdoptedEntity(spec) {
|
|
7160
|
+
return nonEmpty(spec.base44Name);
|
|
7161
|
+
}
|
|
7162
|
+
function physicalEntityName(spec, app) {
|
|
7163
|
+
if (isAdoptedEntity(spec)) return spec.base44Name;
|
|
7164
|
+
return nonEmpty(spec.name) ? `${base44Prefix(app)}${spec.name}` : "";
|
|
7165
|
+
}
|
|
7166
|
+
var ENTITY_NAME = /^[A-Za-z][A-Za-z0-9]*$/;
|
|
7167
|
+
var FUNCTION_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
7168
|
+
function label(spec) {
|
|
7169
|
+
if (nonEmpty(spec.base44Name)) return spec.base44Name;
|
|
7170
|
+
if (nonEmpty(spec.name)) return spec.name;
|
|
7171
|
+
return "<unnamed>";
|
|
7172
|
+
}
|
|
7173
|
+
function userScoped(rule) {
|
|
7174
|
+
if (rule === void 0) return false;
|
|
7175
|
+
try {
|
|
7176
|
+
return (JSON.stringify(rule) ?? "").includes("{{user.");
|
|
7177
|
+
} catch {
|
|
7178
|
+
return false;
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
function validateBase44Entities(cfg, app) {
|
|
7182
|
+
if (!cfg) return [];
|
|
7183
|
+
const issues = [];
|
|
7184
|
+
const add = (severity, ruleCode, entity, message) => issues.push({ severity, ruleCode, message, ...entity !== void 0 ? { entity } : {} });
|
|
7185
|
+
const err = (ruleCode, entity, message) => add("error", ruleCode, entity, message);
|
|
7186
|
+
const prefix = base44Prefix(app);
|
|
7187
|
+
const types = new Set(BASE44_FIELD_TYPES);
|
|
7188
|
+
const formats = new Set(BASE44_STRING_FORMATS);
|
|
7189
|
+
const builtins = new Set(BASE44_BUILTIN_FIELDS);
|
|
7190
|
+
if (cfg.entities !== void 0 && !Array.isArray(cfg.entities)) err("shape-invalid", void 0, "base44.entities must be an array");
|
|
7191
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7192
|
+
for (const raw of Array.isArray(cfg.entities) ? cfg.entities : []) {
|
|
7193
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
7194
|
+
err("shape-invalid", void 0, "every base44 entity declaration must be an object");
|
|
7195
|
+
continue;
|
|
7196
|
+
}
|
|
7197
|
+
const spec = raw;
|
|
7198
|
+
const name = label(spec);
|
|
7199
|
+
const rawName = spec.name;
|
|
7200
|
+
const rawAdopted = spec.base44Name;
|
|
7201
|
+
const hasName = rawName !== void 0;
|
|
7202
|
+
const hasAdopted = rawAdopted !== void 0;
|
|
7203
|
+
if (hasName && hasAdopted) {
|
|
7204
|
+
err("entity-owned-and-adopted", name, "declare either `name` (owned) or `base44Name` (adopted), not both");
|
|
7205
|
+
} else if (!hasName && !hasAdopted) {
|
|
7206
|
+
err("entity-neither-owned-nor-adopted", name, "needs `name` (owned, namespaced) or `base44Name` (adopted, an entity the Base44 app already has)");
|
|
7207
|
+
} else {
|
|
7208
|
+
const value = hasName ? rawName : rawAdopted;
|
|
7209
|
+
if (typeof value !== "string" || !ENTITY_NAME.test(value)) {
|
|
7210
|
+
err("entity-name-invalid", name, `entity ${hasName ? "name" : "base44Name"} ${JSON.stringify(value)} must be alphanumeric and start with a letter \u2014 Base44 entity names allow nothing else`);
|
|
7211
|
+
} else if (hasAdopted && value.startsWith(prefix)) {
|
|
7212
|
+
err("adopted-in-owned-namespace", name, `adopted entity "${value}" starts with this app's owned prefix "${prefix}" \u2014 himi would treat a foreign entity as its own. Declare it with \`name\` if himi owns it, or rename it.`);
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7215
|
+
const physical = physicalEntityName(spec, app);
|
|
7216
|
+
if (physical) {
|
|
7217
|
+
if (seen.has(physical)) err("entity-duplicate", name, `duplicate entity "${physical}"`);
|
|
7218
|
+
seen.add(physical);
|
|
7219
|
+
}
|
|
7220
|
+
const keys = /* @__PURE__ */ new Set();
|
|
7221
|
+
if (!Array.isArray(spec.fields)) {
|
|
7222
|
+
err("shape-invalid", name, "`fields` must be an array");
|
|
7223
|
+
} else {
|
|
7224
|
+
for (const rawField of spec.fields) {
|
|
7225
|
+
if (!rawField || typeof rawField !== "object" || Array.isArray(rawField)) {
|
|
7226
|
+
err("shape-invalid", name, "every field declaration must be an object");
|
|
7227
|
+
continue;
|
|
7228
|
+
}
|
|
7229
|
+
const field = rawField;
|
|
7230
|
+
if (typeof field.key !== "string" || !field.key) {
|
|
7231
|
+
err("shape-invalid", name, "every field needs a string `key`");
|
|
7232
|
+
continue;
|
|
7233
|
+
}
|
|
7234
|
+
if (builtins.has(field.key)) {
|
|
7235
|
+
err("field-builtin", name, `field "${field.key}" is built in \u2014 Base44 adds ${BASE44_BUILTIN_FIELDS.join(", ")} to every row. Remove it from the declaration.`);
|
|
7236
|
+
continue;
|
|
7237
|
+
}
|
|
7238
|
+
if (keys.has(field.key)) err("field-duplicate", name, `duplicate field key "${field.key}"`);
|
|
7239
|
+
keys.add(field.key);
|
|
7240
|
+
if (!types.has(field.type)) err("field-type-unsupported", name, `field "${field.key}" has unsupported type ${JSON.stringify(field.type)} \u2014 supported: ${BASE44_FIELD_TYPES.join(", ")}`);
|
|
7241
|
+
if (field.format !== void 0) {
|
|
7242
|
+
if (field.type !== "string") err("field-format-invalid", name, `field "${field.key}" declares a format but only string fields take one`);
|
|
7243
|
+
else if (!formats.has(field.format)) err("field-format-invalid", name, `field "${field.key}" has unsupported format ${JSON.stringify(field.format)} \u2014 supported: ${BASE44_STRING_FORMATS.join(", ")}`);
|
|
7244
|
+
}
|
|
7245
|
+
if (field.items !== void 0 && (field.type !== "array" || !types.has(field.items?.type))) {
|
|
7246
|
+
err("field-type-unsupported", name, field.type !== "array" ? `field "${field.key}" declares \`items\` but only array fields take one` : `field "${field.key}" has unsupported items type ${JSON.stringify(field.items?.type)} \u2014 supported: ${BASE44_FIELD_TYPES.join(", ")}`);
|
|
7247
|
+
}
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
if (spec.displayField !== void 0 && !keys.has(spec.displayField) && !builtins.has(spec.displayField)) {
|
|
7251
|
+
err("display-field-unknown", name, `displayField "${spec.displayField}" is not one of the declared fields (${[...keys].join(", ") || "none"})`);
|
|
7252
|
+
}
|
|
7253
|
+
if (spec.required !== void 0) {
|
|
7254
|
+
if (!Array.isArray(spec.required)) err("shape-invalid", name, "`required` must be an array of field keys");
|
|
7255
|
+
else for (const key of spec.required) {
|
|
7256
|
+
if (!keys.has(key)) err("required-unknown", name, `required field "${key}" is not declared`);
|
|
7257
|
+
}
|
|
7258
|
+
}
|
|
7259
|
+
if (spec.seed !== void 0) {
|
|
7260
|
+
if (hasAdopted) {
|
|
7261
|
+
err("seed-on-adopted", name, "an adopted entity cannot declare `seed` \u2014 himi never writes to entities it does not own");
|
|
7262
|
+
} else if (!Array.isArray(spec.seed)) {
|
|
7263
|
+
err("shape-invalid", name, "seed must be an array of row objects");
|
|
7264
|
+
} else {
|
|
7265
|
+
spec.seed.forEach((row, index) => {
|
|
7266
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) {
|
|
7267
|
+
err("shape-invalid", name, `seed row ${index} must be an object`);
|
|
7268
|
+
return;
|
|
7269
|
+
}
|
|
7270
|
+
for (const key of Object.keys(row)) {
|
|
7271
|
+
if (!keys.has(key)) err("seed-key-unknown", name, `seed row ${index} sets undeclared field "${key}"`);
|
|
7272
|
+
}
|
|
7273
|
+
});
|
|
7274
|
+
}
|
|
7275
|
+
}
|
|
7276
|
+
if (userScoped(spec.rls?.read)) {
|
|
7277
|
+
add("warning", "read-rule-user-scoped", name, "rls.read is scoped to the signed-in user ({{user.\u2026}}), so a signed-out viewer sees an empty list. Gate the screen behind a sign-in, or widen the read rule if the rows are public.");
|
|
7278
|
+
}
|
|
7279
|
+
}
|
|
7280
|
+
if (cfg.functions !== void 0 && !Array.isArray(cfg.functions)) err("shape-invalid", void 0, "base44.functions must be an array");
|
|
7281
|
+
const seenFns = /* @__PURE__ */ new Set();
|
|
7282
|
+
for (const raw of Array.isArray(cfg.functions) ? cfg.functions : []) {
|
|
7283
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
7284
|
+
err("shape-invalid", void 0, "every base44 function declaration must be an object");
|
|
7285
|
+
continue;
|
|
7286
|
+
}
|
|
7287
|
+
const spec = raw;
|
|
7288
|
+
const name = label(spec);
|
|
7289
|
+
const hasName = spec.name !== void 0;
|
|
7290
|
+
const hasAdopted = spec.base44Name !== void 0;
|
|
7291
|
+
if (hasName && hasAdopted) {
|
|
7292
|
+
err("function-owned-and-adopted", name, "declare either `name` (owned) or `base44Name` (adopted), not both");
|
|
7293
|
+
continue;
|
|
7294
|
+
}
|
|
7295
|
+
if (!hasName && !hasAdopted) {
|
|
7296
|
+
err("function-neither-owned-nor-adopted", name, "needs `name` (owned, source under base44/functions/<name>/) or `base44Name` (adopted, an existing backend function)");
|
|
7297
|
+
continue;
|
|
7298
|
+
}
|
|
7299
|
+
const value = hasName ? spec.name : spec.base44Name;
|
|
7300
|
+
if (typeof value !== "string" || !FUNCTION_NAME.test(value)) {
|
|
7301
|
+
err("function-name-invalid", name, `function name ${JSON.stringify(value)} must be letters, digits, "-" or "_"`);
|
|
7302
|
+
continue;
|
|
7303
|
+
}
|
|
7304
|
+
if (seenFns.has(value)) err("function-duplicate", name, `duplicate function "${value}"`);
|
|
7305
|
+
seenFns.add(value);
|
|
7306
|
+
}
|
|
7307
|
+
return issues;
|
|
7308
|
+
}
|
|
7309
|
+
|
|
7146
7310
|
// ../../core/data-resources/src/schema.ts
|
|
7147
7311
|
var WIX_FIELD_TYPES = [
|
|
7148
7312
|
"TEXT",
|
|
@@ -7492,6 +7656,14 @@ function validateLadderConfig(config) {
|
|
|
7492
7656
|
);
|
|
7493
7657
|
}
|
|
7494
7658
|
}
|
|
7659
|
+
var SLUG_DEPENDENT_BASE44_RULES = /* @__PURE__ */ new Set(["adopted-in-owned-namespace", "entity-duplicate"]);
|
|
7660
|
+
function sameKindBase44Duplicate(entities) {
|
|
7661
|
+
const list = Array.isArray(entities) ? entities.filter((e) => e && typeof e === "object") : [];
|
|
7662
|
+
const firstDup = (xs) => xs.find((x, i) => xs.indexOf(x) !== i);
|
|
7663
|
+
const adopted = list.map((e) => e.base44Name).filter((n) => typeof n === "string" && n !== "");
|
|
7664
|
+
const owned = list.filter((e) => !e.base44Name).map((e) => e.name).filter((n) => typeof n === "string" && n !== "");
|
|
7665
|
+
return firstDup(owned) ?? firstDup(adopted);
|
|
7666
|
+
}
|
|
7495
7667
|
function validateBase44Config(config) {
|
|
7496
7668
|
const b = config.base44;
|
|
7497
7669
|
if (!b || typeof b.appId !== "string" || !/^[A-Za-z0-9]{8,64}$/.test(b.appId)) {
|
|
@@ -7503,6 +7675,12 @@ function validateBase44Config(config) {
|
|
|
7503
7675
|
if (!config.capabilities?.includes("base44")) {
|
|
7504
7676
|
throw new Error('defineApp: base44 is configured but the "base44" capability is not declared.');
|
|
7505
7677
|
}
|
|
7678
|
+
const first = validateBase44Entities({ entities: b.entities, functions: b.functions }, config.id).find((i) => i.severity === "error" && !SLUG_DEPENDENT_BASE44_RULES.has(i.ruleCode));
|
|
7679
|
+
if (first) {
|
|
7680
|
+
throw new Error(`defineApp: base44.entities: ${first.entity ? `"${first.entity}": ` : ""}${first.message} (${first.ruleCode})`);
|
|
7681
|
+
}
|
|
7682
|
+
const dup = sameKindBase44Duplicate(b.entities);
|
|
7683
|
+
if (dup) throw new Error(`defineApp: base44.entities: "${dup}": duplicate entity "${dup}" (entity-duplicate)`);
|
|
7506
7684
|
}
|
|
7507
7685
|
function validateConfigShape(config) {
|
|
7508
7686
|
if (!config.id || !/^[a-z0-9.]+$/.test(config.id)) {
|
|
@@ -7890,7 +8068,7 @@ function tonalElevationAlpha(level) {
|
|
|
7890
8068
|
var BUTTON_SIZES = ["sm", "md", "lg"];
|
|
7891
8069
|
var BUTTON_MIN_HIT_TARGET = 44;
|
|
7892
8070
|
var nonNegative = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : void 0;
|
|
7893
|
-
var
|
|
8071
|
+
var nonEmpty2 = (v) => typeof v === "string" && v !== "" ? v : void 0;
|
|
7894
8072
|
var own = (o, k) => o && typeof o === "object" && Object.prototype.hasOwnProperty.call(o, k) ? o[k] : void 0;
|
|
7895
8073
|
function resolveButtonTokens(tokens, size, style) {
|
|
7896
8074
|
const button = own(own(tokens, "controls"), "button");
|
|
@@ -7904,12 +8082,12 @@ function resolveButtonTokens(tokens, size, style) {
|
|
|
7904
8082
|
set("height", nonNegative(own(s, "height")));
|
|
7905
8083
|
set("paddingH", nonNegative(own(s, "paddingH")));
|
|
7906
8084
|
set("paddingV", nonNegative(own(s, "paddingV")));
|
|
7907
|
-
set("text",
|
|
8085
|
+
set("text", nonEmpty2(own(s, "text")));
|
|
7908
8086
|
set("icon", nonNegative(own(s, "icon")));
|
|
7909
8087
|
set("radius", nonNegative(own(v, "radius")) ?? nonNegative(own(s, "radius")));
|
|
7910
|
-
set("fill",
|
|
7911
|
-
set("label",
|
|
7912
|
-
set("border",
|
|
8088
|
+
set("fill", nonEmpty2(own(v, "fill")));
|
|
8089
|
+
set("label", nonEmpty2(own(v, "label")));
|
|
8090
|
+
set("border", nonEmpty2(own(v, "border")));
|
|
7913
8091
|
set("borderWidth", nonNegative(own(v, "borderWidth")));
|
|
7914
8092
|
return out;
|
|
7915
8093
|
}
|
|
@@ -9522,16 +9700,16 @@ function shouldRevealError(args) {
|
|
|
9522
9700
|
return args.touched && !args.focused;
|
|
9523
9701
|
}
|
|
9524
9702
|
}
|
|
9525
|
-
var
|
|
9703
|
+
var nonEmpty3 = (type) => (v) => typeof v === "string" && v.length > 0 && isValid({ type }, v);
|
|
9526
9704
|
var validators = {
|
|
9527
9705
|
// validates: these are top-level CALLS, which esbuild otherwise has to assume
|
|
9528
9706
|
// might have side effects — and keeping them retained `validate` and every
|
|
9529
9707
|
// predicate behind it, DOUBLING a Tier-5 bundle that does no validation at all.
|
|
9530
|
-
email: /* @__PURE__ */
|
|
9531
|
-
phone: /* @__PURE__ */
|
|
9532
|
-
url: /* @__PURE__ */
|
|
9533
|
-
number: /* @__PURE__ */
|
|
9534
|
-
integer: /* @__PURE__ */
|
|
9708
|
+
email: /* @__PURE__ */ nonEmpty3("email"),
|
|
9709
|
+
phone: /* @__PURE__ */ nonEmpty3("phone"),
|
|
9710
|
+
url: /* @__PURE__ */ nonEmpty3("url"),
|
|
9711
|
+
number: /* @__PURE__ */ nonEmpty3("number"),
|
|
9712
|
+
integer: /* @__PURE__ */ nonEmpty3("integer")
|
|
9535
9713
|
};
|
|
9536
9714
|
function validateAll(rules, values, catalog) {
|
|
9537
9715
|
const errors = {};
|
|
@@ -9599,9 +9777,9 @@ var WATCH_UNAVAILABLE = {
|
|
|
9599
9777
|
};
|
|
9600
9778
|
var CAR_TEMPLATES = ["list"];
|
|
9601
9779
|
var PROJECTION_SNAPSHOT_SIZE = "large";
|
|
9602
|
-
var widgetSurface = (family,
|
|
9780
|
+
var widgetSurface = (family, label2, width, height, platformKey = null) => ({
|
|
9603
9781
|
id: `widget:${family}`,
|
|
9604
|
-
label,
|
|
9782
|
+
label: label2,
|
|
9605
9783
|
chassis: "widget",
|
|
9606
9784
|
viewport: { width, height },
|
|
9607
9785
|
orientations: ["portrait"],
|
|
@@ -13825,9 +14003,9 @@ function normalizeSiteMenu(payload, site) {
|
|
|
13825
14003
|
for (const item of items.slice(0, SITE_MENU_RAW_ITEMS_MAX)) {
|
|
13826
14004
|
if (out.length >= SITE_MENU_MAX_ITEMS) break;
|
|
13827
14005
|
if (!item || typeof item !== "object") continue;
|
|
13828
|
-
const { label, href } = item;
|
|
13829
|
-
if (typeof
|
|
13830
|
-
const clean = cleanSiteMenuLabel(
|
|
14006
|
+
const { label: label2, href } = item;
|
|
14007
|
+
if (typeof label2 !== "string" || typeof href !== "string") continue;
|
|
14008
|
+
const clean = cleanSiteMenuLabel(label2);
|
|
13831
14009
|
if (!clean) continue;
|
|
13832
14010
|
const path = siteMenuPath(href, site.origins);
|
|
13833
14011
|
if (path === null) continue;
|
|
@@ -13950,7 +14128,10 @@ export {
|
|
|
13950
14128
|
ALL_ORIENTATIONS,
|
|
13951
14129
|
APP_ID_PATTERN,
|
|
13952
14130
|
AppRegistryClient,
|
|
14131
|
+
BASE44_BUILTIN_FIELDS,
|
|
14132
|
+
BASE44_FIELD_TYPES,
|
|
13953
14133
|
BASE44_ORIGINS,
|
|
14134
|
+
BASE44_STRING_FORMATS,
|
|
13954
14135
|
BUTTON_LEGACY_STYLES,
|
|
13955
14136
|
BUTTON_MIN_HIT_TARGET,
|
|
13956
14137
|
BUTTON_SIZES,
|
|
@@ -14075,6 +14256,7 @@ export {
|
|
|
14075
14256
|
normalizeSiteMenu,
|
|
14076
14257
|
normalizeSiteOrigin,
|
|
14077
14258
|
parseNumeric,
|
|
14259
|
+
physicalEntityName,
|
|
14078
14260
|
primarySubtag,
|
|
14079
14261
|
resolveAppIdentity,
|
|
14080
14262
|
resolveAppLocale,
|
|
@@ -14121,6 +14303,7 @@ export {
|
|
|
14121
14303
|
tonalElevationAlpha,
|
|
14122
14304
|
validate,
|
|
14123
14305
|
validateAll,
|
|
14306
|
+
validateBase44Entities,
|
|
14124
14307
|
validateDistribution,
|
|
14125
14308
|
validateLaunchManifest,
|
|
14126
14309
|
validateMediaPlayerProps,
|