ignotum 0.0.6 → 0.0.7

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 (33) hide show
  1. package/dist/cli/bin.mjs +663 -38
  2. package/dist/cli/bin.mjs.map +1 -1
  3. package/dist/runtime/{api-D2bsAz4T.d.ts → api-Dp4J-xt-.d.ts} +2 -3
  4. package/dist/runtime/client.d.ts +20 -3
  5. package/dist/runtime/client.js +197 -20
  6. package/dist/runtime/client.js.map +1 -1
  7. package/dist/runtime/{descriptor-t6BOEGw9-BTHR-ZMv.js → descriptor-t6BOEGw9-C1rwYIlx.js} +29 -2
  8. package/dist/runtime/descriptor-t6BOEGw9-C1rwYIlx.js.map +1 -0
  9. package/dist/runtime/{result-BgcHn25t.d.ts → id-Btwac71X-DhnKYsjY.d.ts} +8 -2
  10. package/dist/runtime/{index-Dl_VQGmA.d.ts → index-B5KSOjGN.d.ts} +60 -69
  11. package/dist/runtime/internal/api.d.ts +1 -1
  12. package/dist/runtime/internal/host.d.ts +20 -4
  13. package/dist/runtime/internal/host.js +190 -7
  14. package/dist/runtime/internal/host.js.map +1 -1
  15. package/dist/runtime/internal/server.d.ts +1 -1
  16. package/dist/runtime/internal/server.js +1 -1
  17. package/dist/runtime/internal/types.d.ts +1 -1
  18. package/dist/runtime/internal/types.js +1 -1
  19. package/dist/runtime/pagination-B1BzNkh8-BUSTbeSg.d.ts +80 -0
  20. package/dist/runtime/pagination-BKPko9Hm.d.ts +1 -0
  21. package/dist/runtime/{schema-B-jMZEbs.js → schema-D9RmboaS.js} +93 -29
  22. package/dist/runtime/schema-D9RmboaS.js.map +1 -0
  23. package/dist/runtime/server.d.ts +2 -2
  24. package/dist/runtime/server.js +2 -2
  25. package/package.json +4 -4
  26. package/src/cli/agent-files.ts +4 -0
  27. package/src/client/hooks.ts +164 -2
  28. package/src/client/index.ts +2 -1
  29. package/src/dev-runtime/database.ts +568 -37
  30. package/src/dev-runtime/migrations.ts +30 -0
  31. package/dist/runtime/descriptor-t6BOEGw9-BTHR-ZMv.js.map +0 -1
  32. package/dist/runtime/id-Btwac71X-B9OeBzvq.d.ts +0 -9
  33. package/dist/runtime/schema-B-jMZEbs.js.map +0 -1
@@ -0,0 +1,80 @@
1
+ import "./id-Btwac71X-DhnKYsjY.js";
2
+ import { Schema } from "effect";
3
+ //#region ../contracts/dist/descriptor-CVZycwe2.d.ts
4
+ //#region src/schema/descriptor.d.ts
5
+ interface DescriptorField {
6
+ readonly name: string;
7
+ readonly value: ValueDescriptor;
8
+ }
9
+ type ValueDescriptor = {
10
+ readonly type: "array";
11
+ readonly value: ValueDescriptor;
12
+ } | {
13
+ readonly type: "boolean";
14
+ } | {
15
+ readonly type: "date";
16
+ } | {
17
+ readonly type: "error";
18
+ readonly tag: string;
19
+ readonly fields: ReadonlyArray<DescriptorField>;
20
+ } | {
21
+ readonly type: "id";
22
+ readonly table: string;
23
+ } | {
24
+ readonly type: "integer";
25
+ } | {
26
+ readonly type: "literal";
27
+ readonly value: string | number | boolean;
28
+ } | {
29
+ readonly type: "literals";
30
+ readonly values: ReadonlyArray<string | number | boolean>;
31
+ } | {
32
+ readonly type: "never";
33
+ } | {
34
+ readonly type: "null";
35
+ } | {
36
+ readonly type: "nullable";
37
+ readonly value: ValueDescriptor;
38
+ } | {
39
+ readonly type: "number";
40
+ } | {
41
+ readonly type: "object";
42
+ readonly fields: ReadonlyArray<DescriptorField>;
43
+ } | {
44
+ readonly type: "optional";
45
+ readonly value: ValueDescriptor;
46
+ } | {
47
+ readonly type: "record";
48
+ readonly value: ValueDescriptor;
49
+ } | {
50
+ readonly type: "string";
51
+ } | {
52
+ readonly type: "union";
53
+ readonly members: ReadonlyArray<ValueDescriptor>;
54
+ };
55
+ declare const ValueDescriptor: Schema.Codec<ValueDescriptor>;
56
+ declare const ValueDescriptorTypeId: unique symbol;
57
+ interface ValueDescriptorCarrier {
58
+ readonly [ValueDescriptorTypeId]: ValueDescriptor;
59
+ }
60
+ type DescribedValue<Value extends Schema.Constraint = Schema.Constraint> = Value & ValueDescriptorCarrier;
61
+ type ValueFields = {
62
+ readonly [fieldName: PropertyKey]: DescribedValue;
63
+ };
64
+ //#endregion
65
+ //#region ../contracts/dist/pagination-B1BzNkh8.d.ts
66
+ //#region src/runtime/pagination.d.ts
67
+ declare const PaginationCursor: Schema.brand<Schema.String, "ignotum/runtime/PaginationCursor">;
68
+ type PaginationCursor = typeof PaginationCursor.Type;
69
+ declare const PaginationOptions: Schema.Struct<{
70
+ readonly cursor: Schema.NullOr<Schema.brand<Schema.String, "ignotum/runtime/PaginationCursor">>;
71
+ readonly pageSize: Schema.brand<Schema.Int, "ignotum/runtime/PaginationPageSize">;
72
+ }>;
73
+ type PaginationOptions = typeof PaginationOptions.Type;
74
+ interface PaginationPage<Item> {
75
+ readonly items: ReadonlyArray<Item>;
76
+ readonly nextCursor: PaginationCursor | null;
77
+ }
78
+ //#endregion
79
+ export { ValueDescriptorCarrier as a, ValueDescriptor as i, PaginationPage as n, ValueFields as o, DescribedValue as r, PaginationOptions as t };
80
+ //# sourceMappingURL=pagination-B1BzNkh8-BUSTbeSg.d.ts.map
@@ -0,0 +1 @@
1
+ import "./pagination-B1BzNkh8-BUSTbeSg.js";
@@ -1,36 +1,67 @@
1
1
  import { r as GeneratedId } from "./id-D570vudg.js";
2
- import { a as ErrorBrand, i as getValueDescriptor, n as attachValueDescriptor, r as descriptorFields } from "./descriptor-t6BOEGw9-BTHR-ZMv.js";
2
+ import { a as PaginationCursor, i as getValueDescriptor, n as attachValueDescriptor, o as PaginationPageSize, r as descriptorFields, s as ErrorBrand } from "./descriptor-t6BOEGw9-C1rwYIlx.js";
3
3
  import { Schema, Struct } from "effect";
4
- //#region ../contracts/dist/runtime/schema.js
5
- const FunctionSchemaTypeId = Symbol.for("ignotum/runtime/schema/FunctionSchema");
6
- const attachFunctionSchema = (schema) => (definition) => {
7
- Object.defineProperty(definition, FunctionSchemaTypeId, {
8
- configurable: false,
9
- enumerable: false,
10
- value: schema,
11
- writable: false
12
- });
13
- return definition;
14
- };
15
- const getFunctionSchema = (value) => value[FunctionSchemaTypeId];
16
- //#endregion
17
4
  //#region ../contracts/dist/schema/values.js
18
5
  const LiteralValueSchema = Schema.Union([
19
6
  Schema.String,
20
7
  Schema.Finite,
21
8
  Schema.Boolean
22
9
  ]);
10
+ const schemaIndexLimits = {
11
+ fieldsPerIndex: 8,
12
+ indexesPerSchema: 128,
13
+ indexesPerTable: 16,
14
+ keyBytes: 4096,
15
+ nameBytes: 64
16
+ };
17
+ const utf8ByteLength = (value) => {
18
+ let bytes = 0;
19
+ for (const character of value) {
20
+ const point = character.codePointAt(0) ?? 0;
21
+ bytes += point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;
22
+ }
23
+ return bytes;
24
+ };
23
25
  const table = (fields) => {
24
26
  const tableFields = fields;
25
- return {
26
- _tag: "Table",
27
- descriptor: {
28
- type: "object",
29
- fields: descriptorFields(tableFields)
30
- },
31
- fields: tableFields,
32
- schema: Schema.Struct(tableFields)
27
+ const make = (indexes) => {
28
+ const index = (name, fieldNames) => {
29
+ if (utf8ByteLength(name) > schemaIndexLimits.nameBytes) throw new Error(`Index names cannot exceed ${schemaIndexLimits.nameBytes} UTF-8 bytes.`);
30
+ if (name.length === 0) throw new Error("Index names cannot be empty.");
31
+ if (name.startsWith("$")) throw new Error("Index names beginning with '$' are reserved.");
32
+ if (Object.hasOwn(indexes, name)) throw new Error(`Duplicate index name '${name}'.`);
33
+ if (fieldNames.length > schemaIndexLimits.fieldsPerIndex) throw new Error(`Indexes cannot contain more than ${schemaIndexLimits.fieldsPerIndex} fields.`);
34
+ if (new Set(fieldNames).size !== fieldNames.length) throw new Error(`Index '${name}' contains duplicate fields.`);
35
+ for (const fieldName of fieldNames) {
36
+ if (!Object.hasOwn(tableFields, fieldName)) throw new Error(`Index '${name}' references unknown field '${fieldName}'.`);
37
+ const descriptor = getValueDescriptor(tableFields[fieldName]);
38
+ if (!(descriptor?.type === "boolean" || descriptor?.type === "date" || descriptor?.type === "id" || descriptor?.type === "integer" || descriptor?.type === "number" || descriptor?.type === "string" || descriptor?.type === "literal" || descriptor?.type === "literals")) throw new Error(`Index '${name}' field '${fieldName}' is not indexable.`);
39
+ if (descriptor.type === "literals" && !(descriptor.values.every(Schema.is(Schema.Boolean)) || descriptor.values.every(Schema.is(Schema.Finite)) || descriptor.values.every(Schema.is(Schema.String)))) throw new Error(`Index '${name}' field '${fieldName}' mixes value types.`);
40
+ }
41
+ const duplicate = Object.values(indexes).find((candidate) => candidate.fields.length === fieldNames.length && candidate.fields.every((fieldName, position) => fieldName === fieldNames[position]));
42
+ if (duplicate !== void 0) throw new Error(`Index '${name}' duplicates index '${duplicate.name}'.`);
43
+ if (Object.keys(indexes).length >= schemaIndexLimits.indexesPerTable) throw new Error(`Tables cannot declare more than ${schemaIndexLimits.indexesPerTable} indexes.`);
44
+ return make({
45
+ ...indexes,
46
+ [name]: {
47
+ name,
48
+ fields: fieldNames
49
+ }
50
+ });
51
+ };
52
+ return {
53
+ _tag: "Table",
54
+ descriptor: {
55
+ type: "object",
56
+ fields: descriptorFields(tableFields)
57
+ },
58
+ fields: tableFields,
59
+ index,
60
+ indexes,
61
+ schema: Schema.Struct(tableFields)
62
+ };
33
63
  };
64
+ return make({});
34
65
  };
35
66
  const fresh = (value) => value.pipe(Schema.annotate({}));
36
67
  const string = () => attachValueDescriptor(fresh(Schema.String), { type: "string" });
@@ -143,6 +174,17 @@ const union = (...members) => {
143
174
  members: members.map(requireDescriptor)
144
175
  });
145
176
  };
177
+ const paginationCursor = () => attachValueDescriptor(fresh(PaginationCursor), { type: "string" });
178
+ const pagination = () => fixedObject({
179
+ cursor: nullable(paginationCursor()),
180
+ pageSize: attachValueDescriptor(fresh(PaginationPageSize), { type: "integer" })
181
+ });
182
+ const page = (value) => {
183
+ return fixedObject({
184
+ items: array(value),
185
+ nextCursor: nullable(paginationCursor())
186
+ });
187
+ };
146
188
  const error = (tag, fields) => {
147
189
  if (tag === "InternalServerError") throw new Error("The error tag 'InternalServerError' is reserved by Ignotum.");
148
190
  const errorFields = { ...fields };
@@ -190,22 +232,44 @@ const bindValues = (definition) => {
190
232
  };
191
233
  return fixedObject(Struct.assign(tableFields, systemFields));
192
234
  };
235
+ const boundPagination = () => {
236
+ return pagination();
237
+ };
193
238
  return {
194
239
  ...values,
195
240
  doc,
196
- id: boundId
241
+ id: boundId,
242
+ page,
243
+ pagination: boundPagination
197
244
  };
198
245
  };
199
246
  //#endregion
247
+ //#region ../contracts/dist/runtime/schema.js
248
+ const FunctionSchemaTypeId = Symbol.for("ignotum/runtime/schema/FunctionSchema");
249
+ const attachFunctionSchema = (schema) => (definition) => {
250
+ Object.defineProperty(definition, FunctionSchemaTypeId, {
251
+ configurable: false,
252
+ enumerable: false,
253
+ value: schema,
254
+ writable: false
255
+ });
256
+ return definition;
257
+ };
258
+ const getFunctionSchema = (value) => value[FunctionSchemaTypeId];
259
+ //#endregion
200
260
  //#region ../contracts/dist/schema/index.js
201
261
  const SchemaDefinitionTypeId = Symbol.for("ignotum/schema/SchemaDefinition");
202
- const defineSchema = (define) => ({
203
- _tag: "Schema",
204
- [SchemaDefinitionTypeId]: define({
262
+ const defineSchema = (define) => {
263
+ const definitions = define({
205
264
  table,
206
265
  values
207
- })
208
- });
266
+ });
267
+ if (Object.values(definitions).reduce((count, definition) => count + Object.keys(definition.indexes).length, 0) > schemaIndexLimits.indexesPerSchema) throw new Error(`Schemas cannot declare more than ${schemaIndexLimits.indexesPerSchema} indexes.`);
268
+ return {
269
+ _tag: "Schema",
270
+ [SchemaDefinitionTypeId]: definitions
271
+ };
272
+ };
209
273
  const makeFunctionBuilder = (schema, kind) => {
210
274
  const define = (definition) => attachFunctionSchema(schema)({
211
275
  _tag: kind,
@@ -224,4 +288,4 @@ const bindSchema = (schema) => ({
224
288
  //#endregion
225
289
  export { getFunctionSchema as i, bindSchema as n, defineSchema as r, SchemaDefinitionTypeId as t };
226
290
 
227
- //# sourceMappingURL=schema-B-jMZEbs.js.map
291
+ //# sourceMappingURL=schema-D9RmboaS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-D9RmboaS.js","names":[],"sources":["../../../contracts/dist/schema/values.js","../../../contracts/dist/runtime/schema.js","../../../contracts/dist/schema/index.js"],"sourcesContent":["import { GeneratedId } from \"../runtime/id.js\";\nimport { a as getValueDescriptor, i as descriptorFields, r as attachValueDescriptor } from \"../descriptor-t6BOEGw9.js\";\nimport { PaginationCursor, PaginationPageSize } from \"../runtime/pagination.js\";\nimport { ErrorBrand } from \"../runtime/result.js\";\nimport { Schema, Struct } from \"effect\";\n//#region src/schema/values.ts\nconst LiteralValueSchema = Schema.Union([\n\tSchema.String,\n\tSchema.Finite,\n\tSchema.Boolean\n]);\nconst schemaIndexLimits = {\n\tfieldsPerIndex: 8,\n\tindexesPerSchema: 128,\n\tindexesPerTable: 16,\n\tkeyBytes: 4096,\n\tnameBytes: 64\n};\nconst utf8ByteLength = (value) => {\n\tlet bytes = 0;\n\tfor (const character of value) {\n\t\tconst point = character.codePointAt(0) ?? 0;\n\t\tbytes += point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;\n\t}\n\treturn bytes;\n};\nconst table = (fields) => {\n\tconst tableFields = fields;\n\tconst make = (indexes) => {\n\t\tconst index = (name, fieldNames) => {\n\t\t\tif (utf8ByteLength(name) > schemaIndexLimits.nameBytes) throw new Error(`Index names cannot exceed ${schemaIndexLimits.nameBytes} UTF-8 bytes.`);\n\t\t\tif (name.length === 0) throw new Error(\"Index names cannot be empty.\");\n\t\t\tif (name.startsWith(\"$\")) throw new Error(\"Index names beginning with '$' are reserved.\");\n\t\t\tif (Object.hasOwn(indexes, name)) throw new Error(`Duplicate index name '${name}'.`);\n\t\t\tif (fieldNames.length > schemaIndexLimits.fieldsPerIndex) throw new Error(`Indexes cannot contain more than ${schemaIndexLimits.fieldsPerIndex} fields.`);\n\t\t\tif (new Set(fieldNames).size !== fieldNames.length) throw new Error(`Index '${name}' contains duplicate fields.`);\n\t\t\tfor (const fieldName of fieldNames) {\n\t\t\t\tif (!Object.hasOwn(tableFields, fieldName)) throw new Error(`Index '${name}' references unknown field '${fieldName}'.`);\n\t\t\t\tconst descriptor = getValueDescriptor(tableFields[fieldName]);\n\t\t\t\tif (!(descriptor?.type === \"boolean\" || descriptor?.type === \"date\" || descriptor?.type === \"id\" || descriptor?.type === \"integer\" || descriptor?.type === \"number\" || descriptor?.type === \"string\" || descriptor?.type === \"literal\" || descriptor?.type === \"literals\")) throw new Error(`Index '${name}' field '${fieldName}' is not indexable.`);\n\t\t\t\tif (descriptor.type === \"literals\" && !(descriptor.values.every(Schema.is(Schema.Boolean)) || descriptor.values.every(Schema.is(Schema.Finite)) || descriptor.values.every(Schema.is(Schema.String)))) throw new Error(`Index '${name}' field '${fieldName}' mixes value types.`);\n\t\t\t}\n\t\t\tconst duplicate = Object.values(indexes).find((candidate) => candidate.fields.length === fieldNames.length && candidate.fields.every((fieldName, position) => fieldName === fieldNames[position]));\n\t\t\tif (duplicate !== void 0) throw new Error(`Index '${name}' duplicates index '${duplicate.name}'.`);\n\t\t\tif (Object.keys(indexes).length >= schemaIndexLimits.indexesPerTable) throw new Error(`Tables cannot declare more than ${schemaIndexLimits.indexesPerTable} indexes.`);\n\t\t\treturn make({\n\t\t\t\t...indexes,\n\t\t\t\t[name]: {\n\t\t\t\t\tname,\n\t\t\t\t\tfields: fieldNames\n\t\t\t\t}\n\t\t\t});\n\t\t};\n\t\treturn {\n\t\t\t_tag: \"Table\",\n\t\t\tdescriptor: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tfields: descriptorFields(tableFields)\n\t\t\t},\n\t\t\tfields: tableFields,\n\t\t\tindex,\n\t\t\tindexes,\n\t\t\tschema: Schema.Struct(tableFields)\n\t\t};\n\t};\n\treturn make({});\n};\nconst fresh = (value) => value.pipe(Schema.annotate({}));\nconst string = () => attachValueDescriptor(fresh(Schema.String), { type: \"string\" });\nconst number = () => attachValueDescriptor(fresh(Schema.Finite), { type: \"number\" });\nconst integer = () => attachValueDescriptor(fresh(Schema.Int), { type: \"integer\" });\nconst boolean = () => attachValueDescriptor(fresh(Schema.Boolean), { type: \"boolean\" });\nconst date = () => attachValueDescriptor(fresh(Schema.DateFromMillis), { type: \"date\" });\nconst never = () => attachValueDescriptor(fresh(Schema.Never), { type: \"never\" });\nconst nullValue = () => attachValueDescriptor(fresh(Schema.Null), { type: \"null\" });\nconst literal = (value) => {\n\tSchema.decodeSync(LiteralValueSchema)(value);\n\treturn attachValueDescriptor(Schema.Literal(value), {\n\t\ttype: \"literal\",\n\t\tvalue\n\t});\n};\nconst literals = (...members) => {\n\tSchema.decodeSync(Schema.Array(LiteralValueSchema))(members);\n\treturn attachValueDescriptor(Schema.Literals(members), {\n\t\ttype: \"literals\",\n\t\tvalues: members\n\t});\n};\nconst makeIdSchema = (tableName) => {\n\tconst identifier = `ignotum/id/${tableName}`;\n\treturn attachValueDescriptor(GeneratedId.pipe(Schema.brand(identifier), Schema.annotate({ \"ignotum/table\": tableName })), {\n\t\ttype: \"id\",\n\t\ttable: tableName\n\t});\n};\nconst id = (tableName) => makeIdSchema(tableName);\nconst requireDescriptor = (value) => {\n\tconst descriptor = getValueDescriptor(value);\n\tif (descriptor === void 0) throw new Error(\"Ignotum value combinators require a values validator.\");\n\treturn descriptor;\n};\nconst array = (value) => {\n\treturn attachValueDescriptor(Schema.Array(value), {\n\t\ttype: \"array\",\n\t\tvalue: requireDescriptor(value)\n\t});\n};\nconst assertFieldsExist = (fields, keys, operation) => {\n\tfor (const key of keys) if (!Object.hasOwn(fields, key)) throw new Error(`Cannot ${operation} unknown field '${String(key)}'.`);\n};\nconst fixedObject = (fields) => {\n\tconst pick = (...keys) => {\n\t\tassertFieldsExist(fields, keys, \"pick\");\n\t\treturn fixedObject(Struct.pick(fields, keys));\n\t};\n\tconst omit = (...keys) => {\n\t\tassertFieldsExist(fields, keys, \"omit\");\n\t\treturn fixedObject(Struct.omit(fields, keys));\n\t};\n\tconst extend = (addedFields, ..._validation) => {\n\t\tfor (const key of Reflect.ownKeys(addedFields)) if (Object.hasOwn(fields, key)) throw new Error(`Cannot extend existing field '${String(key)}'.`);\n\t\treturn fixedObject(Struct.assign(fields, addedFields));\n\t};\n\tconst override = (overriddenFields, ..._validation) => {\n\t\tassertFieldsExist(fields, Reflect.ownKeys(overriddenFields), \"override\");\n\t\treturn fixedObject(Struct.assign(fields, overriddenFields));\n\t};\n\tconst partial = () => {\n\t\tconst partialFields = Struct.map(fields, Schema.optional);\n\t\tfor (const name of Reflect.ownKeys(fields)) {\n\t\t\tconst field = fields[name];\n\t\t\tconst partialField = partialFields[name];\n\t\t\tif (field === void 0 || partialField === void 0) continue;\n\t\t\tattachValueDescriptor(partialField, {\n\t\t\t\ttype: \"optional\",\n\t\t\t\tvalue: requireDescriptor(field)\n\t\t\t});\n\t\t}\n\t\treturn fixedObject(partialFields);\n\t};\n\tconst schema = attachValueDescriptor(Schema.Struct(fields), {\n\t\ttype: \"object\",\n\t\tfields: descriptorFields(fields)\n\t});\n\treturn Object.assign(schema, {\n\t\textend,\n\t\tomit,\n\t\toverride,\n\t\tpartial,\n\t\tpick\n\t});\n};\nconst object = (fields) => fixedObject(fields);\nconst optional = (value) => {\n\treturn attachValueDescriptor(Schema.optional(value), {\n\t\ttype: \"optional\",\n\t\tvalue: requireDescriptor(value)\n\t});\n};\nconst nullable = (value) => {\n\treturn attachValueDescriptor(Schema.NullOr(value), {\n\t\ttype: \"nullable\",\n\t\tvalue: requireDescriptor(value)\n\t});\n};\nconst record = (value) => {\n\treturn attachValueDescriptor(Schema.Record(Schema.String, value), {\n\t\ttype: \"record\",\n\t\tvalue: requireDescriptor(value)\n\t});\n};\nconst union = (...members) => {\n\treturn attachValueDescriptor(Schema.Union(members), {\n\t\ttype: \"union\",\n\t\tmembers: members.map(requireDescriptor)\n\t});\n};\nconst paginationCursor = () => attachValueDescriptor(fresh(PaginationCursor), { type: \"string\" });\nconst pagination = () => fixedObject({\n\tcursor: nullable(paginationCursor()),\n\tpageSize: attachValueDescriptor(fresh(PaginationPageSize), { type: \"integer\" })\n});\nconst page = (value) => {\n\treturn fixedObject({\n\t\titems: array(value),\n\t\tnextCursor: nullable(paginationCursor())\n\t});\n};\nconst error = (tag, fields) => {\n\tif (tag === \"InternalServerError\") throw new Error(\"The error tag 'InternalServerError' is reserved by Ignotum.\");\n\tconst errorFields = { ...fields };\n\tReflect.deleteProperty(errorFields, \"_tag\");\n\tconst schema = Schema.TaggedStruct(tag, errorFields).pipe(Schema.brand(ErrorBrand));\n\tconst make = (input) => schema.make(input);\n\tconst definition = Object.assign(make, schema);\n\tObject.setPrototypeOf(definition, Object.getPrototypeOf(schema));\n\tattachValueDescriptor(definition, {\n\t\ttype: \"error\",\n\t\ttag,\n\t\tfields: descriptorFields(errorFields)\n\t});\n\treturn definition;\n};\nconst values = {\n\tarray,\n\tboolean,\n\tdate,\n\terror,\n\tid,\n\tinteger,\n\tliteral,\n\tliterals,\n\tnever,\n\tnull: nullValue,\n\tnullable,\n\tnumber,\n\tobject,\n\toptional,\n\trecord,\n\tstring,\n\tunion\n};\nconst bindValues = (definition) => {\n\tconst boundId = (tableName) => makeIdSchema(tableName);\n\tconst doc = (tableName) => {\n\t\tconst tableDefinition = definition[tableName];\n\t\tif (tableDefinition === void 0) throw new Error(`Unknown table '${tableName}'.`);\n\t\tconst tableFields = tableDefinition.fields;\n\t\tconst systemFields = {\n\t\t\tid: boundId(tableName),\n\t\t\tcreatedAt: date(),\n\t\t\tupdatedAt: date()\n\t\t};\n\t\treturn fixedObject(Struct.assign(tableFields, systemFields));\n\t};\n\tconst boundPagination = () => {\n\t\treturn pagination();\n\t};\n\treturn {\n\t\t...values,\n\t\tdoc,\n\t\tid: boundId,\n\t\tpage,\n\t\tpagination: boundPagination\n\t};\n};\n//#endregion\nexport { bindValues, schemaIndexLimits, table, values };\n\n//# sourceMappingURL=values.js.map","//#region src/runtime/schema.ts\nconst FunctionSchemaTypeId = Symbol.for(\"ignotum/runtime/schema/FunctionSchema\");\nconst attachFunctionSchema = (schema) => (definition) => {\n\tObject.defineProperty(definition, FunctionSchemaTypeId, {\n\t\tconfigurable: false,\n\t\tenumerable: false,\n\t\tvalue: schema,\n\t\twritable: false\n\t});\n\treturn definition;\n};\nconst getFunctionSchema = (value) => value[FunctionSchemaTypeId];\n//#endregion\nexport { FunctionSchemaTypeId, attachFunctionSchema, getFunctionSchema };\n\n//# sourceMappingURL=schema.js.map","import { a as getValueDescriptor, n as ValueDescriptorTypeId, t as ValueDescriptor } from \"../descriptor-t6BOEGw9.js\";\nimport { Result } from \"../runtime/result.js\";\nimport { bindValues, schemaIndexLimits, table, values } from \"./values.js\";\nimport { attachFunctionSchema } from \"../runtime/schema.js\";\nimport { Predicate } from \"effect\";\n//#region src/schema/types.ts\nconst SchemaDefinitionTypeId = Symbol.for(\"ignotum/schema/SchemaDefinition\");\n//#endregion\n//#region src/schema/definition.ts\nconst defineSchema = (define) => {\n\tconst definitions = define({\n\t\ttable,\n\t\tvalues\n\t});\n\tif (Object.values(definitions).reduce((count, definition) => count + Object.keys(definition.indexes).length, 0) > schemaIndexLimits.indexesPerSchema) throw new Error(`Schemas cannot declare more than ${schemaIndexLimits.indexesPerSchema} indexes.`);\n\treturn {\n\t\t_tag: \"Schema\",\n\t\t[SchemaDefinitionTypeId]: definitions\n\t};\n};\nconst isDefinedSchema = (value) => value._tag === \"Schema\" && Predicate.isObject(value[SchemaDefinitionTypeId]);\n//#endregion\n//#region src/schema/server.ts\nconst makeFunctionBuilder = (schema, kind) => {\n\tconst define = (definition) => attachFunctionSchema(schema)({\n\t\t_tag: kind,\n\t\t...definition\n\t});\n\treturn define;\n};\nconst makeFunctionBuilders = (schema) => ({\n\tmutation: makeFunctionBuilder(schema, \"Mutation\"),\n\tquery: makeFunctionBuilder(schema, \"Query\")\n});\nconst bindSchema = (schema) => ({\n\tvalues: bindValues(schema[SchemaDefinitionTypeId]),\n\t...makeFunctionBuilders(schema)\n});\n//#endregion\nexport { Result, SchemaDefinitionTypeId, ValueDescriptor, ValueDescriptorTypeId, bindSchema, bindValues, defineSchema, getValueDescriptor, isDefinedSchema, schemaIndexLimits, table, values };\n\n//# sourceMappingURL=index.js.map"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { r as ErrorValue, s as Result$1 } from "./result-BgcHn25t.js";
2
- import { i as defineSchema$1, n as SchemaAuthoring, t as DefinedSchema } from "./index-Dl_VQGmA.js";
1
+ import { c as Result$1, i as ErrorValue } from "./id-Btwac71X-DhnKYsjY.js";
2
+ import { i as defineSchema$1, n as SchemaAuthoring, t as DefinedSchema } from "./index-B5KSOjGN.js";
3
3
  //#region src/server/index.d.ts
4
4
  declare const Result: typeof Result$1;
5
5
  type Result<Success, Failure extends ErrorValue> = Result$1<Success, Failure>;
@@ -1,5 +1,5 @@
1
- import { s as Result$1 } from "./descriptor-t6BOEGw9-BTHR-ZMv.js";
2
- import { r as defineSchema$1 } from "./schema-B-jMZEbs.js";
1
+ import { l as Result$1 } from "./descriptor-t6BOEGw9-C1rwYIlx.js";
2
+ import { r as defineSchema$1 } from "./schema-D9RmboaS.js";
3
3
  //#region src/server/index.ts
4
4
  const Result = Result$1;
5
5
  const defineSchema = defineSchema$1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ignotum",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Ignotum is an opinionated TypeScript application cloud.",
5
5
  "author": "Johannes Schießl",
6
6
  "repository": {
@@ -78,10 +78,10 @@
78
78
  "@effect/platform-node": "4.0.0-rc.111",
79
79
  "@effect/sql-sqlite-node": "4.0.0-rc.111",
80
80
  "redis": "6.2.1",
81
- "@ignotum/contracts": "1.0.0",
82
- "@ignotum/runtime": "1.0.0",
83
81
  "@ignotum/deployment": "1.0.0",
84
- "@ignotum/shared": "1.0.0"
82
+ "@ignotum/contracts": "1.0.0",
83
+ "@ignotum/shared": "1.0.0",
84
+ "@ignotum/runtime": "1.0.0"
85
85
  },
86
86
  "engines": {
87
87
  "node": ">=22.18.0"
@@ -7,9 +7,11 @@ import gettingStarted from "../../../../docs/user/getting-started.md?raw";
7
7
  import index from "../../../../docs/user/index.md?raw";
8
8
  import limits from "../../../../docs/user/limits.md?raw";
9
9
  import manualSetup from "../../../../docs/user/manual-setup.md?raw";
10
+ import readingData from "../../../../docs/user/reading-data.md?raw";
10
11
  import schema from "../../../../docs/user/schema.md?raw";
11
12
  import serverFunctions from "../../../../docs/user/server-functions.md?raw";
12
13
  import values from "../../../../docs/user/values.md?raw";
14
+ import writingData from "../../../../docs/user/writing-data.md?raw";
13
15
 
14
16
  export interface AppFile {
15
17
  readonly content: string;
@@ -24,9 +26,11 @@ const references = [
24
26
  ["index.md", index],
25
27
  ["limits.md", limits],
26
28
  ["manual-setup.md", manualSetup],
29
+ ["reading-data.md", readingData],
27
30
  ["schema.md", schema],
28
31
  ["server-functions.md", serverFunctions],
29
32
  ["values.md", values],
33
+ ["writing-data.md", writingData],
30
34
  ] as const;
31
35
 
32
36
  export const agentAppFiles: ReadonlyArray<AppFile> = [
@@ -1,9 +1,14 @@
1
1
  import { Effect, Schema } from "effect";
2
- import { useDebugValue, useEffect, useMemo, useState } from "preact/hooks";
2
+ import { useCallback, useDebugValue, useEffect, useMemo, useState } from "preact/hooks";
3
3
 
4
4
  import { functionPathOf, type FunctionReference } from "../internal/api.js";
5
- import { pending } from "@ignotum/contracts/runtime/result";
5
+ import { inspectResult, pending, Result as RuntimeResult } from "@ignotum/contracts/runtime/result";
6
6
  import type { ErrorValue, QueryResult, SettledResult } from "@ignotum/contracts/runtime/result";
7
+ import {
8
+ PaginationPageSize,
9
+ type PaginationOptions,
10
+ type PaginationPage,
11
+ } from "@ignotum/contracts/runtime/pagination";
7
12
  import { encodeTransportObject } from "@ignotum/contracts/runtime/sync";
8
13
  import {
9
14
  ClientInfrastructureError,
@@ -102,6 +107,163 @@ export function useQuery<Args extends object, Success, Failure extends ErrorValu
102
107
  return result;
103
108
  }
104
109
 
110
+ export type PaginationStatus = "CanLoadMore" | "Exhausted" | "LoadingMore";
111
+
112
+ export interface PaginatedQueryValue<Item> {
113
+ readonly items: ReadonlyArray<Item>;
114
+ readonly loadMore: () => void;
115
+ readonly status: PaginationStatus;
116
+ }
117
+
118
+ export interface PaginatedQueryOptions {
119
+ readonly pageSize?: number;
120
+ }
121
+
122
+ type PaginationArguments = { readonly pagination: PaginationOptions };
123
+ type ApplicationPaginationArguments<Args extends PaginationArguments> = Omit<Args, "pagination">;
124
+
125
+ // @effect-diagnostics-next-line missingPipeableSignature:off React hooks are not pipeable functions.
126
+ export function usePaginatedQuery<
127
+ Args extends PaginationArguments,
128
+ Item,
129
+ Failure extends ErrorValue,
130
+ >(
131
+ reference: keyof ApplicationPaginationArguments<Args> extends never
132
+ ? FunctionReference<"Query", Args, PaginationPage<Item>, Failure>
133
+ : never,
134
+ ): QueryResult<PaginatedQueryValue<Item>, Failure>;
135
+ export function usePaginatedQuery<
136
+ Args extends PaginationArguments,
137
+ Item,
138
+ Failure extends ErrorValue,
139
+ >(
140
+ reference: FunctionReference<"Query", Args, PaginationPage<Item>, Failure>,
141
+ args: NoInfer<ApplicationPaginationArguments<Args>> | QuerySkip,
142
+ options?: PaginatedQueryOptions,
143
+ ): QueryResult<PaginatedQueryValue<Item>, Failure>;
144
+ // @effect-diagnostics-next-line missingPipeableSignature:off React hooks must remain direct calls so hook order is statically visible.
145
+ export function usePaginatedQuery<Args extends object, Item, Failure extends ErrorValue>(
146
+ reference: FunctionReference<"Query", Args & PaginationArguments, PaginationPage<Item>, Failure>,
147
+ args?: Args | QuerySkip,
148
+ options: PaginatedQueryOptions = {},
149
+ ): QueryResult<PaginatedQueryValue<Item>, Failure> {
150
+ const functionPath = functionPathOf(reference);
151
+ const skipped = isQuerySkip(args);
152
+ const input = args === undefined || skipped ? {} : args;
153
+ const jsonArgs = encodeTransportObject(input);
154
+ const pageSize = Schema.decodeSync(PaginationPageSize)(options.pageSize ?? 20);
155
+ const identity = skipped
156
+ ? `skip:${functionPath}`
157
+ : syncClientInternals.queryIdentity(functionPath, jsonArgs);
158
+ const [requestedPages, setRequestedPages] = useState(1);
159
+ const [refresh, setRefresh] = useState(0);
160
+ const [state, setState] = useState<{
161
+ readonly identity: string;
162
+ readonly result: QueryResult<PaginatedQueryValue<Item>, Failure> | ClientInfrastructureError;
163
+ }>(() => ({ identity, result: pending() }));
164
+ const loadMore = useCallback(() => setRequestedPages((count) => count + 1), []);
165
+
166
+ useDebugValue({ args: input, function: functionPath, result: state.result });
167
+
168
+ useEffect(() => {
169
+ setRequestedPages(1);
170
+ setState({ identity, result: pending() });
171
+ }, [identity, pageSize]);
172
+
173
+ useEffect(() => {
174
+ if (skipped) return;
175
+
176
+ let active = true;
177
+ const releases: Array<() => void> = [];
178
+
179
+ void syncRuntime
180
+ .runPromise(
181
+ Effect.gen(function* () {
182
+ const client = yield* SyncClient;
183
+ const items: Item[] = [];
184
+ let cursor: PaginationOptions["cursor"] = null;
185
+
186
+ for (let pageNumber = 0; pageNumber < requestedPages; pageNumber += 1) {
187
+ const pageArgs = encodeTransportObject({
188
+ ...input,
189
+ pagination: { cursor, pageSize },
190
+ });
191
+ const observer = yield* client.observe(functionPath, pageArgs);
192
+ if (!active) {
193
+ yield* observer.release;
194
+ return;
195
+ }
196
+ const releaseSubscription = observer.subscribe(() => {
197
+ if (active) setRefresh((version) => version + 1);
198
+ });
199
+ releases.push(() => {
200
+ releaseSubscription();
201
+ syncRuntime.runFork(observer.release);
202
+ });
203
+
204
+ const snapshot = observer.getSnapshot();
205
+ if (Schema.is(ClientInfrastructureError)(snapshot)) {
206
+ setState({ identity, result: snapshot });
207
+ return;
208
+ }
209
+ const inspected = inspectResult(snapshot);
210
+ if (inspected === undefined) {
211
+ setState({
212
+ identity,
213
+ result:
214
+ items.length === 0
215
+ ? pending()
216
+ : RuntimeResult.succeed({ items, loadMore, status: "LoadingMore" }),
217
+ });
218
+ return;
219
+ }
220
+ if (inspected.type === "Failure") {
221
+ // SAFETY: pagination changes only the successful value. The
222
+ // failure channel is the generated query reference's Failure.
223
+ setState({
224
+ identity,
225
+ result: snapshot as QueryResult<PaginatedQueryValue<Item>, Failure>,
226
+ });
227
+ return;
228
+ }
229
+ // SAFETY: the generated reference and values.page validator couple
230
+ // this successful snapshot to PaginationPage<Item>.
231
+ const page = inspected.value as PaginationPage<Item>;
232
+ items.push(...page.items);
233
+ cursor = page.nextCursor;
234
+ if (cursor === null) {
235
+ setState({
236
+ identity,
237
+ result: RuntimeResult.succeed({ items, loadMore, status: "Exhausted" }),
238
+ });
239
+ return;
240
+ }
241
+ }
242
+
243
+ setState({
244
+ identity,
245
+ result: RuntimeResult.succeed({ items, loadMore, status: "CanLoadMore" }),
246
+ });
247
+ }),
248
+ )
249
+ .catch((error) => {
250
+ if (active && Schema.is(ClientInfrastructureError)(error)) {
251
+ setState({ identity, result: error });
252
+ }
253
+ });
254
+
255
+ return () => {
256
+ active = false;
257
+ for (const release of releases) release();
258
+ };
259
+ }, [functionPath, identity, loadMore, pageSize, refresh, requestedPages, skipped]);
260
+
261
+ if (skipped || state.identity !== identity) return pending();
262
+ const result = state.result;
263
+ if (Schema.is(ClientInfrastructureError)(result)) throw result;
264
+ return result;
265
+ }
266
+
105
267
  type Mutation<Args, Success, Failure extends ErrorValue> = [Args] extends [void]
106
268
  ? () => Promise<SettledResult<Success, Failure>>
107
269
  : (args: Args) => Promise<SettledResult<Success, Failure>>;
@@ -9,7 +9,8 @@ export const Result = { match: contractResult.match };
9
9
  export type Result<Value, Error extends ErrorValue> = SettledResult<Value, Error>;
10
10
  export type QueryResult<Value, Error extends ErrorValue> = ContractQueryResult<Value, Error>;
11
11
  export type { InternalServerError } from "@ignotum/contracts/runtime/result";
12
- export { useMutation, useQuery } from "./hooks.js";
12
+ export { useMutation, usePaginatedQuery, useQuery } from "./hooks.js";
13
+ export type { PaginatedQueryOptions, PaginatedQueryValue, PaginationStatus } from "./hooks.js";
13
14
  export { Query } from "./query.js";
14
15
  export type { QuerySkip } from "./query.js";
15
16
  export { app } from "./app.js";