@segmentstream-cloud/ontology 0.6.0 → 0.7.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.
Files changed (43) hide show
  1. package/README.md +14 -3
  2. package/dist/analyze.js +46 -13
  3. package/dist/connection.js +1 -1
  4. package/dist/entity.d.ts +6 -6
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/manifest.d.ts +468 -10
  8. package/dist/manifest.js +46 -6
  9. package/dist/migrate/apply.d.ts +1 -1
  10. package/dist/migrate/apply.js +5 -4
  11. package/dist/migrate/model.d.ts +112 -2
  12. package/dist/migrate/plan.js +7 -6
  13. package/dist/migrate/storage.d.ts +6 -6
  14. package/dist/migrate/storage.js +25 -15
  15. package/dist/names.d.ts +7 -10
  16. package/dist/names.js +10 -13
  17. package/dist/permissions.d.ts +2 -2
  18. package/dist/permissions.js +4 -4
  19. package/dist/query.d.ts +6 -6
  20. package/dist/query.js +41 -30
  21. package/dist/runtime/cursor.js +1 -1
  22. package/dist/runtime/generated-actions.d.ts +4 -4
  23. package/dist/runtime/generated-actions.js +4 -7
  24. package/dist/runtime/history.js +1 -1
  25. package/dist/runtime/model.d.ts +2 -2
  26. package/dist/runtime/model.js +1 -1
  27. package/dist/runtime/principals.js +15 -12
  28. package/dist/runtime/reads.js +1 -1
  29. package/dist/runtime/records.js +1 -1
  30. package/dist/runtime/sql-runtime.js +1 -1
  31. package/dist/service/errors.d.ts +1 -0
  32. package/dist/service/errors.js +5 -1
  33. package/dist/service/handlers.js +2 -2
  34. package/dist/service/runtime-contract.d.ts +1 -1
  35. package/dist/service/schemas.d.ts +201 -26
  36. package/dist/service/schemas.js +30 -21
  37. package/dist/service/service.js +2 -2
  38. package/dist/user.d.ts +3 -3
  39. package/dist/user.js +7 -4
  40. package/dist/warehouse-backed.js +3 -3
  41. package/dist/wire.d.ts +5 -0
  42. package/dist/wire.js +21 -0
  43. package/package.json +1 -1
@@ -42,7 +42,117 @@ export type MigrationRefusal = typeof MigrationRefusal.Type;
42
42
  export declare const MigrationPlan: Schema.Struct<{
43
43
  /** The hash of the applied manifest the plan starts from; absent for a fresh database. */
44
44
  readonly currentHash: Schema.optionalKey<Schema.String>;
45
- readonly target: Schema.Struct<{
45
+ readonly target: Schema.Union<readonly [Schema.encodeKeys<Schema.Struct<{
46
+ readonly entities: Schema.$Array<Schema.encodeKeys<Schema.Struct<{
47
+ readonly properties: Schema.$Array<Schema.encodeKeys<Schema.Struct<{
48
+ readonly column: Schema.optionalKey<Schema.String>;
49
+ readonly scope: Schema.optionalKey<Schema.$Array<Schema.String>>;
50
+ readonly name: Schema.String;
51
+ readonly type: Schema.Literals<readonly ["text", "email", "url", "integer", "number", "boolean", "date", "timestamp", "select", "json"]>;
52
+ readonly label: Schema.String;
53
+ readonly description: Schema.optionalKey<Schema.String>;
54
+ readonly optional: Schema.Boolean;
55
+ readonly unique: Schema.Boolean;
56
+ readonly managed: Schema.Boolean;
57
+ readonly default: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
58
+ readonly display: Schema.optionalKey<Schema.String>;
59
+ readonly renamedFrom: Schema.optionalKey<Schema.String>;
60
+ readonly min: Schema.optionalKey<Schema.Number>;
61
+ readonly max: Schema.optionalKey<Schema.Number>;
62
+ readonly maxLength: Schema.optionalKey<Schema.Number>;
63
+ readonly options: Schema.optionalKey<Schema.$Array<Schema.Struct<{
64
+ readonly value: Schema.String;
65
+ readonly label: Schema.String;
66
+ readonly description: Schema.String;
67
+ }>>>;
68
+ }>, {
69
+ readonly renamedFrom: "renamed_from";
70
+ readonly maxLength: "max_length";
71
+ }>>;
72
+ readonly relationships: Schema.$Array<Schema.encodeKeys<Schema.Struct<{
73
+ readonly on: Schema.optionalKey<Schema.encodeKeys<Schema.Struct<{
74
+ readonly property: Schema.String;
75
+ readonly targetProperty: Schema.String;
76
+ }>, {
77
+ readonly targetProperty: "target_property";
78
+ }>>;
79
+ readonly onDelete: Schema.optionalKey<Schema.decodeTo<Schema.Literals<readonly ["setNull", "cascade", "restrict"]>, Schema.Literals<readonly ["set_null", "cascade", "restrict"]>, never, never>>;
80
+ readonly name: Schema.String;
81
+ readonly to: Schema.String;
82
+ readonly inverse: Schema.String;
83
+ readonly cardinality: Schema.Literals<readonly ["one", "many"]>;
84
+ readonly optional: Schema.optionalKey<Schema.Boolean>;
85
+ readonly ordered: Schema.optionalKey<Schema.Boolean>;
86
+ readonly phrase: Schema.Tuple<readonly [Schema.String, Schema.String]>;
87
+ readonly description: Schema.String;
88
+ }>, {
89
+ readonly onDelete: "on_delete";
90
+ }>>;
91
+ readonly source: Schema.optionalKey<Schema.Struct<{
92
+ readonly asset: Schema.String;
93
+ readonly key: Schema.$Array<Schema.String>;
94
+ readonly currency: Schema.optionalKey<Schema.String>;
95
+ }>>;
96
+ readonly measures: Schema.optionalKey<Schema.$Array<Schema.Struct<{
97
+ readonly name: Schema.String;
98
+ readonly label: Schema.String;
99
+ readonly description: Schema.String;
100
+ readonly unit: Schema.Literals<readonly ["number", "currency", "ratio", "percent"]>;
101
+ readonly format: Schema.Literals<readonly ["decimal", "currency", "percent"]>;
102
+ readonly expression: Schema.Codec<Schema.Json, Schema.Json, never, never>;
103
+ }>>>;
104
+ readonly id: Schema.String;
105
+ readonly name: Schema.String;
106
+ readonly label: Schema.String;
107
+ readonly plural: Schema.String;
108
+ readonly title: Schema.String;
109
+ readonly description: Schema.String;
110
+ readonly builtIn: Schema.Boolean;
111
+ readonly renamedFrom: Schema.optionalKey<Schema.String>;
112
+ readonly guide: Schema.optionalKey<Schema.String>;
113
+ readonly indexes: Schema.$Array<Schema.Struct<{
114
+ readonly properties: Schema.$Array<Schema.String>;
115
+ readonly unique: Schema.Boolean;
116
+ }>>;
117
+ readonly actions: Schema.$Array<Schema.Struct<{
118
+ readonly name: Schema.String;
119
+ readonly description: Schema.String;
120
+ readonly permission: Schema.optionalKey<Schema.String>;
121
+ readonly input: Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>;
122
+ readonly connections: Schema.optionalKey<Schema.$Array<Schema.String>>;
123
+ }>>;
124
+ readonly permissions: Schema.optionalKey<Schema.Struct<{
125
+ readonly read: Schema.String;
126
+ readonly create: Schema.optionalKey<Schema.String>;
127
+ readonly update: Schema.optionalKey<Schema.String>;
128
+ readonly delete: Schema.optionalKey<Schema.String>;
129
+ readonly link: Schema.optionalKey<Schema.String>;
130
+ readonly unlink: Schema.optionalKey<Schema.String>;
131
+ }>>;
132
+ }>, {
133
+ readonly builtIn: "built_in";
134
+ readonly renamedFrom: "renamed_from";
135
+ }>>;
136
+ readonly roles: Schema.$Array<Schema.encodeKeys<Schema.Struct<{
137
+ readonly name: Schema.String;
138
+ readonly description: Schema.String;
139
+ readonly builtIn: Schema.Boolean;
140
+ readonly permissions: Schema.optionalKey<Schema.$Array<Schema.String>>;
141
+ }>, {
142
+ readonly builtIn: "built_in";
143
+ }>>;
144
+ readonly version: Schema.Int;
145
+ readonly hash: Schema.String;
146
+ readonly signIn: Schema.optionalKey<Schema.Struct<{
147
+ readonly policy: Schema.String;
148
+ }>>;
149
+ readonly connections: Schema.optionalKey<Schema.$Array<Schema.Struct<{
150
+ readonly key: Schema.String;
151
+ readonly description: Schema.String;
152
+ }>>>;
153
+ }>, {
154
+ readonly signIn: "sign_in";
155
+ }>, Schema.Struct<{
46
156
  readonly version: Schema.Int;
47
157
  readonly hash: Schema.String;
48
158
  readonly entities: Schema.$Array<Schema.Struct<{
@@ -138,7 +248,7 @@ export declare const MigrationPlan: Schema.Struct<{
138
248
  readonly key: Schema.String;
139
249
  readonly description: Schema.String;
140
250
  }>>>;
141
- }>;
251
+ }>]>;
142
252
  /** Non-transactional steps first, then the steps of the one transaction, in execution order. */
143
253
  readonly steps: Schema.$Array<Schema.Struct<{
144
254
  readonly kind: Schema.Literals<readonly ["createCatalog", "createEntity", "renameEntity", "dropEntities", "addProperty", "renameProperty", "dropProperty", "changeOptional", "changeDefault", "changeCheck", "addSelectOption", "rebuildSelect", "addRelationship", "dropRelationship", "changeOnDelete", "addForeignKey", "addIndex", "dropIndex"]>;
@@ -1,4 +1,4 @@
1
- import { CAMEL_CASE_NAME, SNAKE_CASE_NAME, isSystemProperty } from "../names.js";
1
+ import { SNAKE_CASE_NAME, isSystemProperty } from "../names.js";
2
2
  import { CATALOG_TABLE_DDL, MAX_IDENTIFIER_LENGTH, USER_TABLE, addConstraintStatement, columnDefinition, constraintDefinition, createEnumStatement, createIndexStatement, createTableStatement, defaultExpression, entityStorage, enumTypeName, fieldColumnName, joinTable, propertyCheck, propertyColumn, propertyEnum, quoteIdentifier, quoteLiteral, relationshipColumn, RUNTIME_TABLES_DDL, relationshipForeignKey, SYSTEM_COLUMNS, tableName, } from "./storage.js";
3
3
  const GLOBAL_KINDS = new Set(["table", "type", "index"]);
4
4
  function step(input) {
@@ -158,10 +158,11 @@ function validateEntity(entity, entityNames, invalid) {
158
158
  for (const property of entity.properties) {
159
159
  const path = `${entity.name}.properties.${property.name}`;
160
160
  const values = (property.options ?? []).map((option) => option.value);
161
- if (!CAMEL_CASE_NAME.test(property.name) || isSystemProperty(property.name)) {
162
- invalid(path, "property names are lower camelCase and cannot be system properties.");
161
+ if (!SNAKE_CASE_NAME.test(property.name) || isSystemProperty(property.name)) {
162
+ invalid(path, "property names are lowercase snake_case and cannot be system properties.");
163
163
  }
164
- if (property.type === "select" && (values.length === 0 || values.some((value) => !value))) {
164
+ if (property.type === "select" &&
165
+ (values.length === 0 || values.some((value) => !SNAKE_CASE_NAME.test(value)))) {
165
166
  invalid(path, "a select property needs at least one non-empty option.");
166
167
  }
167
168
  if (new Set(values).size !== values.length) {
@@ -173,8 +174,8 @@ function validateEntity(entity, entityNames, invalid) {
173
174
  }
174
175
  for (const relationship of entity.relationships) {
175
176
  const path = `${entity.name}.relationships.${relationship.name}`;
176
- if (!CAMEL_CASE_NAME.test(relationship.name) || isSystemProperty(relationship.name)) {
177
- invalid(path, "relationship names are lower camelCase and cannot be system properties.");
177
+ if (!SNAKE_CASE_NAME.test(relationship.name) || isSystemProperty(relationship.name)) {
178
+ invalid(path, "relationship names are lowercase snake_case and cannot be system properties.");
178
179
  }
179
180
  if (!entityNames.has(relationship.to)) {
180
181
  invalid(path, `it points at ${relationship.to}, which is not an entity.`);
@@ -12,10 +12,10 @@ export declare const USER_TABLE = "user";
12
12
  /** System properties and their columns, present on every entity table. */
13
13
  export declare const SYSTEM_COLUMNS: {
14
14
  readonly id: "id";
15
- readonly createdAt: "created_at";
16
- readonly updatedAt: "updated_at";
17
- readonly createdBy: "created_by";
18
- readonly updatedBy: "updated_by";
15
+ readonly created_at: "created_at";
16
+ readonly updated_at: "updated_at";
17
+ readonly created_by: "created_by";
18
+ readonly updated_by: "updated_by";
19
19
  };
20
20
  /** The kinds of change a history row records. */
21
21
  export declare const HISTORY_KINDS: readonly ["create", "update", "delete", "link", "unlink"];
@@ -85,7 +85,7 @@ export interface EntityStorage {
85
85
  export declare function quoteIdentifier(name: string): string;
86
86
  /** `'value'`, with embedded quotes doubled (standard_conforming_strings is on). */
87
87
  export declare function quoteLiteral(value: string): string;
88
- /** `fitScore` → `fit_score`. Property and relationship names are camelCase, so the mapping is one-to-one. */
88
+ /** `fitScore` → `fit_score`. New property names already use snake_case; conversion remains for historical manifests. */
89
89
  export declare function snakeCase(name: string): string;
90
90
  /** An entity's table is named after the entity: `lead`, `user`. */
91
91
  export declare function tableName(entity: string): string;
@@ -119,7 +119,7 @@ export declare function primaryKeyName(table: string): string;
119
119
  /** An index over columns: `lead` + `status, created_at` → `lead_status_created_at_idx`. */
120
120
  export declare function indexName(table: string, columns: ReadonlyArray<string>): string;
121
121
  /**
122
- * The column of an index field: a system property (`createdAt` → `created_at`), a property, or a
122
+ * The column of an index field: a system property (`created_at` → `created_at`), a property, or a
123
123
  * `rel.one` (`owner` → `owner_id`). Returns undefined for anything else.
124
124
  */
125
125
  export declare function fieldColumnName(entity: EntityManifest, field: string): string | undefined;
@@ -11,10 +11,10 @@ export const USER_TABLE = "user";
11
11
  /** System properties and their columns, present on every entity table. */
12
12
  export const SYSTEM_COLUMNS = {
13
13
  id: "id",
14
- createdAt: "created_at",
15
- updatedAt: "updated_at",
16
- createdBy: "created_by",
17
- updatedBy: "updated_by",
14
+ created_at: "created_at",
15
+ updated_at: "updated_at",
16
+ created_by: "created_by",
17
+ updated_by: "updated_by",
18
18
  };
19
19
  /** The kinds of change a history row records. */
20
20
  export const HISTORY_KINDS = ["create", "update", "delete", "link", "unlink"];
@@ -43,7 +43,7 @@ export function quoteIdentifier(name) {
43
43
  export function quoteLiteral(value) {
44
44
  return `'${value.replaceAll("'", "''")}'`;
45
45
  }
46
- /** `fitScore` → `fit_score`. Property and relationship names are camelCase, so the mapping is one-to-one. */
46
+ /** `fitScore` → `fit_score`. New property names already use snake_case; conversion remains for historical manifests. */
47
47
  export function snakeCase(name) {
48
48
  return name.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
49
49
  }
@@ -100,10 +100,20 @@ export function indexName(table, columns) {
100
100
  return `${table}_${columns.join("_")}_idx`;
101
101
  }
102
102
  /**
103
- * The column of an index field: a system property (`createdAt` → `created_at`), a property, or a
103
+ * The column of an index field: a system property (`created_at` → `created_at`), a property, or a
104
104
  * `rel.one` (`owner` → `owner_id`). Returns undefined for anything else.
105
105
  */
106
106
  export function fieldColumnName(entity, field) {
107
+ // Applied manifests may still name system fields in camelCase.
108
+ const historical = {
109
+ createdAt: "created_at",
110
+ updatedAt: "updated_at",
111
+ createdBy: "created_by",
112
+ updatedBy: "updated_by",
113
+ };
114
+ if (Object.hasOwn(historical, field)) {
115
+ return historical[field];
116
+ }
107
117
  if (Object.hasOwn(SYSTEM_COLUMNS, field)) {
108
118
  return SYSTEM_COLUMNS[field];
109
119
  }
@@ -228,8 +238,8 @@ export function joinTable(entity, relationship) {
228
238
  columns: [
229
239
  { name: keys.source, type: "uuid", notNull: true },
230
240
  { name: keys.target, type: "uuid", notNull: true },
231
- { name: SYSTEM_COLUMNS.createdAt, type: "timestamptz", notNull: true, default: "now()" },
232
- { name: SYSTEM_COLUMNS.createdBy, type: "uuid", notNull: false },
241
+ { name: SYSTEM_COLUMNS.created_at, type: "timestamptz", notNull: true, default: "now()" },
242
+ { name: SYSTEM_COLUMNS.created_by, type: "uuid", notNull: false },
233
243
  ],
234
244
  primaryKey: { name: primaryKeyName(name), columns: [keys.source, keys.target] },
235
245
  constraints: [
@@ -253,7 +263,7 @@ export function joinTable(entity, relationship) {
253
263
  }),
254
264
  references: tableName(relationship.to),
255
265
  },
256
- userReference(name, SYSTEM_COLUMNS.createdBy),
266
+ userReference(name, SYSTEM_COLUMNS.created_by),
257
267
  ],
258
268
  indexes: [
259
269
  {
@@ -311,10 +321,10 @@ export function historyTable(entity) {
311
321
  function systemColumns() {
312
322
  return [
313
323
  { name: SYSTEM_COLUMNS.id, type: "uuid", notNull: true, default: "gen_random_uuid()" },
314
- { name: SYSTEM_COLUMNS.createdAt, type: "timestamptz", notNull: true, default: "now()" },
315
- { name: SYSTEM_COLUMNS.updatedAt, type: "timestamptz", notNull: true, default: "now()" },
316
- { name: SYSTEM_COLUMNS.createdBy, type: "uuid", notNull: false },
317
- { name: SYSTEM_COLUMNS.updatedBy, type: "uuid", notNull: false },
324
+ { name: SYSTEM_COLUMNS.created_at, type: "timestamptz", notNull: true, default: "now()" },
325
+ { name: SYSTEM_COLUMNS.updated_at, type: "timestamptz", notNull: true, default: "now()" },
326
+ { name: SYSTEM_COLUMNS.created_by, type: "uuid", notNull: false },
327
+ { name: SYSTEM_COLUMNS.updated_by, type: "uuid", notNull: false },
318
328
  ];
319
329
  }
320
330
  /**
@@ -376,8 +386,8 @@ export function entityStorage(entity) {
376
386
  ],
377
387
  primaryKey: { name: primaryKeyName(table), columns: [SYSTEM_COLUMNS.id] },
378
388
  constraints: [
379
- userReference(table, SYSTEM_COLUMNS.createdBy),
380
- userReference(table, SYSTEM_COLUMNS.updatedBy),
389
+ userReference(table, SYSTEM_COLUMNS.created_by),
390
+ userReference(table, SYSTEM_COLUMNS.updated_by),
381
391
  ...checks,
382
392
  ...ones.map((relationship) => relationshipForeignKey(entity.name, relationship)),
383
393
  ],
package/dist/names.d.ts CHANGED
@@ -1,19 +1,16 @@
1
- /** Entity and role names: lowercase snake_case. They become table names and API path segments. */
1
+ /** Ontology names: lowercase snake_case. */
2
2
  export declare const SNAKE_CASE_NAME: RegExp;
3
- /**
4
- * Property, relationship and action names: lower camelCase, as the API and the TypeScript records spell
5
- * them. Each one maps to exactly one snake_case column name.
6
- */
7
- export declare const CAMEL_CASE_NAME: RegExp;
3
+ /** Historical property names accepted only as explicit rename sources. */
4
+ export declare const LEGACY_MEMBER_NAME: RegExp;
8
5
  /** Stable entity identities, for example `ent_01J9Q4M8ZK`. */
9
6
  export declare const ENTITY_ID: RegExp;
10
7
  /** Properties every entity has. They are never declared and cannot be redeclared. */
11
- export declare const SYSTEM_PROPERTIES: readonly ["id", "createdAt", "updatedAt", "createdBy", "updatedBy"];
8
+ export declare const SYSTEM_PROPERTIES: readonly ["id", "created_at", "updated_at", "created_by", "updated_by"];
12
9
  export type SystemProperty = (typeof SYSTEM_PROPERTIES)[number];
13
10
  /** Actions the platform generates for every entity; authored actions cannot use these names. */
14
11
  export declare const GENERATED_ACTIONS: readonly ["create", "update", "delete", "link", "unlink"];
15
- /** Prefix of the generated `upsertBy<Property>` actions. */
16
- export declare const GENERATED_UPSERT_PREFIX = "upsertBy";
12
+ /** Prefix of the generated `upsert_by_<property>` actions. */
13
+ export declare const GENERATED_UPSERT_PREFIX = "upsert_by_";
17
14
  /** The built-in role every active app user holds. */
18
15
  export declare const MEMBER_ROLE = "member";
19
16
  /** Suffix reserved for the history table each entity gets. */
@@ -25,5 +22,5 @@ export declare const RESERVED_ENTITY_NAMES: readonly ["graph", "status", "descri
25
22
  /** `/api/ontology/<entity>/{id}/history`, which a relationship's traversal would shadow. */
26
23
  export declare const RESERVED_RELATIONSHIP_NAMES: readonly ["history"];
27
24
  export declare function isSystemProperty(name: string): boolean;
28
- /** `createdAt` → `Created at`, `pilot_request` → `Pilot request`. */
25
+ /** `created_at` → `Created at`, `pilot_request` → `Pilot request`. */
29
26
  export declare function humanize(name: string): string;
package/dist/names.js CHANGED
@@ -1,24 +1,21 @@
1
- /** Entity and role names: lowercase snake_case. They become table names and API path segments. */
1
+ /** Ontology names: lowercase snake_case. */
2
2
  export const SNAKE_CASE_NAME = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;
3
- /**
4
- * Property, relationship and action names: lower camelCase, as the API and the TypeScript records spell
5
- * them. Each one maps to exactly one snake_case column name.
6
- */
7
- export const CAMEL_CASE_NAME = /^[a-z][a-zA-Z0-9]*$/;
3
+ /** Historical property names accepted only as explicit rename sources. */
4
+ export const LEGACY_MEMBER_NAME = /^(?:[a-z][a-zA-Z0-9]*|[a-z][a-z0-9]*(?:_[a-z0-9]+)*)$/;
8
5
  /** Stable entity identities, for example `ent_01J9Q4M8ZK`. */
9
6
  export const ENTITY_ID = /^ent_[A-Za-z0-9_]+$/;
10
7
  /** Properties every entity has. They are never declared and cannot be redeclared. */
11
8
  export const SYSTEM_PROPERTIES = [
12
9
  "id",
13
- "createdAt",
14
- "updatedAt",
15
- "createdBy",
16
- "updatedBy",
10
+ "created_at",
11
+ "updated_at",
12
+ "created_by",
13
+ "updated_by",
17
14
  ];
18
15
  /** Actions the platform generates for every entity; authored actions cannot use these names. */
19
16
  export const GENERATED_ACTIONS = ["create", "update", "delete", "link", "unlink"];
20
- /** Prefix of the generated `upsertBy<Property>` actions. */
21
- export const GENERATED_UPSERT_PREFIX = "upsertBy";
17
+ /** Prefix of the generated `upsert_by_<property>` actions. */
18
+ export const GENERATED_UPSERT_PREFIX = "upsert_by_";
22
19
  /** The built-in role every active app user holds. */
23
20
  export const MEMBER_ROLE = "member";
24
21
  /** Suffix reserved for the history table each entity gets. */
@@ -39,7 +36,7 @@ export const RESERVED_RELATIONSHIP_NAMES = ["history"];
39
36
  export function isSystemProperty(name) {
40
37
  return SYSTEM_PROPERTIES.includes(name);
41
38
  }
42
- /** `createdAt` → `Created at`, `pilot_request` → `Pilot request`. */
39
+ /** `created_at` → `Created at`, `pilot_request` → `Pilot request`. */
43
40
  export function humanize(name) {
44
41
  const words = name
45
42
  .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Permissions are `<entity>:<verb>` strings. The verbs are `read`, the generated `create`, `update`,
3
- * `delete`, `link` and `unlink`, and the camelCase name of an authored action. A role may use `*` for
3
+ * `delete`, `link` and `unlink`, and the snake_case name of an authored action. A role may use `*` for
4
4
  * the entity (`*:read`), the verb (`lead:*`) or both (`*:*`); what an action or a read requires never
5
5
  * holds a wildcard.
6
6
  */
@@ -34,7 +34,7 @@ export declare function isAllowed(required: string, principal: PermissionHolder)
34
34
  /** The first of the required permissions the principal lacks, or `undefined` when it holds all. */
35
35
  export declare function missingPermission(required: ReadonlyArray<string>, principal: PermissionHolder): string | undefined;
36
36
  /**
37
- * What a generated action requires: `<entity>:<action>`, except `upsertBy<Property>`, which may
37
+ * What a generated action requires: `<entity>:<action>`, except `upsert_by_<property>`, which may
38
38
  * create or update and so requires both `<entity>:create` and `<entity>:update`.
39
39
  */
40
40
  export declare function generatedActionPermissions(entity: string, action: string): ReadonlyArray<string>;
@@ -1,7 +1,7 @@
1
1
  import { GENERATED_UPSERT_PREFIX } from "./names.js";
2
2
  /**
3
3
  * Permissions are `<entity>:<verb>` strings. The verbs are `read`, the generated `create`, `update`,
4
- * `delete`, `link` and `unlink`, and the camelCase name of an authored action. A role may use `*` for
4
+ * `delete`, `link` and `unlink`, and the snake_case name of an authored action. A role may use `*` for
5
5
  * the entity (`*:read`), the verb (`lead:*`) or both (`*:*`); what an action or a read requires never
6
6
  * holds a wildcard.
7
7
  */
@@ -11,8 +11,8 @@ export const WILDCARD = "*";
11
11
  export const READ_VERB = "read";
12
12
  /** What the built-in `member` role holds when `defineOntology` does not say: reading everything. */
13
13
  export const DEFAULT_MEMBER_PERMISSIONS = [`${WILDCARD}:${READ_VERB}`];
14
- /** `<entity>:<verb>` with lowercase snake_case entities and lower camelCase verbs, or `*` for either. */
15
- const PERMISSION = /^(\*|[a-z][a-z0-9]*(?:_[a-z0-9]+)*):(\*|[a-z][a-zA-Z0-9]*)$/;
14
+ /** `<entity>:<verb>` with lowercase snake_case entities and lowercase snake_case verbs, or `*` for either. */
15
+ const PERMISSION = /^(\*|[a-z][a-z0-9]*(?:_[a-z0-9]+)*):(\*|[a-z][a-z0-9]*(?:_[a-z0-9]+)*)$/;
16
16
  /** The entity and verb of a permission, or `undefined` when the value is not one. */
17
17
  export function parsePermission(value) {
18
18
  if (typeof value !== "string") {
@@ -47,7 +47,7 @@ export function missingPermission(required, principal) {
47
47
  return required.find((permission) => !isAllowed(permission, principal));
48
48
  }
49
49
  /**
50
- * What a generated action requires: `<entity>:<action>`, except `upsertBy<Property>`, which may
50
+ * What a generated action requires: `<entity>:<action>`, except `upsert_by_<property>`, which may
51
51
  * create or update and so requires both `<entity>:create` and `<entity>:update`.
52
52
  */
53
53
  export function generatedActionPermissions(entity, action) {
package/dist/query.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Schema } from "effect";
2
2
  import type { JsonSchemaObject } from "./analyze.js";
3
3
  import type { EntityManifest, OntologyManifest } from "./manifest.js";
4
4
  import type { PropertyType } from "./property.js";
5
- /** How a record field is stored: a property type, or a UUID for ids and `<relationship>Id` keys. */
5
+ /** How a record field is stored: a property type, or a UUID for ids and `<relationship>_id` keys. */
6
6
  export type StorageType = PropertyType | "uuid";
7
7
  /**
8
8
  * The query language of `find` and of the HTTP API's list and query endpoints.
@@ -15,7 +15,7 @@ export type StorageType = PropertyType | "uuid";
15
15
  * "tags": { "some": { "name": { "eq": "priority" } } },
16
16
  * "or": [{ "fitScore": { "gte": 80 } }, { "source": "pilot_request" }]
17
17
  * },
18
- * "orderBy": [{ "field": "createdAt", "direction": "desc" }],
18
+ * "orderBy": [{ "field": "created_at", "direction": "desc" }],
19
19
  * "include": { "owner": true },
20
20
  * "limit": 50
21
21
  * }
@@ -114,7 +114,7 @@ export declare function queryResultSchema<S extends Schema.Top>(record: S): Sche
114
114
  readonly items: Schema.$Array<S>;
115
115
  readonly nextCursor: Schema.NullOr<Schema.String>;
116
116
  }>;
117
- /** A field a query can filter and sort on: a system field, a property, or a `<relationship>Id`. */
117
+ /** A field a query can filter and sort on: a system field, a property, or a `<relationship>_id`. */
118
118
  export interface QueryField {
119
119
  readonly name: string;
120
120
  readonly storage: StorageType;
@@ -170,12 +170,12 @@ export interface EntityQuerySchemas {
170
170
  * include. Every struct is closed: an unknown field, operator or key is an issue whatever the parse
171
171
  * options, never a silently ignored filter.
172
172
  */
173
- export declare function entityQuerySchemas(manifest: OntologyManifest, entityName: string): EntityQuerySchemas;
173
+ export declare function entityQuerySchemas(manifest: OntologyManifest, entityName: string, wire?: boolean): EntityQuerySchemas;
174
174
  /** The query schema of one entity; see {@link entityQuerySchemas}. */
175
175
  export declare function entityQuerySchema(manifest: OntologyManifest, entityName: string): Schema.Codec<Query>;
176
176
  /**
177
177
  * The record of an entity as the runtime returns it: system fields, properties (`null` when empty;
178
- * dates as `YYYY-MM-DD`, timestamps as ISO 8601 in UTC) and a `<relationship>Id` per `rel.one`. It
178
+ * dates as `YYYY-MM-DD`, timestamps as ISO 8601 in UTC) and a `<relationship>_id` per `rel.one`. It
179
179
  * checks the shape of stored values, not the refinements of the definition (`maxLength`, `min`,
180
180
  * patterns), so that tightening a refinement never makes existing records unreadable.
181
181
  */
@@ -185,7 +185,7 @@ export type JsonRecord = {
185
185
  readonly [field: string]: Schema.Json;
186
186
  };
187
187
  /** A page of an entity's records, with the relationships a query may include. */
188
- export declare function entityQueryResultSchema(manifest: OntologyManifest, entityName: string): Schema.Codec<QueryResult<JsonRecord>>;
188
+ export declare function entityQueryResultSchema(manifest: OntologyManifest, entityName: string, wire?: boolean): Schema.Codec<QueryResult<JsonRecord>, unknown>;
189
189
  /** The JSON Schema (draft 2020-12) of an entity's queries, for MCP tools, OpenAPI and the console. */
190
190
  export declare function queryJsonSchema(manifest: OntologyManifest, entityName: string): JsonSchemaObject;
191
191
  /** The JSON Schema (draft 2020-12) of a page of an entity's records. */