@drhomet/mithaq 0.0.0-stage → 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.
Files changed (152) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSES/openstatus-time-picker.txt +21 -0
  3. package/LICENSES/payload.txt +22 -0
  4. package/LICENSES/ponytail.txt +21 -0
  5. package/README.md +160 -2
  6. package/dist/asas/actor.d.ts +96 -0
  7. package/dist/asas/actor.js +114 -0
  8. package/dist/asas/build.d.ts +239 -0
  9. package/dist/asas/build.js +834 -0
  10. package/dist/asas/cli/mithaq.d.ts +2 -0
  11. package/dist/asas/cli/mithaq.js +177 -0
  12. package/dist/asas/cli/upgrade.d.ts +33 -0
  13. package/dist/asas/cli/upgrade.js +256 -0
  14. package/dist/asas/http/fetch.d.ts +41 -0
  15. package/dist/asas/http/fetch.js +178 -0
  16. package/dist/asas/http/orpc.d.ts +45 -0
  17. package/dist/asas/http/orpc.js +153 -0
  18. package/dist/asas/runner/bulk.d.ts +20 -0
  19. package/dist/asas/runner/bulk.js +196 -0
  20. package/dist/asas/runner/errors.d.ts +63 -0
  21. package/dist/asas/runner/errors.js +75 -0
  22. package/dist/asas/runner/read.d.ts +72 -0
  23. package/dist/asas/runner/read.js +601 -0
  24. package/dist/asas/runner/runtime.d.ts +21 -0
  25. package/dist/asas/runner/runtime.js +8 -0
  26. package/dist/asas/runner/steps.d.ts +418 -0
  27. package/dist/asas/runner/steps.js +277 -0
  28. package/dist/asas/runner/store.d.ts +4 -0
  29. package/dist/asas/runner/store.js +21 -0
  30. package/dist/asas/runner/tenant.d.ts +54 -0
  31. package/dist/asas/runner/tenant.js +275 -0
  32. package/dist/asas/runner/write.d.ts +606 -0
  33. package/dist/asas/runner/write.js +1019 -0
  34. package/dist/auth/better-auth/access.d.ts +29 -0
  35. package/dist/auth/better-auth/access.js +103 -0
  36. package/dist/auth/better-auth/generate.d.ts +31 -0
  37. package/dist/auth/better-auth/generate.js +328 -0
  38. package/dist/auth/better-auth/index.d.ts +94 -0
  39. package/dist/auth/better-auth/index.js +81 -0
  40. package/dist/auth/better-auth/tenant.d.ts +26 -0
  41. package/dist/auth/better-auth/tenant.js +34 -0
  42. package/dist/auth/local/index.d.ts +285 -0
  43. package/dist/auth/local/index.js +738 -0
  44. package/dist/base/decimal.d.ts +9 -0
  45. package/dist/base/decimal.js +16 -0
  46. package/dist/base/fields.d.ts +124 -0
  47. package/dist/base/fields.js +52 -0
  48. package/dist/base/index.d.ts +47 -0
  49. package/dist/base/index.js +5 -0
  50. package/dist/base/json-schema.d.ts +7 -0
  51. package/dist/base/json-schema.js +35 -0
  52. package/dist/base/kinds.d.ts +75 -0
  53. package/dist/base/kinds.js +123 -0
  54. package/dist/base/rules.d.ts +73 -0
  55. package/dist/base/rules.js +81 -0
  56. package/dist/drizzle/index.d.ts +308 -0
  57. package/dist/drizzle/index.js +951 -0
  58. package/dist/drizzle/kinds.d.ts +28 -0
  59. package/dist/drizzle/kinds.js +43 -0
  60. package/dist/drizzle/migrate.d.ts +159 -0
  61. package/dist/drizzle/migrate.js +1328 -0
  62. package/dist/drizzle/proxy/index.d.ts +1 -0
  63. package/dist/drizzle/proxy/index.js +1 -0
  64. package/dist/drizzle/proxy/node-postgres.d.ts +1 -0
  65. package/dist/drizzle/proxy/node-postgres.js +1 -0
  66. package/dist/drizzle/proxy/pg-core.d.ts +1 -0
  67. package/dist/drizzle/proxy/pg-core.js +1 -0
  68. package/dist/drizzle/rules.d.ts +336 -0
  69. package/dist/drizzle/rules.js +44 -0
  70. package/dist/index.d.ts +35 -0
  71. package/dist/index.js +26 -0
  72. package/dist/mithaq/define.d.ts +335 -0
  73. package/dist/mithaq/define.js +57 -0
  74. package/dist/mithaq/generate-messages.d.ts +38 -0
  75. package/dist/mithaq/generate-messages.js +235 -0
  76. package/dist/mithaq/language.d.ts +374 -0
  77. package/dist/mithaq/language.js +76 -0
  78. package/dist/mithaq/lock.d.ts +71 -0
  79. package/dist/mithaq/lock.js +329 -0
  80. package/dist/mithaq/message-file.d.ts +13 -0
  81. package/dist/mithaq/message-file.js +29 -0
  82. package/dist/mithaq/messages.d.ts +55 -0
  83. package/dist/mithaq/messages.js +111 -0
  84. package/dist/mithaq/refusal.d.ts +6 -0
  85. package/dist/mithaq/refusal.js +6 -0
  86. package/dist/mithaq/resolve.d.ts +10 -0
  87. package/dist/mithaq/resolve.js +1014 -0
  88. package/dist/mithaq/rows.d.ts +87 -0
  89. package/dist/mithaq/rows.js +174 -0
  90. package/dist/mithaq/rukn.d.ts +72 -0
  91. package/dist/mithaq/rukn.js +15 -0
  92. package/dist/mithaq/standard-schema.d.ts +38 -0
  93. package/dist/mithaq/standard-schema.js +2 -0
  94. package/dist/mithaq/types.d.ts +386 -0
  95. package/dist/mithaq/types.js +15 -0
  96. package/dist/mithaq/user.d.ts +19 -0
  97. package/dist/mithaq/user.js +16 -0
  98. package/dist/mithaq/where.d.ts +32 -0
  99. package/dist/mithaq/where.js +87 -0
  100. package/dist/rbac/index.d.ts +105 -0
  101. package/dist/rbac/index.js +182 -0
  102. package/dist/rbac/steps.d.ts +22 -0
  103. package/dist/rbac/steps.js +161 -0
  104. package/dist/rich-text/index.d.ts +28 -0
  105. package/dist/rich-text/index.js +59 -0
  106. package/dist/rich-text/rich-text.d.ts +106 -0
  107. package/dist/rich-text/rich-text.js +249 -0
  108. package/dist/rich-text/value.d.ts +55 -0
  109. package/dist/rich-text/value.js +126 -0
  110. package/dist/screen/client.d.ts +156 -0
  111. package/dist/screen/client.js +71 -0
  112. package/dist/screen/generate.d.ts +14 -0
  113. package/dist/screen/generate.js +268 -0
  114. package/dist/screen/index.d.ts +496 -0
  115. package/dist/screen/index.js +663 -0
  116. package/dist/screen/react.d.ts +97 -0
  117. package/dist/screen/react.js +58 -0
  118. package/dist/screen/studio.d.ts +24 -0
  119. package/dist/screen/studio.js +68 -0
  120. package/dist/service/index.d.ts +63 -0
  121. package/dist/service/index.js +15 -0
  122. package/dist/storage/allowed-type.d.ts +5 -0
  123. package/dist/storage/allowed-type.js +7 -0
  124. package/dist/storage/index.d.ts +42 -0
  125. package/dist/storage/index.js +43 -0
  126. package/dist/storage/storage.d.ts +386 -0
  127. package/dist/storage/storage.js +412 -0
  128. package/dist/targets.d.ts +14 -0
  129. package/dist/targets.js +16 -0
  130. package/dist/versions/index.d.ts +37 -0
  131. package/dist/versions/index.js +8 -0
  132. package/dist/versions/versions.d.ts +104 -0
  133. package/dist/versions/versions.js +160 -0
  134. package/dist/vite.d.ts +7 -0
  135. package/dist/vite.js +81 -0
  136. package/dist/zod/index.d.ts +193 -0
  137. package/dist/zod/index.js +122 -0
  138. package/dist/zod/kinds.d.ts +36 -0
  139. package/dist/zod/kinds.js +58 -0
  140. package/dist/zod/rules.d.ts +117 -0
  141. package/dist/zod/rules.js +67 -0
  142. package/docs/packages/mithaq/README.md +962 -0
  143. package/docs/packages/mithaq/src/asas/cli/README.md +252 -0
  144. package/docs/packages/mithaq/src/asas/runner/README.md +472 -0
  145. package/docs/packages/mithaq/src/drizzle/README.md +39 -0
  146. package/docs/packages/mithaq-admin/README.md +312 -0
  147. package/docs/templates/asas/README.md +1056 -0
  148. package/package.json +92 -4
  149. package/skills/add-field/SKILL.md +27 -0
  150. package/skills/add-kayan/SKILL.md +26 -0
  151. package/skills/eject-admin-piece/SKILL.md +28 -0
  152. package/skills/upgrade-mithaq/SKILL.md +35 -0
@@ -0,0 +1,58 @@
1
+ import { z } from 'zod';
2
+ import { isJson } from '../base/kinds.js';
3
+ import { isDecimal } from '../base/decimal.js';
4
+ import { jsonSchemaCheck } from '../base/json-schema.js';
5
+ // A missing key, or a `null` on a required field, is the `required` rule refusing;
6
+ // anything else is the kind refusing the value. A field with no kayan keeps zod's text.
7
+ export const errorOf = (field, element = false) => field?.kayan
8
+ ? (issue) => issue.input === undefined || (issue.input === null && !element && field.rules?.required === true)
9
+ ? `${field.kayan}.${field.name}.required`
10
+ : `${field.kayan}.${field.name}.invalid`
11
+ : undefined;
12
+ const idShapes = {
13
+ // A number id is an int4 `serial`, so a fraction or a value past its range is a 400, not a Postgres 500.
14
+ number: (error) => z.int32({ error }),
15
+ text: (error) => z.string({ error }),
16
+ // `guid`, not `uuid`: `z.uuid()` also demands an RFC version and variant, which Postgres does not.
17
+ // Lower-cased, the spelling Postgres answers, so a step comparing ids as text sees one id.
18
+ uuid: (error) => z.guid({ error }).toLowerCase(),
19
+ };
20
+ /** The kinds this target shapes an id of, the same three the store's columns are. */
21
+ export const idKinds = Object.keys(idShapes);
22
+ const idShape = (kind, error) => idShapes[kind](error);
23
+ // Narrowed to the field's `options` on the server, not only in the browser.
24
+ const textShape = (field, element = false) => {
25
+ const values = field?.options?.map((option) => option.value);
26
+ return values?.length ? z.enum(values, { error: errorOf(field, element) }) : z.string({ error: errorOf(field, element) });
27
+ };
28
+ /** One shape per kind, the same record shape as the adapter's kinds. */
29
+ export const kinds = {
30
+ text: textShape,
31
+ email: (field) => z.email({ error: errorOf(field) }),
32
+ // The id is the `serial` column `idShapes` says it is; any other number is a
33
+ // `numeric` column, which takes every finite number.
34
+ number: (field) => (field?.name === 'id' ? idShape('number', errorOf(field)) : z.number({ error: errorOf(field) })),
35
+ // A Postgres `integer`, the same int4 a number id is.
36
+ integer: (field) => z.int32({ error: errorOf(field) }),
37
+ // A JS number is refused: it may already have lost a digit. `abort`, so no
38
+ // rule after it reads text that is no decimal.
39
+ decimal: (field) => z.string({ error: errorOf(field) }).refine(isDecimal, { error: errorOf(field), abort: true }),
40
+ checkbox: (field) => z.boolean({ error: errorOf(field) }),
41
+ datetime: (field) => z.date({ error: errorOf(field) }),
42
+ // A string, so a `Date` is refused rather than truncated to whichever day its zone makes of it.
43
+ date: (field) => z.iso.date({ error: errorOf(field) }),
44
+ // The same error on each element, so a bad element reads as the field's own sentence.
45
+ textArray: (field) => z.array(textShape(field, true), { error: errorOf(field) }),
46
+ uuid: (field) => idShape('uuid', errorOf(field)),
47
+ relationship: (field) => field.hasMany
48
+ ? z.array(idShape(field.target.fields.id.kind, errorOf(field, true)), { error: errorOf(field) })
49
+ : idShape(field.target.fields.id.kind, errorOf(field)),
50
+ // Only what JSON can say, so a value reads back as it was written; `z.json()` lets a cycle through.
51
+ // A `jsonSchema` only judges: what is stored is the value as sent.
52
+ json: (field) => {
53
+ const shape = z.custom((value) => isJson(value) && !(field?.maxBytes && new TextEncoder().encode(JSON.stringify(value)).length > field.maxBytes), { error: errorOf(field) });
54
+ return field?.jsonSchema ? shape.refine(jsonSchemaCheck(field), { error: errorOf(field) }) : shape;
55
+ },
56
+ // Left loose: the child's row shape may not be derived yet, and the child's own read already parsed the rows.
57
+ join: (field) => z.array(z.record(z.string(), z.unknown()), { error: errorOf(field) }),
58
+ };
@@ -0,0 +1,117 @@
1
+ import { z } from 'zod';
2
+ import type { ResolvedField } from '../mithaq/types.ts';
3
+ export declare const rules: {
4
+ /** The database enforces it, and only the database can. */
5
+ unique: ({ shape }: {
6
+ shape: z.ZodType;
7
+ value: boolean;
8
+ field: ResolvedField;
9
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
10
+ /** Nothing about reading rows faster changes what a write must look like. */
11
+ index: ({ shape }: {
12
+ shape: z.ZodType;
13
+ value: boolean;
14
+ field: ResolvedField;
15
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
16
+ /** A rule about deleting the other row, and a write is not a delete. */
17
+ onDelete: ({ shape }: {
18
+ shape: z.ZodType;
19
+ value: import("../index.ts").OnDelete;
20
+ field: ResolvedField;
21
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
22
+ providedBy: ({ shape }: {
23
+ shape: z.ZodType;
24
+ value: Readonly<{
25
+ create?: import("../base/rules.ts").Provider;
26
+ update?: import("../base/rules.ts").Provider;
27
+ }>;
28
+ field: ResolvedField;
29
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
30
+ minLength: ({ shape, value: length, field }: {
31
+ shape: z.ZodType;
32
+ value: number;
33
+ field: ResolvedField;
34
+ }) => z.ZodString;
35
+ maxLength: ({ shape, value: length, field }: {
36
+ shape: z.ZodType;
37
+ value: number;
38
+ field: ResolvedField;
39
+ }) => z.ZodString;
40
+ pattern: ({ shape, value: expression, field }: {
41
+ shape: z.ZodType;
42
+ value: RegExp;
43
+ field: ResolvedField;
44
+ }) => z.ZodString;
45
+ precision: ({ shape, value: precision, field }: {
46
+ shape: z.ZodType;
47
+ value: number;
48
+ field: ResolvedField;
49
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
50
+ scale: ({ shape, value: scale, field }: {
51
+ shape: z.ZodType;
52
+ value: number;
53
+ field: ResolvedField;
54
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
55
+ min: ({ shape, value, field }: {
56
+ shape: z.ZodType;
57
+ value: string | number;
58
+ field: ResolvedField;
59
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
60
+ max: ({ shape, value, field }: {
61
+ shape: z.ZodType;
62
+ value: string | number;
63
+ field: ResolvedField;
64
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
65
+ minRows: ({ shape, value: rows, field }: {
66
+ shape: z.ZodType;
67
+ value: number;
68
+ field: ResolvedField;
69
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
70
+ maxRows: ({ shape, value: rows, field }: {
71
+ shape: z.ZodType;
72
+ value: number;
73
+ field: ResolvedField;
74
+ }) => z.ZodArray<z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
75
+ trim: ({ shape, value: on, field }: {
76
+ shape: z.ZodType;
77
+ value: boolean;
78
+ field: ResolvedField;
79
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
80
+ uppercase: ({ shape, value: on, field }: {
81
+ shape: z.ZodType;
82
+ value: boolean;
83
+ field: ResolvedField;
84
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
85
+ lowercase: ({ shape, value: on, field }: {
86
+ shape: z.ZodType;
87
+ value: boolean;
88
+ field: ResolvedField;
89
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
90
+ localized: ({ shape, value: on, field }: {
91
+ shape: z.ZodType;
92
+ value: boolean;
93
+ field: ResolvedField;
94
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
95
+ required: ({ shape, value: on, field }: {
96
+ shape: z.ZodType;
97
+ value: boolean;
98
+ field: ResolvedField;
99
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
100
+ defaultValue: ({ shape }: {
101
+ shape: z.ZodType;
102
+ value: Date | readonly unknown[] | import("../index.ts").Ref | import("../index.ts").Json;
103
+ field: ResolvedField;
104
+ }) => z.ZodOptional<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
105
+ /** The moment the defaults step writes, which leaves the key optional as a literal does. */
106
+ defaultNow: ({ shape, value: on }: {
107
+ shape: z.ZodType;
108
+ value: boolean;
109
+ field: ResolvedField;
110
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
111
+ /** Filled on update by the defaults step, and never client-supplied there, so nothing to shape. */
112
+ nowOnUpdate: ({ shape }: {
113
+ shape: z.ZodType;
114
+ value: boolean;
115
+ field: ResolvedField;
116
+ }) => z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
117
+ };
@@ -0,0 +1,67 @@
1
+ import { z } from 'zod';
2
+ import { compareDecimals, decimalDigits } from '../base/decimal.js';
3
+ import { errorOf } from './kinds.js';
4
+ // One copy key per field per rule, with no number in it: the browser already
5
+ // holds the field's rules for any number it shows.
6
+ const keyOf = (field, rule) => field.kayan ? `${field.kayan}.${field.name}.${rule}` : undefined;
7
+ // `required`, `defaultValue` and `defaultNow` come last: an optional shape is a
8
+ // `ZodOptional` with none of the narrowing methods left on it.
9
+ export const rules = {
10
+ /** The database enforces it, and only the database can. */
11
+ unique: ({ shape }) => shape,
12
+ /** Nothing about reading rows faster changes what a write must look like. */
13
+ index: ({ shape }) => shape,
14
+ /** A rule about deleting the other row, and a write is not a delete. */
15
+ onDelete: ({ shape }) => shape,
16
+ // Read where the objects are assembled: a field the client does not supply is
17
+ // absent from that shape, so the strict object refuses a caller that sends it.
18
+ providedBy: ({ shape }) => shape,
19
+ minLength: ({ shape, value: length, field }) => shape.min(length, { error: keyOf(field, 'minLength') }),
20
+ maxLength: ({ shape, value: length, field }) => shape.max(length, { error: keyOf(field, 'maxLength') }),
21
+ pattern: ({ shape, value: expression, field }) => shape.regex(expression, { error: keyOf(field, 'pattern') }),
22
+ // Counted as `numeric(precision, scale)` counts, so Postgres never rounds a value or refuses it as a 500.
23
+ precision: ({ shape, value: precision, field }) => shape.refine((held) => {
24
+ const { whole, fraction } = decimalDigits(String(held));
25
+ return whole + fraction <= precision && whole <= precision - Number(field.rules?.scale);
26
+ }, { error: keyOf(field, 'precision') }),
27
+ scale: ({ shape, value: scale, field }) => shape.refine((held) => decimalDigits(String(held)).fraction <= scale, { error: keyOf(field, 'scale') }),
28
+ // `min` on a string shape is a length, so an ISO day gets a check of its own.
29
+ min: ({ shape, value, field }) => typeof value === 'number'
30
+ ? shape.min(value, { error: keyOf(field, 'min') })
31
+ : shape.refine((held) => (field.kind === 'decimal' ? compareDecimals(String(held), value) >= 0 : String(held) >= value), {
32
+ error: keyOf(field, 'min') ?? `Too small: expected value to be >=${value}`,
33
+ }),
34
+ max: ({ shape, value, field }) => typeof value === 'number'
35
+ ? shape.max(value, { error: keyOf(field, 'max') })
36
+ : shape.refine((held) => (field.kind === 'decimal' ? compareDecimals(String(held), value) <= 0 : String(held) <= value), {
37
+ error: keyOf(field, 'max') ?? `Too big: expected value to be <=${value}`,
38
+ }),
39
+ // An empty list passes the floor unless the field is `required`.
40
+ minRows: ({ shape, value: rows, field }) => shape.refine((held) => held.length >= rows || (!field.rules?.required && !held.length), {
41
+ error: keyOf(field, 'minRows') ?? `Too small: expected array to have >=${rows} items`,
42
+ }),
43
+ maxRows: ({ shape, value: rows, field }) => shape.max(rows, { error: keyOf(field, 'maxRows') }),
44
+ // Piped in front of what the kind and earlier rules built, so `maxLength` and
45
+ // `z.email()` judge the trimmed value; before `localized`, so each locale is trimmed.
46
+ trim: ({ shape, value: on, field }) => (on ? z.string({ error: errorOf(field) }).trim().pipe(shape) : shape),
47
+ uppercase: ({ shape, value: on, field }) => (on ? z.string({ error: errorOf(field) }).toUpperCase().pipe(shape) : shape),
48
+ lowercase: ({ shape, value: on, field }) => (on ? z.string({ error: errorOf(field) }).toLowerCase().pipe(shape) : shape),
49
+ // After every narrowing rule and before `required`: rules apply to each locale's
50
+ // value, and a field nobody wrote is one null rather than an object of them.
51
+ localized: ({ shape, value: on, field }) => on ? z.strictObject(Object.fromEntries(field.locales.map((locale) => [locale, shape]))) : shape,
52
+ // A required text refuses the empty string too. A required `textArray` may be
53
+ // empty; `minRows: 1` refuses that.
54
+ required: ({ shape, value: on, field }) => field.name === 'id'
55
+ ? shape
56
+ : !on
57
+ ? shape.nullable().optional()
58
+ : field.kind === 'text'
59
+ ? shape.refine((held) => !(field.rules?.localized ? Object.values(held) : [held]).includes(''), { error: keyOf(field, 'required') })
60
+ : shape,
61
+ // Optional, not nullable: the runner fills every default on every write that makes or changes a row.
62
+ defaultValue: ({ shape }) => shape.optional(),
63
+ /** The moment the defaults step writes, which leaves the key optional as a literal does. */
64
+ defaultNow: ({ shape, value: on }) => (on ? shape.optional() : shape),
65
+ /** Filled on update by the defaults step, and never client-supplied there, so nothing to shape. */
66
+ nowOnUpdate: ({ shape }) => shape,
67
+ };