@almadar/core 10.86.0 → 10.87.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/builders.d.ts +5 -4
- package/dist/builders.js +68 -29
- package/dist/builders.js.map +1 -1
- package/dist/{effect-BgDiw_bG.d.ts → effect-DMA97JxX.d.ts} +22 -6
- package/dist/{entityAccess-DK5S_2cT.d.ts → entityAccess-DNDEF75i.d.ts} +2 -2
- package/dist/{expression-Fk8bQWef.d.ts → expression-WfTp2arD.d.ts} +2 -65
- package/dist/factory/index.d.ts +6 -5
- package/dist/factory/index.js +1194 -401
- package/dist/factory/index.js.map +1 -1
- package/dist/factory-runtime/index.d.ts +35 -5
- package/dist/factory-runtime/index.js +127 -52
- package/dist/factory-runtime/index.js.map +1 -1
- package/dist/i18n/index.d.ts +111 -1
- package/dist/i18n/index.js +500 -19
- package/dist/i18n/index.js.map +1 -1
- package/dist/{index-ChYsqVJj.d.ts → index-xZP_Ajx3.d.ts} +18 -5
- package/dist/index.d.ts +82 -14
- package/dist/index.js +1876 -333
- package/dist/index.js.map +1 -1
- package/dist/json-D8gmyK3l.d.ts +65 -0
- package/dist/mock/index.d.ts +129 -12
- package/dist/mock/index.js +192 -61
- package/dist/mock/index.js.map +1 -1
- package/dist/patterns/component-mapping.json +1 -1
- package/dist/patterns/event-contracts.json +1 -1
- package/dist/patterns/index.d.ts +2525 -609
- package/dist/patterns/index.js +1238 -384
- package/dist/patterns/index.js.map +1 -1
- package/dist/patterns/integrators-registry.json +107 -23
- package/dist/patterns/patterns-registry.json +1170 -400
- package/dist/patterns/registry.json +1170 -400
- package/dist/patterns/services-registry.json +170 -35
- package/dist/{schema-BhfQb1oe.d.ts → schema-_SPrm5Ic.d.ts} +46381 -21335
- package/dist/state-machine/index.d.ts +2 -1
- package/dist/trait-9tfq2tQb.d.ts +10554 -0
- package/dist/types/index.d.ts +7 -6
- package/dist/types/index.js +132 -43
- package/dist/types/index.js.map +1 -1
- package/dist/{types-CCAmdxcH.d.ts → types-CjRjhiaO.d.ts} +19 -3
- package/package.json +2 -2
- package/dist/trait-pavNlGqm.d.ts +0 -5385
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON primitives — the universal "data crossed a boundary" type.
|
|
3
|
+
*
|
|
4
|
+
* Every value that arrives over the wire from an LLM (tool-call args),
|
|
5
|
+
* from disk (workspace files), or from an HTTP body before
|
|
6
|
+
* domain-specific validation is a `JsonValue`. Narrow with a typed
|
|
7
|
+
* predicate (`is`-guard) at the boundary; don't widen back to `unknown`.
|
|
8
|
+
*
|
|
9
|
+
* `JsonObject` and `ToolArgs` are aliases for the common
|
|
10
|
+
* `Record<string, JsonValue>` shape. `ToolArgs` is the name the
|
|
11
|
+
* agent surface uses for LLM-emitted tool-call arguments; `JsonObject`
|
|
12
|
+
* is the general-purpose alias. They are the same type — the alias
|
|
13
|
+
* exists so call sites read at the right semantic level.
|
|
14
|
+
*
|
|
15
|
+
* Why not `Record<string, unknown>`? Two reasons. (1) `unknown` widens
|
|
16
|
+
* back to anything, which defeats the purpose of typing the boundary.
|
|
17
|
+
* (2) The `@almadar/eslint-plugin/no-record-string-unknown` rule blocks
|
|
18
|
+
* the wider form — `JsonValue`-based records are the typed answer.
|
|
19
|
+
*
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Recursive JSON value union — every shape JSON can carry.
|
|
25
|
+
*/
|
|
26
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
27
|
+
[key: string]: JsonValue;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* JSON object — keyed string→JsonValue. The wire form of arbitrary
|
|
31
|
+
* structured data. Replaces `Record<string, unknown>` at typed
|
|
32
|
+
* boundaries (LLM emits, file reads, HTTP bodies).
|
|
33
|
+
*/
|
|
34
|
+
type JsonObject = {
|
|
35
|
+
[key: string]: JsonValue;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* LLM tool-call arguments — same shape as `JsonObject`, named for the
|
|
39
|
+
* agent-surface call site. Each tool's `execute(args: ToolArgs)`
|
|
40
|
+
* receives this and narrows via an `is`-guard predicate before any
|
|
41
|
+
* field access.
|
|
42
|
+
*/
|
|
43
|
+
type ToolArgs = JsonObject;
|
|
44
|
+
/**
|
|
45
|
+
* Universal type-guard input — every runtime value shape a predicate can
|
|
46
|
+
* be handed, enumerated instead of `unknown` (the repo bans `unknown`
|
|
47
|
+
* even at guard boundaries). Primitives cover every `typeof` result;
|
|
48
|
+
* `object` covers arrays, records, class instances, and functions.
|
|
49
|
+
*/
|
|
50
|
+
type RuntimeValue = string | number | bigint | boolean | symbol | Date | null | undefined | object;
|
|
51
|
+
/**
|
|
52
|
+
* Type guard: is the given value a JSON primitive (non-array,
|
|
53
|
+
* non-object)? Used by walkers that decide whether to recurse.
|
|
54
|
+
*/
|
|
55
|
+
declare function isJsonPrimitive(value: JsonValue): value is string | number | boolean | null;
|
|
56
|
+
/**
|
|
57
|
+
* Type guard: is the given value a JSON object (non-array, non-null)?
|
|
58
|
+
*/
|
|
59
|
+
declare function isJsonObject(value: JsonValue): value is JsonObject;
|
|
60
|
+
/**
|
|
61
|
+
* Type guard: is the given value a JSON array?
|
|
62
|
+
*/
|
|
63
|
+
declare function isJsonArray(value: JsonValue): value is JsonValue[];
|
|
64
|
+
|
|
65
|
+
export { type JsonValue as J, type RuntimeValue as R, type ToolArgs as T, type JsonObject as a, isJsonObject as b, isJsonPrimitive as c, isJsonArray as i };
|
package/dist/mock/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import '../expression-Fk8bQWef.js';
|
|
1
|
+
import { f as OrbitalEntity, a as EntityPersistence, E as EntityField, F as FieldValue, g as EntityRow } from '../effect-DMA97JxX.js';
|
|
2
|
+
import { a as OrbitalDefinition, O as OrbitalSchema } from '../schema-_SPrm5Ic.js';
|
|
3
|
+
import { S as SExpr } from '../expression-WfTp2arD.js';
|
|
4
|
+
export { E as EntityAccessPolicies, e as entityAccessPolicies, a as entityAccessPoliciesByStoreKey, b as entityAccessTable } from '../entityAccess-DNDEF75i.js';
|
|
6
5
|
import 'zod';
|
|
6
|
+
import '../json-D8gmyK3l.js';
|
|
7
|
+
import '../trait-9tfq2tQb.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Lightweight seeded pseudo-random generator for mock data.
|
|
@@ -78,7 +79,8 @@ declare function randomPhone(): string;
|
|
|
78
79
|
*/
|
|
79
80
|
|
|
80
81
|
/**
|
|
81
|
-
* The
|
|
82
|
+
* The `[identity]` entities that decide what `@user` resolves to, primaries
|
|
83
|
+
* first then auxiliaries.
|
|
82
84
|
*
|
|
83
85
|
* A behavior declares its own roster so it runs standalone. Composing it never
|
|
84
86
|
* imports that orbital, but a trait bound to one of its siblings drags the
|
|
@@ -88,16 +90,125 @@ declare function randomPhone(): string;
|
|
|
88
90
|
* wraps one behavior inherit that behavior's roster.
|
|
89
91
|
*
|
|
90
92
|
* Compiled-path twin: `identity_entities` in
|
|
93
|
+
* `orbital-compiler/src/phases/validation/user_identity.rs` (L94-102).
|
|
94
|
+
*/
|
|
95
|
+
declare function identityEntitiesOf(orbitals: readonly OrbitalDefinition[]): OrbitalEntity[];
|
|
96
|
+
/**
|
|
97
|
+
* The name of the schema's `[identity]` entity, if it declares one.
|
|
98
|
+
*
|
|
99
|
+
* Compiled-path twin: `identity_entities` in
|
|
91
100
|
* `orbital-compiler/src/phases/validation/user_identity.rs`.
|
|
92
101
|
*/
|
|
93
102
|
declare function identityEntityName(schema: OrbitalSchema): string | undefined;
|
|
94
103
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
104
|
+
* Every `[identity]`-tagged name, shadowed copies included.
|
|
105
|
+
*
|
|
106
|
+
* Owner-column derivation asks whether a relation targets *a* roster, not *the*
|
|
107
|
+
* one: `Timesheet.employeeId : Employee` is an owner column whether or not
|
|
108
|
+
* `Employee` won the `@user` binding. Dropping the shadowed names here would
|
|
109
|
+
* leave an imported behavior's rows unscoped at runtime while the compiled path
|
|
110
|
+
* treats the very same column as an owner column.
|
|
111
|
+
*
|
|
112
|
+
* Compiled-path twin: `identity_entity_names` in
|
|
113
|
+
* `orbital-compiler/src/phases/validation/user_identity.rs`.
|
|
114
|
+
*/
|
|
115
|
+
declare function identityEntityNames(schema: OrbitalSchema): string[];
|
|
116
|
+
/**
|
|
117
|
+
* The declared vocabulary for an identity field, following `items` for the
|
|
118
|
+
* array/map form. `roles : ["a" | "b"]` keeps the union on the ELEMENT, so a
|
|
119
|
+
* multi-valued role field is read through `items` — one level, not recursive.
|
|
120
|
+
*
|
|
121
|
+
* Compiled-path twin: `vocabulary` in
|
|
122
|
+
* `orbital-compiler/src/phases/validation/user_identity.rs` (L125-134).
|
|
123
|
+
*/
|
|
124
|
+
declare function roleVocabularyOf(entity: OrbitalEntity, field?: string): readonly string[] | undefined;
|
|
125
|
+
/**
|
|
126
|
+
* Every column `expr` compares to `@user.id` via direct equality — the
|
|
127
|
+
* general form of "self-identity": `@entity.<field> == @user.id` (either
|
|
128
|
+
* operand order, either spelling — see `fieldRefName`) names `field` as an
|
|
129
|
+
* owner column, whether `field` is the row's OWN `id` (distinct from a
|
|
130
|
+
* relation column like `@entity.managerId == @user.id`) or any other
|
|
131
|
+
* declared field (the shape `ORB_S_OWNER_FIELD_NOT_IDENTITY_TYPED` flags as
|
|
132
|
+
* an authoring error when it is neither — codegen still needs to seed it).
|
|
133
|
+
* Recurses through `and`/`or`/`not`/any other combinator —
|
|
134
|
+
* `std-time-tracking`'s `Employee [identity]` declares
|
|
135
|
+
* `@read (or (= @user.role "approver") (= (object/get @entity id) @user.id))`,
|
|
136
|
+
* and the self-access arm counts even though it isn't the whole policy.
|
|
137
|
+
* Rust twin: `owner_columns_from_policy` in `orbital-core/src/runtime/seed.rs`.
|
|
138
|
+
*/
|
|
139
|
+
declare function ownerColumnsFromPolicy(expr: SExpr, out?: string[]): string[];
|
|
140
|
+
/**
|
|
141
|
+
* Owner columns as `Entity.field` pairs — every NON-INTRINSIC relation field
|
|
142
|
+
* pointing at an `[identity]`-tagged entity, shadowed imported rosters
|
|
143
|
+
* included, PLUS `Entity.id` for an `[identity]` entity whose own declared
|
|
144
|
+
* access policy compares its row directly to the viewer (self-identity), PLUS
|
|
145
|
+
* any other column an entity's own declared `@read`/`@update`/`@delete`
|
|
146
|
+
* compares to `@user.id` (see `ownerColumnsFromPolicy`). Empty when the
|
|
97
147
|
* program declares no identity, which keeps every unmigrated app behaving
|
|
98
148
|
* exactly as before.
|
|
149
|
+
*
|
|
150
|
+
* An `intrinsic: true` relation field is excluded even when it targets the
|
|
151
|
+
* identity entity: intrinsic marks framework plumbing the owning trait
|
|
152
|
+
* computes itself (`EntityField.intrinsic` doc, `types/field.ts`), never
|
|
153
|
+
* domain ownership — a generic atom's self-relation (`ModalRecord.seedRow :
|
|
154
|
+
* ModalRecord`, record-detail/modal edit-seed plumbing) gets its relation
|
|
155
|
+
* target rewritten onto whatever entity the trait binds, so a self-identity
|
|
156
|
+
* entity like `std-time-tracking`'s `Employee [identity]` ends up with an
|
|
157
|
+
* `Employee.seedRow : Employee` self-relation that is structurally
|
|
158
|
+
* indistinguishable from a real owner column by type/target alone. Stamping
|
|
159
|
+
* it with the viewer id (as an owner column would be) creates a row that
|
|
160
|
+
* references itself, which trips the entity's own `onDelete: restrict`.
|
|
99
161
|
*/
|
|
100
162
|
declare function ownerFieldsFromSchema(schema: OrbitalSchema): string[];
|
|
163
|
+
/**
|
|
164
|
+
* Every literal an expression compares against `@user.<field>` (any field),
|
|
165
|
+
* keyed by field name — the collecting counterpart of `orbital-compiler`'s
|
|
166
|
+
* `validation::user_identity::check_comparison` (B4-R4; the two must stay
|
|
167
|
+
* shape-identical, each cites the other): an equality node (`EQUALITY_OPS`)
|
|
168
|
+
* or an `array/includes` node, walked transparently through `and`/`or`/`not`
|
|
169
|
+
* and any other combinator (the Rust check runs on EVERY array node
|
|
170
|
+
* regardless of what wraps it, so this does too).
|
|
171
|
+
*
|
|
172
|
+
* `array/includes` is directional, but the sigil can sit on EITHER side:
|
|
173
|
+
* `(array/includes @user.roles "ghost")` checks a literal against a
|
|
174
|
+
* multi-valued field's own vocabulary (field is the haystack, position 0);
|
|
175
|
+
* the Stage-B orbital-import role rewrite (Rust `inline/rewrite.rs`
|
|
176
|
+
* `rewrite_role_literals`, which `check_comparison` mirrors) instead
|
|
177
|
+
* produces `(array/includes ["owner","project_manager"] @user.role)` — a
|
|
178
|
+
* literal ARRAY haystack with the sigil as the needle, position 1 (found
|
|
179
|
+
* live: Project Friday's imported `Timesheet.@delete` after `roles {
|
|
180
|
+
* approver: [owner, project_manager] }`). So the sigil is located BY
|
|
181
|
+
* CONTENT, never position: check position 0 first, fall back to position 1.
|
|
182
|
+
* The OTHER side is then flattened to a literal list — a scalar (equality,
|
|
183
|
+
* or an `array/includes` whose haystack is the sigil's own multi-valued
|
|
184
|
+
* field) or, for the role-rewrite shape, every string element of a literal
|
|
185
|
+
* array.
|
|
186
|
+
*
|
|
187
|
+
* A collected literal is a CANDIDATE a viewer might satisfy the expression
|
|
188
|
+
* with, never a proof: a policy that ANDs the field check with an unrelated
|
|
189
|
+
* condition can still reject a viewer carrying it. Callers that need
|
|
190
|
+
* certainty re-check with the real evaluator (`checkMutationAccess` /
|
|
191
|
+
* `evaluate`), the way any other synthesized dispatch is confirmed.
|
|
192
|
+
*/
|
|
193
|
+
declare function collectUserFieldLiterals(expr: SExpr, out?: Map<string, Set<string>>): Map<string, Set<string>>;
|
|
194
|
+
/**
|
|
195
|
+
* A `@user.<field>` value that satisfies `policy`, chosen from the identity
|
|
196
|
+
* entity's own declared vocabulary — never a guess: only a literal BOTH
|
|
197
|
+
* (a) compared against `field` in an equality/`array/includes` node
|
|
198
|
+
* somewhere in `policy` (see {@link collectUserFieldLiterals}) AND (b) a
|
|
199
|
+
* declared member of `identity`'s `field` vocabulary (see
|
|
200
|
+
* {@link roleVocabularyOf}) is a candidate. The pick is deterministic — the
|
|
201
|
+
* first vocabulary value, in declaration order, that is also a candidate —
|
|
202
|
+
* so two callers asking about the same policy always agree.
|
|
203
|
+
*
|
|
204
|
+
* `undefined` when `policy` is absent/`null` (no restriction — nothing to
|
|
205
|
+
* satisfy), `field` carries no declared vocabulary on `identity`, or no
|
|
206
|
+
* declared value appears anywhere in the policy. The last case is a genuine
|
|
207
|
+
* finding for the CALLER to report, not a probe defect to paper over: the
|
|
208
|
+
* policy structurally cannot be satisfied by any roster member, so forcing a
|
|
209
|
+
* viewer past it would misreport an unreachable transition as reachable.
|
|
210
|
+
*/
|
|
211
|
+
declare function roleSatisfyingPolicy(policy: SExpr | undefined, identity: OrbitalEntity, field?: string): string | undefined;
|
|
101
212
|
|
|
102
213
|
/**
|
|
103
214
|
* The one owner of mock-seed value synthesis.
|
|
@@ -152,13 +263,19 @@ declare function sampleRowCount(entity: SampleEntity, requested: number): number
|
|
|
152
263
|
/**
|
|
153
264
|
* One sample value for one field. `undefined` means OMIT the key.
|
|
154
265
|
*
|
|
155
|
-
* Order matters — see the
|
|
156
|
-
* schema properties (`persistence`, `intrinsic`
|
|
266
|
+
* Order matters — see the four gates in the plan. Gates 1, 2 and 3 read
|
|
267
|
+
* declared schema properties (`persistence`, `intrinsic`, `required`,
|
|
268
|
+
* `default`, `type`), never field names.
|
|
157
269
|
*/
|
|
158
270
|
declare function sampleFieldValue(field: EntityField, ctx: SampleContext): FieldValue | undefined;
|
|
159
|
-
/**
|
|
271
|
+
/**
|
|
272
|
+
* One row. Reserved keys are left to the caller. Under `strategy: 'seeded'`,
|
|
273
|
+
* every other row (see {@link omitsUndefaultedOptionalFields}) omits its
|
|
274
|
+
* undefaulted optional fields — required/defaulted/relation fields are
|
|
275
|
+
* always present.
|
|
276
|
+
*/
|
|
160
277
|
declare function sampleRow(entity: SampleEntity, ctx: Omit<SampleContext, 'entityName' | 'depth'>): EntityRow;
|
|
161
278
|
/** `count` rows, 1-based, honoring the runtime-singleton gate. */
|
|
162
279
|
declare function sampleRows(entity: SampleEntity, count: number, strategy: SampleStrategy): EntityRow[];
|
|
163
280
|
|
|
164
|
-
export { IMAGE_FIELD_NAMES, type SampleContext, type SampleEntity, type SampleStrategy, identityEntityName, isDeclaredDefaultHonored, ownerFieldsFromSchema, randomAnytimeDate, randomArrayElement, randomBoolean, randomColor, randomEmail, randomFloat, randomInt, randomPassword, randomPastDate, randomPhone, randomRecentDate, randomSentence, randomStraddlingDate, randomUrl, randomUuid, randomWords, sampleFieldValue, sampleImageUrl, sampleRow, sampleRowCount, sampleRows, seedRandom, shuffleArray };
|
|
281
|
+
export { IMAGE_FIELD_NAMES, type SampleContext, type SampleEntity, type SampleStrategy, collectUserFieldLiterals, identityEntitiesOf, identityEntityName, identityEntityNames, isDeclaredDefaultHonored, ownerColumnsFromPolicy, ownerFieldsFromSchema, randomAnytimeDate, randomArrayElement, randomBoolean, randomColor, randomEmail, randomFloat, randomInt, randomPassword, randomPastDate, randomPhone, randomRecentDate, randomSentence, randomStraddlingDate, randomUrl, randomUuid, randomWords, roleSatisfyingPolicy, roleVocabularyOf, sampleFieldValue, sampleImageUrl, sampleRow, sampleRowCount, sampleRows, seedRandom, shuffleArray };
|
package/dist/mock/index.js
CHANGED
|
@@ -166,7 +166,7 @@ function randomPhone() {
|
|
|
166
166
|
return `+1 (${area}) ${prefix}-${line}`;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
// src/
|
|
169
|
+
// src/access/entityAccess.ts
|
|
170
170
|
function inlineEntities(schema) {
|
|
171
171
|
const out = [];
|
|
172
172
|
for (const orbital of schema.orbitals ?? []) {
|
|
@@ -179,15 +179,74 @@ function inlineEntities(schema) {
|
|
|
179
179
|
}
|
|
180
180
|
return out;
|
|
181
181
|
}
|
|
182
|
-
function
|
|
182
|
+
function isDeclared(p) {
|
|
183
|
+
return p.read !== void 0 || p.create !== void 0 || p.update !== void 0 || p.delete !== void 0;
|
|
184
|
+
}
|
|
185
|
+
function entityAccessTable(schema) {
|
|
186
|
+
const table = /* @__PURE__ */ new Map();
|
|
187
|
+
const collectionOf = /* @__PURE__ */ new Map();
|
|
188
|
+
for (const def of inlineEntities(schema)) {
|
|
189
|
+
table.set(def.name, {
|
|
190
|
+
read: def.read_policy,
|
|
191
|
+
create: def.create_policy,
|
|
192
|
+
update: def.update_policy,
|
|
193
|
+
delete: def.delete_policy
|
|
194
|
+
});
|
|
195
|
+
if (def.collection) collectionOf.set(def.name, def.collection);
|
|
196
|
+
}
|
|
197
|
+
const byCollection = /* @__PURE__ */ new Map();
|
|
198
|
+
for (const [name, policies] of table) {
|
|
199
|
+
const collection = collectionOf.get(name);
|
|
200
|
+
if (collection && isDeclared(policies) && !byCollection.has(collection)) {
|
|
201
|
+
byCollection.set(collection, policies);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
for (const [name, policies] of table) {
|
|
205
|
+
if (isDeclared(policies)) continue;
|
|
206
|
+
const collection = collectionOf.get(name);
|
|
207
|
+
const inherited = collection ? byCollection.get(collection) : void 0;
|
|
208
|
+
if (inherited) table.set(name, { ...inherited });
|
|
209
|
+
}
|
|
210
|
+
return table;
|
|
211
|
+
}
|
|
212
|
+
function entityAccessPolicies(schema, entityName) {
|
|
213
|
+
return entityAccessTable(schema).get(entityName);
|
|
214
|
+
}
|
|
215
|
+
function entityAccessPoliciesByStoreKey(schema) {
|
|
216
|
+
const collectionOf = /* @__PURE__ */ new Map();
|
|
217
|
+
for (const def of inlineEntities(schema)) {
|
|
218
|
+
if (def.collection) collectionOf.set(def.name, def.collection);
|
|
219
|
+
}
|
|
220
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
221
|
+
for (const [name, policies] of entityAccessTable(schema)) {
|
|
222
|
+
const key = collectionOf.get(name) ?? name.toLowerCase();
|
|
223
|
+
if (!byKey.has(key) && isDeclared(policies)) byKey.set(key, policies);
|
|
224
|
+
}
|
|
225
|
+
return byKey;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/mock/identityOwners.ts
|
|
229
|
+
function inlineEntities2(schema) {
|
|
183
230
|
const out = [];
|
|
184
231
|
for (const orbital of schema.orbitals ?? []) {
|
|
232
|
+
const refs = [orbital.entity, ...orbital.auxiliaryEntities ?? []];
|
|
233
|
+
for (const ref of refs) {
|
|
234
|
+
if (typeof ref === "object" && ref !== null && "fields" in ref) {
|
|
235
|
+
out.push(ref);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return out;
|
|
240
|
+
}
|
|
241
|
+
function identityEntitiesTaggedOf(orbitals) {
|
|
242
|
+
const out = [];
|
|
243
|
+
for (const orbital of orbitals) {
|
|
185
244
|
const ref = orbital.entity;
|
|
186
245
|
if (typeof ref === "object" && ref !== null && "fields" in ref && ref.identity === true) {
|
|
187
246
|
out.push({ def: ref, primary: true });
|
|
188
247
|
}
|
|
189
248
|
}
|
|
190
|
-
for (const orbital of
|
|
249
|
+
for (const orbital of orbitals) {
|
|
191
250
|
for (const ref of orbital.auxiliaryEntities ?? []) {
|
|
192
251
|
if (typeof ref === "object" && ref !== null && "fields" in ref && ref.identity === true) {
|
|
193
252
|
out.push({ def: ref, primary: false });
|
|
@@ -196,26 +255,74 @@ function identityEntitiesTagged(schema) {
|
|
|
196
255
|
}
|
|
197
256
|
return out;
|
|
198
257
|
}
|
|
258
|
+
function identityEntitiesOf(orbitals) {
|
|
259
|
+
const tagged = identityEntitiesTaggedOf(orbitals);
|
|
260
|
+
const hasPrimary = tagged.some((e) => e.primary);
|
|
261
|
+
return tagged.filter((e) => e.primary || !hasPrimary).map((e) => e.def);
|
|
262
|
+
}
|
|
199
263
|
function identityEntityName(schema) {
|
|
200
|
-
|
|
201
|
-
return (tagged.find((e) => e.primary) ?? tagged[0])?.def.name;
|
|
264
|
+
return identityEntitiesOf(schema.orbitals ?? [])[0]?.name;
|
|
202
265
|
}
|
|
203
266
|
function identityEntityNames(schema) {
|
|
204
267
|
const out = [];
|
|
205
|
-
for (const { def } of
|
|
268
|
+
for (const { def } of identityEntitiesTaggedOf(schema.orbitals ?? [])) {
|
|
206
269
|
if (!out.includes(def.name)) out.push(def.name);
|
|
207
270
|
}
|
|
208
271
|
return out;
|
|
209
272
|
}
|
|
273
|
+
function roleVocabularyOf(entity, field = "role") {
|
|
274
|
+
const def = entity.fields.find((f) => f.name === field);
|
|
275
|
+
if (!def) return void 0;
|
|
276
|
+
return fieldVocabulary(def);
|
|
277
|
+
}
|
|
278
|
+
function fieldVocabulary(field) {
|
|
279
|
+
if ("values" in field && field.values && field.values.length > 0) {
|
|
280
|
+
return field.values;
|
|
281
|
+
}
|
|
282
|
+
if ("items" in field && field.items && "values" in field.items && field.items.values && field.items.values.length > 0) {
|
|
283
|
+
return field.items.values;
|
|
284
|
+
}
|
|
285
|
+
return void 0;
|
|
286
|
+
}
|
|
287
|
+
function fieldRefName(x, binding) {
|
|
288
|
+
if (typeof x === "string" && x.startsWith(`${binding}.`)) return x.slice(binding.length + 1);
|
|
289
|
+
if (Array.isArray(x) && x.length === 3 && x[0] === "object/get" && x[1] === binding && typeof x[2] === "string") {
|
|
290
|
+
return x[2];
|
|
291
|
+
}
|
|
292
|
+
return void 0;
|
|
293
|
+
}
|
|
294
|
+
function isFieldRef(x, binding, field) {
|
|
295
|
+
return fieldRefName(x, binding) === field;
|
|
296
|
+
}
|
|
297
|
+
var OWNER_EQ_OPS = ["=", "=="];
|
|
298
|
+
function ownerColumnsFromPolicy(expr, out = []) {
|
|
299
|
+
if (Array.isArray(expr)) {
|
|
300
|
+
if (expr.length === 3) {
|
|
301
|
+
const [op, a, b] = expr;
|
|
302
|
+
if (typeof op === "string" && OWNER_EQ_OPS.includes(op)) {
|
|
303
|
+
const field = isFieldRef(b, "@user", "id") ? fieldRefName(a, "@entity") : isFieldRef(a, "@user", "id") ? fieldRefName(b, "@entity") : void 0;
|
|
304
|
+
if (field !== void 0 && !out.includes(field)) out.push(field);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
for (const item of expr) ownerColumnsFromPolicy(item, out);
|
|
308
|
+
}
|
|
309
|
+
return out;
|
|
310
|
+
}
|
|
311
|
+
function policiesSelfIdentify(policies) {
|
|
312
|
+
if (policies === void 0) return false;
|
|
313
|
+
return [policies.read, policies.create, policies.update, policies.delete].some(
|
|
314
|
+
(expr) => expr !== void 0 && ownerColumnsFromPolicy(expr).includes("id")
|
|
315
|
+
);
|
|
316
|
+
}
|
|
210
317
|
function ownerFieldsFromSchema(schema) {
|
|
211
318
|
const identities = identityEntityNames(schema);
|
|
212
319
|
if (identities.length === 0) return [];
|
|
213
320
|
const out = [];
|
|
214
|
-
const defs =
|
|
321
|
+
const defs = inlineEntities2(schema);
|
|
215
322
|
const declaredByCollection = /* @__PURE__ */ new Map();
|
|
216
323
|
for (const def of defs) {
|
|
217
324
|
for (const field of def.fields ?? []) {
|
|
218
|
-
if (field.name && field.type === "relation" && identities.includes(field.relation.entity)) {
|
|
325
|
+
if (field.name && field.type === "relation" && !field.intrinsic && identities.includes(field.relation.entity)) {
|
|
219
326
|
out.push(`${def.name}.${field.name}`);
|
|
220
327
|
if (def.collection) {
|
|
221
328
|
const cols = declaredByCollection.get(def.collection) ?? [];
|
|
@@ -225,6 +332,23 @@ function ownerFieldsFromSchema(schema) {
|
|
|
225
332
|
}
|
|
226
333
|
}
|
|
227
334
|
}
|
|
335
|
+
for (const name of identities) {
|
|
336
|
+
if (policiesSelfIdentify(entityAccessPolicies(schema, name))) {
|
|
337
|
+
const key = `${name}.id`;
|
|
338
|
+
if (!out.includes(key)) out.push(key);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
for (const def of defs) {
|
|
342
|
+
const policies = entityAccessPolicies(schema, def.name);
|
|
343
|
+
if (policies === void 0) continue;
|
|
344
|
+
for (const policy of [policies.read, policies.update, policies.delete]) {
|
|
345
|
+
if (policy === void 0) continue;
|
|
346
|
+
for (const field of ownerColumnsFromPolicy(policy)) {
|
|
347
|
+
const key = `${def.name}.${field}`;
|
|
348
|
+
if (!out.includes(key)) out.push(key);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
228
352
|
for (const def of defs) {
|
|
229
353
|
const cols = def.collection ? declaredByCollection.get(def.collection) : void 0;
|
|
230
354
|
if (!cols) continue;
|
|
@@ -236,64 +360,62 @@ function ownerFieldsFromSchema(schema) {
|
|
|
236
360
|
}
|
|
237
361
|
return out;
|
|
238
362
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const out = [];
|
|
243
|
-
for (const orbital of schema.orbitals ?? []) {
|
|
244
|
-
const refs = [orbital.entity, ...orbital.auxiliaryEntities ?? []];
|
|
245
|
-
for (const ref of refs) {
|
|
246
|
-
if (typeof ref === "object" && ref !== null && "fields" in ref) {
|
|
247
|
-
out.push(ref);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
return out;
|
|
363
|
+
var EQUALITY_OPS = ["=", "==", "!=", "!==", "eq", "neq"];
|
|
364
|
+
function isUserFieldSigil(x) {
|
|
365
|
+
return typeof x === "string" && fieldRefName(x, "@user") !== void 0;
|
|
252
366
|
}
|
|
253
|
-
function
|
|
254
|
-
|
|
367
|
+
function literalHaystackMembers(items) {
|
|
368
|
+
const isListCall = items[0] === "list";
|
|
369
|
+
const members = isListCall ? items.slice(1) : items;
|
|
370
|
+
return members.every((v) => typeof v === "string") ? [...members] : void 0;
|
|
255
371
|
}
|
|
256
|
-
function
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
372
|
+
function collectUserFieldLiterals(expr, out = /* @__PURE__ */ new Map()) {
|
|
373
|
+
if (Array.isArray(expr)) {
|
|
374
|
+
const [op, ...args] = expr;
|
|
375
|
+
if (typeof op === "string" && args.length >= 2 && (EQUALITY_OPS.includes(op) || op === "array/includes")) {
|
|
376
|
+
const isIncludes = op === "array/includes";
|
|
377
|
+
let sigilSide;
|
|
378
|
+
let literalSide;
|
|
379
|
+
if (isIncludes) {
|
|
380
|
+
if (isUserFieldSigil(args[0])) {
|
|
381
|
+
sigilSide = args.slice(0, 1);
|
|
382
|
+
literalSide = args.slice(1, 2);
|
|
383
|
+
} else {
|
|
384
|
+
sigilSide = args.slice(1, 2);
|
|
385
|
+
literalSide = args.slice(0, 1);
|
|
386
|
+
}
|
|
387
|
+
} else {
|
|
388
|
+
sigilSide = args;
|
|
389
|
+
literalSide = args;
|
|
390
|
+
}
|
|
391
|
+
const field = sigilSide.map((arg) => fieldRefName(arg, "@user")).find((f) => f !== void 0);
|
|
392
|
+
if (field !== void 0) {
|
|
393
|
+
const literalArrayHaystack = literalSide[0];
|
|
394
|
+
const literals = isIncludes && Array.isArray(literalArrayHaystack) ? literalHaystackMembers(literalArrayHaystack) ?? [] : literalSide;
|
|
395
|
+
for (const literal of literals) {
|
|
396
|
+
if (typeof literal === "string" && !literal.startsWith("@")) {
|
|
397
|
+
const set = out.get(field) ?? /* @__PURE__ */ new Set();
|
|
398
|
+
set.add(literal);
|
|
399
|
+
out.set(field, set);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
273
403
|
}
|
|
404
|
+
for (const item of expr) collectUserFieldLiterals(item, out);
|
|
405
|
+
return out;
|
|
274
406
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const collection = collectionOf.get(name);
|
|
278
|
-
const inherited = collection ? byCollection.get(collection) : void 0;
|
|
279
|
-
if (inherited) table.set(name, { ...inherited });
|
|
407
|
+
if (expr !== null && typeof expr === "object") {
|
|
408
|
+
for (const value of Object.values(expr)) collectUserFieldLiterals(value, out);
|
|
280
409
|
}
|
|
281
|
-
return
|
|
410
|
+
return out;
|
|
282
411
|
}
|
|
283
|
-
function
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
292
|
-
for (const [name, policies] of entityAccessTable(schema)) {
|
|
293
|
-
const key = collectionOf.get(name) ?? name.toLowerCase();
|
|
294
|
-
if (!byKey.has(key) && isDeclared(policies)) byKey.set(key, policies);
|
|
295
|
-
}
|
|
296
|
-
return byKey;
|
|
412
|
+
function roleSatisfyingPolicy(policy, identity, field = "role") {
|
|
413
|
+
if (policy === void 0 || policy === null) return void 0;
|
|
414
|
+
const vocab = roleVocabularyOf(identity, field);
|
|
415
|
+
if (vocab === void 0) return void 0;
|
|
416
|
+
const accepted = collectUserFieldLiterals(policy).get(field);
|
|
417
|
+
if (accepted === void 0) return void 0;
|
|
418
|
+
return vocab.find((value) => accepted.has(value));
|
|
297
419
|
}
|
|
298
420
|
var ID_PREFIXES = {
|
|
299
421
|
orbital: "orb_",
|
|
@@ -712,6 +834,9 @@ var EntityPersistenceSchema = z.enum([
|
|
|
712
834
|
]);
|
|
713
835
|
z.object({
|
|
714
836
|
name: z.string().min(1, "Entity name is required"),
|
|
837
|
+
// V4 arena id (`EntityDefinition.id`); declared so the strip-mode zod gate
|
|
838
|
+
// carries an imported entity's id through instead of erasing it.
|
|
839
|
+
id: EntityIdSchema.optional(),
|
|
715
840
|
persistence: EntityPersistenceSchema.default("persistent"),
|
|
716
841
|
shared: z.boolean().optional(),
|
|
717
842
|
// Must stay in step with the Rust serde field (`EntityDefinition.identity`,
|
|
@@ -870,6 +995,9 @@ function sampleUnion(field, ctx) {
|
|
|
870
995
|
const child = { ...firstVariant, name: field.name };
|
|
871
996
|
return sampleFieldValue(child, { ...ctx, depth: depth + 1 });
|
|
872
997
|
}
|
|
998
|
+
function omitsUndefaultedOptionalFields(ctx) {
|
|
999
|
+
return ctx.strategy === "seeded" && ctx.index % 2 === 0;
|
|
1000
|
+
}
|
|
873
1001
|
function sampleFieldValue(field, ctx) {
|
|
874
1002
|
const honoredDefault = field.default !== void 0 && isFieldValue(field.default) ? field.default : void 0;
|
|
875
1003
|
if (field.intrinsic === true) return honoredDefault;
|
|
@@ -878,6 +1006,9 @@ function sampleFieldValue(field, ctx) {
|
|
|
878
1006
|
if (!isRuntime && isDeclaredDefaultHonored(field) && honoredDefault !== void 0) {
|
|
879
1007
|
return honoredDefault;
|
|
880
1008
|
}
|
|
1009
|
+
if (!field.required && field.default === void 0 && field.type !== "relation" && omitsUndefaultedOptionalFields(ctx)) {
|
|
1010
|
+
return void 0;
|
|
1011
|
+
}
|
|
881
1012
|
const values = declaredValues(field);
|
|
882
1013
|
if (values) {
|
|
883
1014
|
const ordinal = isRuntime ? 1 : ctx.index;
|
|
@@ -977,6 +1108,6 @@ function sampleRows(entity, count, strategy) {
|
|
|
977
1108
|
return rows;
|
|
978
1109
|
}
|
|
979
1110
|
|
|
980
|
-
export { IMAGE_FIELD_NAMES, entityAccessPolicies, entityAccessPoliciesByStoreKey, entityAccessTable, identityEntityName, isDeclaredDefaultHonored, ownerFieldsFromSchema, randomAnytimeDate, randomArrayElement, randomBoolean, randomColor, randomEmail, randomFloat, randomInt, randomPassword, randomPastDate, randomPhone, randomRecentDate, randomSentence, randomStraddlingDate, randomUrl, randomUuid, randomWords, sampleFieldValue, sampleImageUrl, sampleRow, sampleRowCount, sampleRows, seedRandom, shuffleArray };
|
|
1111
|
+
export { IMAGE_FIELD_NAMES, collectUserFieldLiterals, entityAccessPolicies, entityAccessPoliciesByStoreKey, entityAccessTable, identityEntitiesOf, identityEntityName, identityEntityNames, isDeclaredDefaultHonored, ownerColumnsFromPolicy, ownerFieldsFromSchema, randomAnytimeDate, randomArrayElement, randomBoolean, randomColor, randomEmail, randomFloat, randomInt, randomPassword, randomPastDate, randomPhone, randomRecentDate, randomSentence, randomStraddlingDate, randomUrl, randomUuid, randomWords, roleSatisfyingPolicy, roleVocabularyOf, sampleFieldValue, sampleImageUrl, sampleRow, sampleRowCount, sampleRows, seedRandom, shuffleArray };
|
|
981
1112
|
//# sourceMappingURL=index.js.map
|
|
982
1113
|
//# sourceMappingURL=index.js.map
|