@drhomet/mithaq 0.1.1 → 0.2.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/LICENSES/openstatus-time-picker.txt +21 -0
- package/README.md +161 -0
- package/dist/asas/build.d.ts +10 -2
- package/dist/asas/build.js +69 -22
- package/dist/asas/cli/mithaq.js +35 -3
- package/dist/asas/cli/upgrade.d.ts +22 -9
- package/dist/asas/cli/upgrade.js +187 -78
- package/dist/asas/http/fetch.d.ts +21 -3
- package/dist/asas/http/fetch.js +123 -60
- package/dist/asas/http/orpc.d.ts +5 -3
- package/dist/asas/http/orpc.js +126 -108
- package/dist/asas/runner/bulk.d.ts +1 -1
- package/dist/asas/runner/bulk.js +16 -11
- package/dist/asas/runner/errors.d.ts +5 -2
- package/dist/asas/runner/errors.js +18 -2
- package/dist/asas/runner/read.d.ts +6 -2
- package/dist/asas/runner/read.js +28 -6
- package/dist/asas/runner/steps.d.ts +22 -4
- package/dist/asas/runner/steps.js +15 -9
- package/dist/asas/runner/store.d.ts +4 -0
- package/dist/asas/runner/store.js +21 -0
- package/dist/asas/runner/tenant.d.ts +2 -2
- package/dist/asas/runner/tenant.js +78 -16
- package/dist/asas/runner/write.d.ts +173 -11
- package/dist/asas/runner/write.js +274 -46
- package/dist/auth/better-auth/access.d.ts +14 -0
- package/dist/auth/better-auth/access.js +32 -0
- package/dist/auth/better-auth/generate.d.ts +3 -1
- package/dist/auth/better-auth/generate.js +26 -8
- package/dist/auth/better-auth/index.d.ts +2 -0
- package/dist/auth/better-auth/tenant.d.ts +11 -3
- package/dist/auth/better-auth/tenant.js +10 -2
- package/dist/auth/local/index.js +5 -3
- package/dist/base/fields.d.ts +3 -2
- package/dist/base/fields.js +3 -2
- package/dist/base/index.d.ts +2 -1
- package/dist/base/json-schema.d.ts +7 -0
- package/dist/base/json-schema.js +35 -0
- package/dist/base/kinds.d.ts +21 -0
- package/dist/base/kinds.js +46 -1
- package/dist/base/rules.d.ts +4 -4
- package/dist/base/rules.js +4 -3
- package/dist/drizzle/index.d.ts +9 -139
- package/dist/drizzle/index.js +143 -24
- package/dist/drizzle/kinds.d.ts +1 -0
- package/dist/drizzle/kinds.js +3 -1
- package/dist/drizzle/migrate.d.ts +26 -0
- package/dist/drizzle/migrate.js +69 -26
- package/dist/drizzle/rules.d.ts +1 -1
- package/dist/index.d.ts +11 -21
- package/dist/index.js +8 -18
- package/dist/mithaq/define.d.ts +62 -15
- package/dist/mithaq/define.js +23 -9
- package/dist/mithaq/generate-messages.js +5 -4
- package/dist/mithaq/language.d.ts +43 -4
- package/dist/mithaq/message-file.d.ts +13 -0
- package/dist/mithaq/message-file.js +29 -0
- package/dist/mithaq/messages.js +5 -0
- package/dist/mithaq/resolve.js +70 -10
- package/dist/mithaq/types.d.ts +29 -1
- package/dist/rbac/index.d.ts +2 -2
- package/dist/rbac/index.js +1 -1
- package/dist/rich-text/index.d.ts +1 -0
- package/dist/rich-text/index.js +1 -0
- package/dist/rich-text/rich-text.d.ts +2 -55
- package/dist/rich-text/rich-text.js +2 -125
- package/dist/rich-text/value.d.ts +55 -0
- package/dist/rich-text/value.js +126 -0
- package/dist/screen/client.d.ts +5 -2
- package/dist/screen/client.js +5 -2
- package/dist/screen/generate.js +48 -6
- package/dist/screen/index.d.ts +18 -1
- package/dist/screen/index.js +24 -6
- package/dist/screen/react.d.ts +2 -0
- package/dist/storage/index.d.ts +2 -3
- package/dist/storage/index.js +1 -2
- package/dist/storage/storage.d.ts +2 -0
- package/dist/storage/storage.js +9 -2
- package/dist/targets.d.ts +14 -0
- package/dist/targets.js +16 -0
- package/dist/vite.d.ts +7 -0
- package/dist/vite.js +81 -0
- package/dist/zod/index.d.ts +12 -3
- package/dist/zod/index.js +6 -5
- package/dist/zod/kinds.d.ts +3 -1
- package/dist/zod/kinds.js +11 -2
- package/dist/zod/rules.d.ts +1 -1
- package/docs/packages/mithaq/README.md +962 -0
- package/docs/packages/mithaq/src/asas/cli/README.md +252 -0
- package/docs/packages/mithaq/src/asas/runner/README.md +472 -0
- package/docs/packages/mithaq/src/drizzle/README.md +39 -0
- package/docs/packages/mithaq-admin/README.md +312 -0
- package/docs/templates/asas/README.md +1056 -0
- package/package.json +37 -8
- package/skills/add-field/SKILL.md +27 -0
- package/skills/add-kayan/SKILL.md +26 -0
- package/skills/eject-admin-piece/SKILL.md +28 -0
- package/skills/upgrade-mithaq/SKILL.md +35 -0
- package/r/mithaq-cells.json +0 -20
- package/r/mithaq-controls.json +0 -37
- package/r/mithaq-directional-icon.json +0 -15
- package/r/mithaq-expected-updated-at.json +0 -15
- package/r/mithaq-field-shell.json +0 -18
- package/r/mithaq-filter-operators.json +0 -15
- package/r/mithaq-form.json +0 -33
- package/r/mithaq-list-columns.json +0 -23
- package/r/mithaq-list-filters.json +0 -24
- package/r/mithaq-list-pagination.json +0 -24
- package/r/mithaq-list-query.json +0 -18
- package/r/mithaq-list-selection.json +0 -19
- package/r/mithaq-list.json +0 -33
- package/r/mithaq-nav.json +0 -24
- package/r/mithaq-nodes.json +0 -34
- package/r/mithaq-relationship-cell.json +0 -20
- package/r/mithaq-relationship-control.json +0 -20
- package/r/mithaq-rich-text.json +0 -40
- package/r/mithaq-screens-host.json +0 -96
- package/r/mithaq-storage.json +0 -44
- package/r/mithaq-upload.json +0 -29
- package/r/registry.json +0 -550
package/dist/drizzle/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { and, asc, count as sqlCount, desc, eq, getTableColumns, getTableName, gt, gte, ilike, inArray, isNotNull, isNull, lt, lte, ne, notInArray, or, sql } from 'drizzle-orm';
|
|
1
|
+
import { and, asc, count as sqlCount, sum as sqlSum, desc, eq, getTableColumns, getTableName, gt, gte, ilike, inArray, isNotNull, isNull, lt, lte, ne, notInArray, or, sql } from 'drizzle-orm';
|
|
2
2
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
3
3
|
import { boolean as pgBoolean, index, integer as pgInteger, isPgEnum, jsonb, timestamp, uuid as pgUuid, pgEnum, pgSchema, pgTable, primaryKey, unique as uniqueConstraint, uniqueIndex, } from 'drizzle-orm/pg-core';
|
|
4
4
|
import { isPlainIdentifier, snakeCase, uniqueRuleIndexes, versionsTableOf } from '../mithaq/resolve.js';
|
|
5
5
|
import { implementationOf } from '../mithaq/rukn.js';
|
|
6
|
-
import { conflict, localizedQuery } from '../asas/runner/errors.js';
|
|
6
|
+
import { conflict, invalid, missing, localizedQuery } from '../asas/runner/errors.js';
|
|
7
7
|
import { Refusal } from '../mithaq/refusal.js';
|
|
8
8
|
import { providerOf } from '../base/rules.js';
|
|
9
|
-
import {
|
|
10
|
-
import { rules as drizzleRules } from './rules.js';
|
|
9
|
+
import { kinds as drizzleKinds } from './kinds.js';
|
|
11
10
|
const modifiable = (column) => {
|
|
12
11
|
for (const method of ['default', 'notNull', 'primaryKey', 'unique']) {
|
|
13
12
|
if (typeof Reflect.get(column, method) !== 'function') {
|
|
@@ -49,11 +48,13 @@ const refusedSchema = (name) => typeof name !== 'string' || !isPlainIdentifier(n
|
|
|
49
48
|
// A plain `Error`: what reaches here is a `where` an access callback returned, the
|
|
50
49
|
// project's own bug; the read layer refuses a caller's first.
|
|
51
50
|
const refuseLocalized = (kayan, field, what, locales) => new Error(localizedQuery({ kayan, field, what, locales }));
|
|
52
|
-
// Postgres answers `23503`,
|
|
53
|
-
// row, never which row. Read by schema too: another
|
|
51
|
+
// Postgres answers `23503`, or from 18 on `23001` for an `ON DELETE RESTRICT` key, refused as a
|
|
52
|
+
// conflict naming which kayan points at the row, never which row. Read by schema too: another
|
|
53
|
+
// tool may share a table name.
|
|
54
|
+
const pointedAt = new Set(['23503', '23001']);
|
|
54
55
|
const referenced = ({ thrown, name, kayans, tables }) => {
|
|
55
56
|
const held = thrown;
|
|
56
|
-
const error = held?.code
|
|
57
|
+
const error = pointedAt.has(held?.code) ? held : pointedAt.has(held?.cause?.code) ? held.cause : undefined;
|
|
57
58
|
if (!error)
|
|
58
59
|
return thrown;
|
|
59
60
|
// A kayan's join tables are built in its own table's schema.
|
|
@@ -122,6 +123,47 @@ const conditionsOf = (column, rules) => {
|
|
|
122
123
|
});
|
|
123
124
|
return checks.length === 1 ? checks[0] : and(...checks);
|
|
124
125
|
};
|
|
126
|
+
// Payload's own path, `$[*].a[*].b[*]`: a list at any segment, a list inside a list included, is
|
|
127
|
+
// matched by any of its entries. The path and every value are bound parameters, and each key a
|
|
128
|
+
// quoted jsonpath string, so nothing a caller wrote is read as SQL or jsonpath.
|
|
129
|
+
const jsonConditionsOf = (column, path, rules) => {
|
|
130
|
+
const at = `$[*]${path.map((key) => `.${JSON.stringify(key)}[*]`).join('')}`;
|
|
131
|
+
const some = (test) => sql `exists (select 1 from jsonb_path_query(${column}, ${at}::jsonpath) as item(value) where ${test})`;
|
|
132
|
+
// A JSON `null` is no value, as a SQL `NULL` is: `exists` and `equals: null` read both alike.
|
|
133
|
+
const present = some(sql `item.value <> 'null'::jsonb`);
|
|
134
|
+
const text = sql `(item.value #>> '{}')`;
|
|
135
|
+
const equal = (value) => (value === null ? sql `not ${present}` : some(sql `item.value = ${JSON.stringify(value)}::jsonb`));
|
|
136
|
+
// One subquery for the whole list, against a hashed set: one per value, or `= any(array)`, compares
|
|
137
|
+
// every item with every value, which took seconds for a thousand values over 20,000 rows.
|
|
138
|
+
const listed = (value) => {
|
|
139
|
+
const { hasNull, values } = splitNulls(value);
|
|
140
|
+
const hit = values.length ? some(sql `item.value in (select unnest(${sql.param(values.map((one) => JSON.stringify(one)))}::jsonb[]))`) : sql `false`;
|
|
141
|
+
return hasNull ? or(sql `not ${present}`, hit) : hit;
|
|
142
|
+
};
|
|
143
|
+
const checks = Object.entries(rules).map(([operator, value]) => {
|
|
144
|
+
switch (operator) {
|
|
145
|
+
case 'contains':
|
|
146
|
+
return some(ilike(text, pattern(String(value))));
|
|
147
|
+
case 'like': {
|
|
148
|
+
const words = String(value).trim().split(/\s+/).filter(Boolean);
|
|
149
|
+
return words.length ? some(and(...words.map((word) => ilike(text, pattern(word))))) : undefined;
|
|
150
|
+
}
|
|
151
|
+
case 'equals':
|
|
152
|
+
return equal(value);
|
|
153
|
+
case 'not_equals':
|
|
154
|
+
return value === null ? present : and(present, sql `not ${equal(value)}`);
|
|
155
|
+
case 'exists':
|
|
156
|
+
return value ? present : sql `not ${present}`;
|
|
157
|
+
case 'in':
|
|
158
|
+
return listed(value);
|
|
159
|
+
case 'not_in':
|
|
160
|
+
return and(present, sql `not ${listed(value)}`);
|
|
161
|
+
}
|
|
162
|
+
// Unreachable past the kind's operators, but never left out of a `where` that carries an access constraint.
|
|
163
|
+
throw new Error(`Unsupported where operator "${operator}" on a json field.`);
|
|
164
|
+
});
|
|
165
|
+
return checks.length === 1 ? checks[0] : and(...checks);
|
|
166
|
+
};
|
|
125
167
|
const whereOf = (db, tables, kayanByName, name, where) => {
|
|
126
168
|
const table = tables[name];
|
|
127
169
|
const kayan = kayanByName.get(name);
|
|
@@ -135,8 +177,23 @@ const whereOf = (db, tables, kayanByName, name, where) => {
|
|
|
135
177
|
for (const [field, rules] of Object.entries(where)) {
|
|
136
178
|
if (field === 'and' || field === 'or')
|
|
137
179
|
continue;
|
|
138
|
-
const [ownField,
|
|
180
|
+
const [ownField, ...path] = field.split('.');
|
|
181
|
+
const relatedField = path[0];
|
|
139
182
|
const relationField = kayan.fields[ownField];
|
|
183
|
+
if (relationField?.kind === 'json') {
|
|
184
|
+
parts.push(jsonConditionsOf(table[ownField], path, rules));
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
// Whether a versions table's snapshot holds an id in one field, alone or in a set: the delete's
|
|
188
|
+
// reference check asks it, and a caller's read of versions refuses every path before here.
|
|
189
|
+
// Lowered, since a draft keeps a uuid as its writer sent it.
|
|
190
|
+
if (!relationField && ownField === 'version' && relatedField && table.version) {
|
|
191
|
+
const { equals, ...other } = rules;
|
|
192
|
+
if (equals === undefined || Object.keys(other).length)
|
|
193
|
+
throw new Error(`Kayan "${name}" path "${field}" takes equals alone.`);
|
|
194
|
+
parts.push(sql `lower((${table.version} -> ${relatedField})::text)::jsonb @> ${JSON.stringify(typeof equals === 'string' ? equals.toLowerCase() : equals)}::jsonb`);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
140
197
|
// A `hasMany` field has no column here, so the join table is filtered and its
|
|
141
198
|
// parent ids filter this table.
|
|
142
199
|
if (relationField?.hasMany) {
|
|
@@ -279,9 +336,7 @@ export const recordMigration = async ({ db, hash, createdAt, name }) => {
|
|
|
279
336
|
await db.execute(sql `with gone as (delete from ${historyTable} where name = ${devPushMarker})
|
|
280
337
|
insert into ${historyTable} (hash, created_at, name) values (${hash}, ${createdAt}, ${name})`);
|
|
281
338
|
};
|
|
282
|
-
|
|
283
|
-
export const drizzleTarget = { capability: 'store', type: 'drizzle', idKinds: drizzleIdKinds, kinds: drizzleKinds, rules: drizzleRules };
|
|
284
|
-
export const drizzleAdapter = ({ db: ready, connectionString, kinds, rules, idKinds = drizzleIdKinds, push: named, prodMigrations, }) => {
|
|
339
|
+
export const drizzleAdapter = ({ db: ready, connectionString, kinds, rules, idKinds, push: named, prodMigrations, }) => {
|
|
285
340
|
if (prodMigrations && prodMigrations.pending !== 'run' && prodMigrations.pending !== 'refuse') {
|
|
286
341
|
throw new Error(`drizzleAdapter's prodMigrations.pending is 'run' or 'refuse', not ${JSON.stringify(prodMigrations.pending)}.`);
|
|
287
342
|
}
|
|
@@ -361,6 +416,27 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
361
416
|
}
|
|
362
417
|
return flat;
|
|
363
418
|
};
|
|
419
|
+
const declaredData = (name, values) => {
|
|
420
|
+
const described = kayanByName.get(name);
|
|
421
|
+
// A version's fields describe virtual snapshot paths, while core writes the physical snapshot column.
|
|
422
|
+
const fields = described?.fields.parent?.target?.versions?.table === name ? getTableColumns(tables[name]) : described?.fields ?? getTableColumns(tables[name]);
|
|
423
|
+
const field = Object.keys(values).find((key) => !Object.hasOwn(fields, key));
|
|
424
|
+
if (field)
|
|
425
|
+
throw invalid({ message: `Kayan "${name}" declares no field "${field}".`, key: 'error.invalid.value', params: { kayan: name, field } });
|
|
426
|
+
return values;
|
|
427
|
+
};
|
|
428
|
+
const increments = ({ name, values, insert = false }) => {
|
|
429
|
+
const data = { ...declaredData(name, values) };
|
|
430
|
+
for (const [field, value] of Object.entries(data)) {
|
|
431
|
+
if (kayanByName.get(name)?.fields[field]?.kind === 'json' || !value || typeof value !== 'object' || !('$inc' in value))
|
|
432
|
+
continue;
|
|
433
|
+
if (kayanByName.get(name)?.fields[field]?.kind !== 'integer' || !Number.isSafeInteger(value.$inc) || Object.keys(value).length !== 1) {
|
|
434
|
+
throw invalid({ message: `Kayan "${name}" field "${field}" accepts $inc only on an integer field with one safe integer.`, key: 'error.invalid.value', params: { kayan: name, field } });
|
|
435
|
+
}
|
|
436
|
+
data[field] = insert ? value.$inc : sql `${tables[name][field]} + ${value.$inc}`;
|
|
437
|
+
}
|
|
438
|
+
return data;
|
|
439
|
+
};
|
|
364
440
|
// A field whose every locale column is null is one null, which matches the derived row shape.
|
|
365
441
|
const expand = (name, row) => {
|
|
366
442
|
const fields = localizedOf(name);
|
|
@@ -472,7 +548,11 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
472
548
|
throw new Error(`Kayan "${kayan.name}" asks for the schema ${JSON.stringify(kayan.schemaName)}, ${refused} Give the kayan another schemaName.`);
|
|
473
549
|
}
|
|
474
550
|
const built = Object.create(null);
|
|
475
|
-
|
|
551
|
+
// A table reads its own columns first, whichever place the kayan spread the timestamps in.
|
|
552
|
+
// A column never moves in a table that exists: drizzle-kit diffs columns by name.
|
|
553
|
+
const stamp = (field) => field.name === 'createdAt' || field.name === 'updatedAt';
|
|
554
|
+
const declared = Object.values(kayan.fields).flatMap(columnsOfField(kayan.store));
|
|
555
|
+
const columns = [...declared.filter((field) => !stamp(field)), ...declared.filter(stamp)];
|
|
476
556
|
// `pgTable` keys on the field name, so a localized `title` and a plain `titleAr` would
|
|
477
557
|
// both ask for `title_ar` and one field would end with no column.
|
|
478
558
|
const asked = new Set();
|
|
@@ -550,9 +630,9 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
550
630
|
if (tables[name]) {
|
|
551
631
|
throw new Error(`Kayan "${kayan.name}" field "${field.name}" needs the join table "${name}", which is already the table of kayan "${name}". Rename one of the two, or give the kayan a dbName of its own.`);
|
|
552
632
|
}
|
|
553
|
-
// Each end takes the type of the id it points at.
|
|
554
|
-
// the
|
|
555
|
-
const reference = (build, column, target) => modifiable(build({ ...field, name: column, column: `${column}_id`, target, rules: { onDelete
|
|
633
|
+
// Each end takes the type of the id it points at. The parent's end cascades, since the row
|
|
634
|
+
// belongs to its parent; the target's is the field's own `onDelete`.
|
|
635
|
+
const reference = (build, column, target, onDelete) => modifiable(build({ ...field, name: column, column: `${column}_id`, target, rules: { onDelete } }, tables)).notNull();
|
|
556
636
|
// Named, so the check below holds them to the schema's one namespace.
|
|
557
637
|
const key = `${name}_pkey`;
|
|
558
638
|
const targetIndex = `${name}_target_id_index`;
|
|
@@ -564,8 +644,8 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
564
644
|
indexNames.push({ where: `Kayan "${kayan.name}" field "${field.name}" join table ${what}`, kayan: kayan.name, name: named });
|
|
565
645
|
}
|
|
566
646
|
tables[name] = tableIn(schemaOf(tables[kayan.name]))(name, {
|
|
567
|
-
parent: reference(kinds.relationship, 'parent', kayan),
|
|
568
|
-
target: reference(implementationOf({ table: kinds, shipped: drizzleKinds, name: field.kind, own: field.kindTargets, type: 'drizzle' }), 'target', field.target),
|
|
647
|
+
parent: reference(kinds.relationship, 'parent', kayan, 'cascade'),
|
|
648
|
+
target: reference(implementationOf({ table: kinds, shipped: drizzleKinds, name: field.kind, own: field.kindTargets, type: 'drizzle' }), 'target', field.target, field.rules?.onDelete),
|
|
569
649
|
// The only order a set of ids has.
|
|
570
650
|
order: pgInteger('order').notNull(),
|
|
571
651
|
}, (table) => [
|
|
@@ -663,8 +743,7 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
663
743
|
if (!tablesFilter.length)
|
|
664
744
|
return;
|
|
665
745
|
await refuseStrangers({ db, tables, by: 'push' });
|
|
666
|
-
|
|
667
|
-
// are told to leave the import to the runtime.
|
|
746
|
+
(await import('./migrate.js')).holdOwnKit();
|
|
668
747
|
const { pushSchema } = await import(/* webpackIgnore: true */ 'drizzle-kit/api-postgres');
|
|
669
748
|
// `owned`: a column of a table of the language has the type, which makes it the language's own.
|
|
670
749
|
const listed = (values) => sql.join(values.map((value) => sql `${value}`), sql `, `);
|
|
@@ -725,7 +804,7 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
725
804
|
return db.transaction((tx) => run(tx));
|
|
726
805
|
},
|
|
727
806
|
async insert({ tx, kayan: name, data: values }) {
|
|
728
|
-
const { columns, sets } = withoutSets(name, values);
|
|
807
|
+
const { columns, sets } = withoutSets(name, declaredData(name, values));
|
|
729
808
|
let result;
|
|
730
809
|
try {
|
|
731
810
|
result = await tx.insert(tables[name]).values(flatten(name, columns)).returning();
|
|
@@ -741,16 +820,44 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
741
820
|
await writeSets(tx, name, held.id, sets);
|
|
742
821
|
return withSets(tx, name, held);
|
|
743
822
|
},
|
|
823
|
+
async upsert({ tx, kayan: name, on, data: values, where }) {
|
|
824
|
+
if (!tx)
|
|
825
|
+
throw new Error('An upsert requires a transaction.');
|
|
826
|
+
const kayan = kayanByName.get(name);
|
|
827
|
+
const table = tables[name];
|
|
828
|
+
const inserted = withoutSets(name, increments({ name, values, insert: true }));
|
|
829
|
+
const updated = withoutSets(name, increments({ name, values }));
|
|
830
|
+
const set = flatten(name, Object.fromEntries(Object.entries(updated.columns).filter(([field]) => field !== 'id' && field !== kayan.tenant && !on.includes(field))));
|
|
831
|
+
// Even a key-only upsert returns the existing row, without changing its identity.
|
|
832
|
+
if (!Object.keys(set).length)
|
|
833
|
+
set[on[0]] = table[on[0]];
|
|
834
|
+
let result;
|
|
835
|
+
try {
|
|
836
|
+
result = await tx.insert(table).values(flatten(name, inserted.columns)).onConflictDoUpdate({ target: on.map((field) => table[field]), set, setWhere: where ? whereOf(tx, tables, kayanByName, name, where) : undefined }).returning();
|
|
837
|
+
}
|
|
838
|
+
catch (thrown) {
|
|
839
|
+
throw collision(thrown, name);
|
|
840
|
+
}
|
|
841
|
+
if (!Array.isArray(result))
|
|
842
|
+
throw new Error('The drizzle store expected upsert to return rows.');
|
|
843
|
+
const [row] = result;
|
|
844
|
+
if (!row)
|
|
845
|
+
throw missing({ message: `No "${name}" row found.`, key: 'error.not_found.row', params: { kayan: name } });
|
|
846
|
+
const held = expand(name, row);
|
|
847
|
+
await writeSets(tx, name, held.id, inserted.sets);
|
|
848
|
+
return withSets(tx, name, held);
|
|
849
|
+
},
|
|
744
850
|
async update({ tx, kayan: name, id, data: values, where }) {
|
|
745
|
-
const { columns, sets } = withoutSets(name, values);
|
|
851
|
+
const { columns, sets } = withoutSets(name, increments({ name, values }));
|
|
746
852
|
const flat = flatten(name, columns);
|
|
747
853
|
const matched = idWhere(tx, tables, kayanByName, name, id, where);
|
|
748
854
|
let result;
|
|
749
855
|
try {
|
|
750
|
-
// drizzle refuses an empty `set`, so a write naming only sets locks the row instead
|
|
856
|
+
// drizzle refuses an empty `set`, so a write naming only sets locks the row instead, as an UPDATE
|
|
857
|
+
// of no key column would: a stronger lock would deadlock with a write naming the row.
|
|
751
858
|
result = Object.keys(flat).length
|
|
752
859
|
? await tx.update(tables[name]).set(flat).where(matched).returning()
|
|
753
|
-
: await tx.select().from(tables[name]).where(matched).for('update');
|
|
860
|
+
: await tx.select().from(tables[name]).where(matched).for('no key update');
|
|
754
861
|
}
|
|
755
862
|
catch (thrown) {
|
|
756
863
|
throw collision(thrown, name);
|
|
@@ -787,8 +894,12 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
787
894
|
return { ...sets, ...expand(name, row) };
|
|
788
895
|
},
|
|
789
896
|
async find({ kayan: name, args: { limit, lock, page, sort, where }, tx }) {
|
|
897
|
+
if (lock && !tx)
|
|
898
|
+
throw new Error('A locked find requires a transaction.');
|
|
790
899
|
const client = (tx ?? db);
|
|
791
900
|
const table = tables[name];
|
|
901
|
+
if (!Object.hasOwn(kayanByName.get(name)?.fields ?? getTableColumns(table), sort.field))
|
|
902
|
+
throw invalid({ message: `Kayan "${name}" declares no field "${sort.field}".`, key: 'error.invalid.value', params: { kayan: name, field: sort.field } });
|
|
792
903
|
if (kayanByName.get(name)?.fields[sort.field]?.rules?.localized) {
|
|
793
904
|
throw refuseLocalized(name, sort.field, 'sort');
|
|
794
905
|
}
|
|
@@ -805,7 +916,7 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
805
916
|
const offset = limit > 0 ? (page - 1) * limit : 0;
|
|
806
917
|
// `$dynamic()` keeps each branch one type, so drizzle checks `orderBy` against the table.
|
|
807
918
|
const query = client.select().from(table).$dynamic().where(condition);
|
|
808
|
-
const locked = tx && lock
|
|
919
|
+
const locked = tx && lock ? query.for({ update: 'update', noKeyUpdate: 'no key update', share: 'share', keyShare: 'key share' }[lock]) : query;
|
|
809
920
|
const ordered = locked.orderBy(...orderBy).offset(offset);
|
|
810
921
|
const docs = limit > 0 ? await ordered.limit(limit) : await ordered;
|
|
811
922
|
const rows = await client.select({ totalDocs: sqlCount() }).from(table).where(condition);
|
|
@@ -816,6 +927,14 @@ const storeOf = ({ ready, opened, db, connectionString, kinds, rules, idKinds, p
|
|
|
816
927
|
totalDocs: Number(rows[0]?.totalDocs ?? 0),
|
|
817
928
|
};
|
|
818
929
|
},
|
|
930
|
+
async sum({ tx, kayan: name, field, where }) {
|
|
931
|
+
if (!['integer', 'number', 'decimal'].includes(kayanByName.get(name)?.fields[field]?.kind ?? '')) {
|
|
932
|
+
throw invalid({ message: `Kayan "${name}" field "${field}" is not numeric, so it cannot be summed.`, key: 'error.invalid.value', params: { kayan: name, field } });
|
|
933
|
+
}
|
|
934
|
+
const client = (tx ?? db);
|
|
935
|
+
const rows = await client.select({ total: sqlSum(tables[name][field]) }).from(tables[name]).where(where ? whereOf(client, tables, kayanByName, name, where) : undefined);
|
|
936
|
+
return rows[0]?.total ?? '0';
|
|
937
|
+
},
|
|
819
938
|
async count({ kayan: name, args: { where }, tx }) {
|
|
820
939
|
const client = (tx ?? db);
|
|
821
940
|
// The relationship filters use subqueries, so there are no joins to deduplicate.
|
package/dist/drizzle/kinds.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare const kinds: {
|
|
|
22
22
|
datetime: (field: ResolvedField) => import("drizzle-orm/pg-core").PgTimestampBuilder;
|
|
23
23
|
date: (field: ResolvedField) => import("drizzle-orm/pg-core").PgDateStringBuilder;
|
|
24
24
|
join: (field: ResolvedField) => never;
|
|
25
|
+
json: (field: ResolvedField) => import("drizzle-orm/pg-core").PgJsonbBuilder;
|
|
25
26
|
relationship: ColumnBuilder;
|
|
26
27
|
};
|
|
27
28
|
export {};
|
package/dist/drizzle/kinds.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { boolean, date, integer, numeric, serial, text, timestamp, uuid, varchar } from 'drizzle-orm/pg-core';
|
|
1
|
+
import { boolean, date, integer, jsonb, numeric, serial, text, timestamp, uuid, varchar } from 'drizzle-orm/pg-core';
|
|
2
2
|
/** Length is a rule, not a kind: without a maximum a string column is `text`. */
|
|
3
3
|
const string = (field) => typeof field.rules?.maxLength !== 'number'
|
|
4
4
|
? text(field.column)
|
|
@@ -37,5 +37,7 @@ export const kinds = {
|
|
|
37
37
|
join: (field) => {
|
|
38
38
|
throw new Error(`Field "${field.name}" is a join, whose rows are held by kayan "${field.target?.name}", so this store builds no column for it.`);
|
|
39
39
|
},
|
|
40
|
+
// `jsonb`, as Payload's Postgres adapter stores a json field, so either reads what the other wrote.
|
|
41
|
+
json: (field) => jsonb(field.column),
|
|
40
42
|
relationship,
|
|
41
43
|
};
|
|
@@ -1,7 +1,33 @@
|
|
|
1
|
+
import * as modules from 'node:module';
|
|
1
2
|
import { type NodePgDatabase } from 'drizzle-orm/node-postgres';
|
|
2
3
|
import { type ProdMigrations } from './index.ts';
|
|
3
4
|
import type { ResolvedKayan } from '../mithaq/types.ts';
|
|
4
5
|
export declare const binary: string;
|
|
6
|
+
/**
|
|
7
|
+
* Resolves each drizzle-orm import made under `kit` from `from` instead. drizzle-kit imports
|
|
8
|
+
* drizzle-orm without declaring it, so on its own it loads whatever copy the project hoists,
|
|
9
|
+
* such as a 0.45 beside the one the tables were built with, and fails on it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const holdKitOrm: ({ kit, from }: {
|
|
12
|
+
kit: string;
|
|
13
|
+
from: string;
|
|
14
|
+
}) => modules.ModuleHooks;
|
|
15
|
+
/** The drizzle-kit this mithaq installs, and the file its drizzle-orm resolves from. */
|
|
16
|
+
export declare const ownKit: {
|
|
17
|
+
kit: string;
|
|
18
|
+
from: string;
|
|
19
|
+
};
|
|
20
|
+
/** Holds this mithaq's drizzle-kit to its own drizzle-orm in this process, once. */
|
|
21
|
+
export declare const holdOwnKit: () => {};
|
|
22
|
+
/**
|
|
23
|
+
* A module to `--import` that holds `kit`'s drizzle-orm to `from`'s in a child process.
|
|
24
|
+
* ponytail: only the drizzle-kit mithaq starts is held; `drizzle-kit migrate` run by hand beside a
|
|
25
|
+
* second drizzle-orm still loads the hoisted one. Ship a `mithaq` word that applies migrations if that bites.
|
|
26
|
+
*/
|
|
27
|
+
export declare const kitOrm: (held: {
|
|
28
|
+
kit: string;
|
|
29
|
+
from: string;
|
|
30
|
+
}) => string;
|
|
5
31
|
export declare const header = "// Written by `mithaq migrate`. Commit it.";
|
|
6
32
|
/** One `unresolved` item, and one reply in the hints file, are the same shape. */
|
|
7
33
|
type Hint = {
|
package/dist/drizzle/migrate.js
CHANGED
|
@@ -6,8 +6,9 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
6
6
|
}
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import * as modules from 'node:module';
|
|
11
|
+
import { closeSync, existsSync, openSync, readFileSync } from 'node:fs';
|
|
11
12
|
import { mkdir, mkdtemp, readdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
12
13
|
import { tmpdir } from 'node:os';
|
|
13
14
|
import { join, resolve as resolvePath } from 'node:path';
|
|
@@ -22,6 +23,34 @@ import { createHistory, devPushMarker, historyLock, historyTable, joinTableOf, m
|
|
|
22
23
|
// `bin.cjs` is not in drizzle-kit's `exports`, so it is resolved as the root entry's
|
|
23
24
|
// sibling; resolved from this file, so a consumer gets its own `mithaq`'s copy.
|
|
24
25
|
export const binary = fileURLToPath(new URL('bin.cjs', import.meta.resolve('drizzle-kit')));
|
|
26
|
+
/**
|
|
27
|
+
* Resolves each drizzle-orm import made under `kit` from `from` instead. drizzle-kit imports
|
|
28
|
+
* drizzle-orm without declaring it, so on its own it loads whatever copy the project hoists,
|
|
29
|
+
* such as a 0.45 beside the one the tables were built with, and fails on it.
|
|
30
|
+
*/
|
|
31
|
+
export const holdKitOrm = ({ kit, from }) =>
|
|
32
|
+
// Node's alone: a runtime without it resolves as it did.
|
|
33
|
+
modules.registerHooks?.({
|
|
34
|
+
resolve: (specifier, context, next) => {
|
|
35
|
+
if (!/^drizzle-orm($|\/)/.test(specifier) || !context.parentURL?.startsWith(kit))
|
|
36
|
+
return next(specifier, context);
|
|
37
|
+
// A require is resolved from the requiring file whatever parentURL says, so it is resolved here.
|
|
38
|
+
return context.conditions.includes('require')
|
|
39
|
+
? { url: pathToFileURL(modules.createRequire(from).resolve(specifier)).href, shortCircuit: true }
|
|
40
|
+
: next(specifier, { ...context, parentURL: from });
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
/** The drizzle-kit this mithaq installs, and the file its drizzle-orm resolves from. */
|
|
44
|
+
export const ownKit = { kit: new URL('.', import.meta.resolve('drizzle-kit')).href, from: import.meta.url };
|
|
45
|
+
let ownHeld;
|
|
46
|
+
/** Holds this mithaq's drizzle-kit to its own drizzle-orm in this process, once. */
|
|
47
|
+
export const holdOwnKit = () => (ownHeld ??= holdKitOrm(ownKit) ?? true);
|
|
48
|
+
/**
|
|
49
|
+
* A module to `--import` that holds `kit`'s drizzle-orm to `from`'s in a child process.
|
|
50
|
+
* ponytail: only the drizzle-kit mithaq starts is held; `drizzle-kit migrate` run by hand beside a
|
|
51
|
+
* second drizzle-orm still loads the hoisted one. Ship a `mithaq` word that applies migrations if that bites.
|
|
52
|
+
*/
|
|
53
|
+
export const kitOrm = (held) => `data:text/javascript,${encodeURIComponent(`import { holdKitOrm } from ${JSON.stringify(import.meta.url)}\nholdKitOrm(${JSON.stringify(held)})\n`)}`;
|
|
25
54
|
const configName = 'drizzle.config.ts';
|
|
26
55
|
const schemaName = 'schema.ts';
|
|
27
56
|
const hintsName = 'mithaq.hints.json';
|
|
@@ -640,16 +669,19 @@ const moveHistory = async ({ db, directory, check }) => {
|
|
|
640
669
|
order by old.id returning name`);
|
|
641
670
|
console.log(`Copied ${moved.rows.length} ${moved.rows.length === 1 ? 'row' : 'rows'} of this project's history from drizzle.__drizzle_migrations into ${history}, where mithaq keeps it now. The rows in drizzle.__drizzle_migrations are left as they were.`);
|
|
642
671
|
};
|
|
643
|
-
|
|
644
|
-
const unapplied = async ({ db, directory }) => {
|
|
645
|
-
let localMigrations = [];
|
|
672
|
+
const migrationsIn = (directory) => {
|
|
646
673
|
try {
|
|
647
|
-
|
|
674
|
+
return readMigrationFiles({ migrationsFolder: fileURLToPath(directory) });
|
|
648
675
|
}
|
|
649
676
|
catch (error) {
|
|
650
677
|
if (error.code !== 'ENOENT')
|
|
651
678
|
throw error;
|
|
679
|
+
return [];
|
|
652
680
|
}
|
|
681
|
+
};
|
|
682
|
+
// drizzle's own rule, which matches a folder to a row by `name` alone.
|
|
683
|
+
const unapplied = async ({ db, directory }) => {
|
|
684
|
+
const localMigrations = migrationsIn(directory);
|
|
653
685
|
if (!localMigrations.length)
|
|
654
686
|
return [];
|
|
655
687
|
let dbMigrations = [];
|
|
@@ -674,6 +706,10 @@ export const bootMigrations = async ({ db, prodMigrations }) => {
|
|
|
674
706
|
throw new Refusal(`prodMigrations names ${migrationsFolder} as the migrations folder, and under ${process.cwd()} it holds no ${configName}, which every folder \`mithaq migrate\` writes holds, so this boot cannot tell which migrations this database has applied. Ship the folder with the deploy, or name where it is. Nothing was checked or applied.`);
|
|
675
707
|
}
|
|
676
708
|
const directory = pathToFileURL(`${resolvePath(migrationsFolder)}/`);
|
|
709
|
+
// A new project's folder holds the config and no migration, which would read as nothing pending.
|
|
710
|
+
if (!migrationsIn(directory).length) {
|
|
711
|
+
throw new Refusal(`prodMigrations names ${migrationsFolder}, which holds no migration yet, so a production boot would serve a database nothing built. Write the first with \`mithaq migrate --name init\` against an empty database, ship it, and start again. Nothing was checked or applied.`);
|
|
712
|
+
}
|
|
677
713
|
const history = `${migrationsTable.schema}.${migrationsTable.table}`;
|
|
678
714
|
// Read from mithaq's table alone, an unmoved history says nothing was applied.
|
|
679
715
|
if ((await moveHistory({ db, directory, check: true })) !== undefined) {
|
|
@@ -698,26 +734,33 @@ export const bootMigrations = async ({ db, prodMigrations }) => {
|
|
|
698
734
|
const names = behind.map((migration) => migration.name);
|
|
699
735
|
throw new Refusal(`This database has not applied ${names.join(', ')}. prodMigrations refuses a production boot while a migration is pending, so nothing was served and nothing was written. Apply ${names.length === 1 ? 'it' : 'them'} with the installed binary, \`drizzle-kit migrate --config ${join(migrationsFolder, configName)}\`, and start again.`);
|
|
700
736
|
};
|
|
701
|
-
// stdout alone is parsed: stderr carries import-time warnings, never the envelope.
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}
|
|
737
|
+
// stdout alone is parsed: stderr carries import-time warnings, never the envelope. Both go to files:
|
|
738
|
+
// drizzle-kit exits right after printing, and Node writes to a pipe asynchronously off Linux, so
|
|
739
|
+
// an envelope past the pipe's 64 KB was cut short, where a file is written synchronously.
|
|
740
|
+
const kit = async (cwd, argv) => {
|
|
741
|
+
const scratch = await mkdtemp(join(tmpdir(), 'mithaq-kit-'));
|
|
742
|
+
const [out, err] = [join(scratch, 'stdout'), join(scratch, 'stderr')];
|
|
743
|
+
// Opened inside the `try`, so one that fails to open leaves none behind.
|
|
744
|
+
const opened = [];
|
|
745
|
+
try {
|
|
746
|
+
for (const path of [out, err])
|
|
747
|
+
opened.push(openSync(path, 'w'));
|
|
748
|
+
const [outFd, errFd] = opened;
|
|
749
|
+
const { code, signal } = await new Promise((done, fail) => {
|
|
750
|
+
const child = spawn(process.execPath, ['--import', kitOrm(ownKit), binary, ...argv], { cwd, stdio: ['ignore', outFd, errFd] });
|
|
751
|
+
// Without an `error` listener a child that cannot spawn hangs the command.
|
|
752
|
+
child.on('error', fail);
|
|
753
|
+
// The signal too, since a child killed from outside closes with no code.
|
|
754
|
+
child.on('close', (code, signal) => done({ code, signal }));
|
|
755
|
+
});
|
|
756
|
+
return { code, signal, stdout: await readFile(out, 'utf8'), stderr: await readFile(err, 'utf8') };
|
|
757
|
+
}
|
|
758
|
+
finally {
|
|
759
|
+
for (const fd of opened)
|
|
760
|
+
closeSync(fd);
|
|
761
|
+
await rm(scratch, { recursive: true, force: true });
|
|
762
|
+
}
|
|
763
|
+
};
|
|
721
764
|
const envelopeOf = async (cwd, argv) => {
|
|
722
765
|
const { code, signal, stdout, stderr } = await kit(cwd, argv);
|
|
723
766
|
try {
|
package/dist/drizzle/rules.d.ts
CHANGED
|
@@ -69,7 +69,7 @@ export declare const rules: {
|
|
|
69
69
|
primaryKey(): import("drizzle-orm/pg-core").AnyPgColumnBuilder & /*elided*/ any;
|
|
70
70
|
unique(): import("drizzle-orm/pg-core").AnyPgColumnBuilder & /*elided*/ any;
|
|
71
71
|
};
|
|
72
|
-
value:
|
|
72
|
+
value: Date | readonly unknown[] | import("../mithaq/user.ts").Ref | import("../index.ts").Json;
|
|
73
73
|
field: import("../index.ts").ResolvedField;
|
|
74
74
|
}) => import("drizzle-orm/pg-core").AnyPgColumnBuilder & {
|
|
75
75
|
default(value: unknown): import("drizzle-orm/pg-core").AnyPgColumnBuilder & any;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,42 +4,32 @@ export { betterAuth, betterAuthStrategy } from './auth/better-auth/index.ts';
|
|
|
4
4
|
export { defaultLockTime, defaultMaxLoginAttempts, defaultTokenExpiration, local, localAuthFields, localAuthOperations, localAuthStrategy } from './auth/local/index.ts';
|
|
5
5
|
export { actorPermissions, actorRoles, authActor } from './asas/actor.ts';
|
|
6
6
|
export { assignableRole, grantedPermissions, writableRoleName } from './rbac/steps.ts';
|
|
7
|
-
export
|
|
8
|
-
export {
|
|
9
|
-
export { heldPermissions, rbacTarget, type AccessOptions, type AccessTarget, type Assigned, type CommandActor, type SystemRole, type SystemRoles } from './rbac/index.ts';
|
|
7
|
+
export * from './targets.ts';
|
|
8
|
+
export { heldPermissions, type Assigned, type CommandActor } from './rbac/index.ts';
|
|
10
9
|
export { holdsPermission, requestOrganization } from './auth/better-auth/index.ts';
|
|
11
10
|
export type { AssignedResolver, AuthStrategy, KayanAuth } from './asas/actor.ts';
|
|
12
|
-
export type { AuthConfig, HttpPlug, Operation, OperationTable } from './asas/build.ts';
|
|
13
|
-
export { fetchHttp, type FetchHttpOptions } from './asas/http/fetch.ts';
|
|
14
|
-
export { AfterCommitError, AsasError, conflict, denied, invalid, missing, Notice, type MessageKey } from './asas/runner/errors.ts';
|
|
11
|
+
export type { AuthConfig, HttpPlug, Operation, OperationTable, Vocabulary } from './asas/build.ts';
|
|
12
|
+
export { defaultMaxBodyBytes, fetchHttp, type FetchHttpOptions } from './asas/http/fetch.ts';
|
|
13
|
+
export { AfterCommitError, AsasError, conflict, denied, invalid, missing, retryConflict, Notice, type MessageKey } from './asas/runner/errors.ts';
|
|
15
14
|
export { audit, count, defaultOperations, defaultGlobalOperations, defaults, find, findOne, findVersionByID, findVersions, insert, remove, restoreVersion, update, updateMany, deleteMany, validate, type BulkResult, type Context, type CommonStep, type CommonTools, type ContextOf, type Ctx, type CtxOf, type AuditHandler, type Derives, type FieldsOf, type DerivedSchemas, type DerivedShapes, type SchemasOf, type Lists, type OperationDeclaration, type OperationEffect, type OperationStep, type OperationSteps, type ProjectStep, type SlotSteps, type Operations, type OperationDefaults, type ReadMode, type ReadStep, type ReadTools, type ResolvedOperation, type Sealed, type Step, type StepsOf, type Tools, type WriteStep, type WriteTools, } from './asas/runner/steps.ts';
|
|
16
|
-
export { defaultAuthorize } from './asas/runner/write.ts';
|
|
17
15
|
export type { Authorize, BoundKayans, ByID, CreateOf, Globals, IdOf, Options, Procedures, ReadOptions, Row, RowOf, UpdateOf, Version, Writes } from './asas/runner/write.ts';
|
|
18
16
|
export type { Where } from './mithaq/where.ts';
|
|
19
17
|
export { defaultFields, defaultGlobalFields, defaultIdField, defaultTimestampFields } from './base/fields.ts';
|
|
20
18
|
export { uploadFields } from './storage/storage.ts';
|
|
21
19
|
export { accessFor, fieldAccessFor } from './mithaq/types.ts';
|
|
22
|
-
export type { Access, AccessArgs, AccessResult, AdminAccess, AdminAccessArgs, CompoundIndex, FieldAccess, FieldAccessArgs, Field, Kayan, KayanService, LabelFunction, Localized, LocalesOf, MessageMap, MessageTree, ResolvedField, ResolvedKayan, RuntimeField } from './mithaq/types.ts';
|
|
20
|
+
export type { Access, AccessArgs, AccessResult, AdminAccess, AdminAccessArgs, CompoundIndex, FieldAccess, FieldAccessArgs, Field, FilterOptions, JsonSchema, Kayan, KayanService, LabelFunction, Localized, LocalesOf, MessageMap, MessageTree, ResolvedField, ResolvedKayan, RuntimeField } from './mithaq/types.ts';
|
|
23
21
|
export type { Copy, MessageRegistry, MessageScope, MessagesResolver, ProjectMessages } from './mithaq/messages.ts';
|
|
24
|
-
export { defaultKinds, kind, type Kind, type OnDelete } from './base/kinds.ts';
|
|
25
|
-
export
|
|
22
|
+
export { defaultJsonMaxBytes, defaultKinds, isJson, kind, type Json, type Kind, type OnDelete } from './base/kinds.ts';
|
|
23
|
+
export { jsonSchemaCheck } from './base/json-schema.ts';
|
|
24
|
+
export type { RichTextNode, RichTextValue } from './rich-text/value.ts';
|
|
26
25
|
export { defineRukn, type KayanConfigs, type Rukn } from './mithaq/rukn.ts';
|
|
27
26
|
export { base } from './base/index.ts';
|
|
28
|
-
export { richText } from './rich-text/index.ts';
|
|
29
27
|
export { storage, upload } from './storage/index.ts';
|
|
30
28
|
export { versions } from './versions/index.ts';
|
|
31
29
|
export { defineMithaq, isAccess, isScreen, isService, isStorage, isStore, isTenant, isVersions, type Command, type CommandInput, type Language, type SchemaTarget, type Store, type Target, type TenantField, type TenantTarget } from './mithaq/language.ts';
|
|
32
30
|
export { Refusal } from './mithaq/refusal.ts';
|
|
33
31
|
export { defaultRules, providerOf, rule, type ProvidedBy, type Provider, type Rule, type Rules, type RuleValue } from './base/rules.ts';
|
|
34
|
-
export { drizzleAdapter, drizzleTarget, type Adapter, type ColumnBuilder, type ColumnRule, } from './drizzle/index.ts';
|
|
35
|
-
export { kinds as drizzleKinds } from './drizzle/kinds.ts';
|
|
36
|
-
export { defaultBulkLimit, defaultDepth, defaultJoinLimit, defaultLimit, defaultMaxLimit, serviceTarget, type ServiceTarget } from './service/index.ts';
|
|
37
|
-
export { versionsTarget, type KayanVersions, type VersionsTarget } from './versions/index.ts';
|
|
38
32
|
export { draftFields, versionOperations } from './versions/versions.ts';
|
|
39
|
-
export { adapterOf, allowedType, checkReference,
|
|
40
|
-
export {
|
|
41
|
-
export { rules as drizzleRules } from './drizzle/rules.ts';
|
|
33
|
+
export { adapterOf, allowedType, checkReference, fileHeaders, readForFile, sanitizeFilename, signReference, withUploadReference, type KayanStorage, type StorageAdapter, type StorageKayan, type StorageStep, type StoredFile, type SweepArgs, type UploadInstructions, type UploadReference, type UploadRequest, type Verified, type VerifyArgs, } from './storage/storage.ts';
|
|
34
|
+
export { folderOf, type ScreenKind, type ScreenButton, type ScreenFrame, type ScreenLayout, type ScreenOwnPage, type ScreenRegions, type Ui, type ScreenField, type ScreenKayan, type ScreenLeaf, type ScreenNode, type ScreenPage, type ScreenRef, } from './screen/index.ts';
|
|
42
35
|
export type { InferInput, InferOutput, StandardSchemaV1 } from './mithaq/standard-schema.ts';
|
|
43
|
-
export { zodTarget, type ZodRule, type ZodShape } from './zod/index.ts';
|
|
44
|
-
export { kinds as zodKinds } from './zod/kinds.ts';
|
|
45
|
-
export { rules as zodRules } from './zod/rules.ts';
|
package/dist/index.js
CHANGED
|
@@ -3,34 +3,24 @@ export { betterAuth, betterAuthStrategy } from './auth/better-auth/index.js';
|
|
|
3
3
|
export { defaultLockTime, defaultMaxLoginAttempts, defaultTokenExpiration, local, localAuthFields, localAuthOperations, localAuthStrategy } from './auth/local/index.js';
|
|
4
4
|
export { actorPermissions, actorRoles, authActor } from './asas/actor.js';
|
|
5
5
|
export { assignableRole, grantedPermissions, writableRoleName } from './rbac/steps.js';
|
|
6
|
-
export
|
|
7
|
-
export {
|
|
8
|
-
export { heldPermissions, rbacTarget } from './rbac/index.js';
|
|
6
|
+
export * from './targets.js';
|
|
7
|
+
export { heldPermissions } from './rbac/index.js';
|
|
9
8
|
export { holdsPermission, requestOrganization } from './auth/better-auth/index.js';
|
|
10
|
-
export { fetchHttp } from './asas/http/fetch.js';
|
|
11
|
-
export { AfterCommitError, AsasError, conflict, denied, invalid, missing, Notice } from './asas/runner/errors.js';
|
|
9
|
+
export { defaultMaxBodyBytes, fetchHttp } from './asas/http/fetch.js';
|
|
10
|
+
export { AfterCommitError, AsasError, conflict, denied, invalid, missing, retryConflict, Notice } from './asas/runner/errors.js';
|
|
12
11
|
export { audit, count, defaultOperations, defaultGlobalOperations, defaults, find, findOne, findVersionByID, findVersions, insert, remove, restoreVersion, update, updateMany, deleteMany, validate, } from './asas/runner/steps.js';
|
|
13
|
-
export { defaultAuthorize } from './asas/runner/write.js';
|
|
14
12
|
export { defaultFields, defaultGlobalFields, defaultIdField, defaultTimestampFields } from './base/fields.js';
|
|
15
13
|
export { uploadFields } from './storage/storage.js';
|
|
16
14
|
export { accessFor, fieldAccessFor } from './mithaq/types.js';
|
|
17
|
-
export { defaultKinds, kind } from './base/kinds.js';
|
|
15
|
+
export { defaultJsonMaxBytes, defaultKinds, isJson, kind } from './base/kinds.js';
|
|
16
|
+
export { jsonSchemaCheck } from './base/json-schema.js';
|
|
18
17
|
export { defineRukn } from './mithaq/rukn.js';
|
|
19
18
|
export { base } from './base/index.js';
|
|
20
|
-
export { richText } from './rich-text/index.js';
|
|
21
19
|
export { storage, upload } from './storage/index.js';
|
|
22
20
|
export { versions } from './versions/index.js';
|
|
23
21
|
export { defineMithaq, isAccess, isScreen, isService, isStorage, isStore, isTenant, isVersions } from './mithaq/language.js';
|
|
24
22
|
export { Refusal } from './mithaq/refusal.js';
|
|
25
23
|
export { defaultRules, providerOf, rule } from './base/rules.js';
|
|
26
|
-
export { drizzleAdapter, drizzleTarget, } from './drizzle/index.js';
|
|
27
|
-
export { kinds as drizzleKinds } from './drizzle/kinds.js';
|
|
28
|
-
export { defaultBulkLimit, defaultDepth, defaultJoinLimit, defaultLimit, defaultMaxLimit, serviceTarget } from './service/index.js';
|
|
29
|
-
export { versionsTarget } from './versions/index.js';
|
|
30
24
|
export { draftFields, versionOperations } from './versions/versions.js';
|
|
31
|
-
export { adapterOf, allowedType, checkReference,
|
|
32
|
-
export {
|
|
33
|
-
export { rules as drizzleRules } from './drizzle/rules.js';
|
|
34
|
-
export { zodTarget } from './zod/index.js';
|
|
35
|
-
export { kinds as zodKinds } from './zod/kinds.js';
|
|
36
|
-
export { rules as zodRules } from './zod/rules.js';
|
|
25
|
+
export { adapterOf, allowedType, checkReference, fileHeaders, readForFile, sanitizeFilename, signReference, withUploadReference, } from './storage/storage.js';
|
|
26
|
+
export { folderOf, } from './screen/index.js';
|