ignotum 0.0.14 → 0.0.16

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 (127) hide show
  1. package/README.md +6 -6
  2. package/dist/cli/bin.mjs +6042 -4693
  3. package/dist/cli/bin.mjs.map +1 -1
  4. package/dist/cli/emscripten-module-D5GzfUNv.mjs +533 -0
  5. package/dist/cli/emscripten-module-D5GzfUNv.mjs.map +1 -0
  6. package/dist/cli/ffi-7IElU4Co.mjs +148 -0
  7. package/dist/cli/ffi-7IElU4Co.mjs.map +1 -0
  8. package/dist/cli/managed-release-WHYLZwaS.mjs +10902 -0
  9. package/dist/cli/managed-release-WHYLZwaS.mjs.map +1 -0
  10. package/dist/cli/managed-release.d.mts +1 -0
  11. package/dist/cli/managed-release.mjs +14 -0
  12. package/dist/cli/managed-release.mjs.map +1 -0
  13. package/dist/cli/module-ES6BEMUI-D36I4NVn.mjs +1289 -0
  14. package/dist/cli/module-ES6BEMUI-D36I4NVn.mjs.map +1 -0
  15. package/dist/runtime/{api-Cv3hMbzo.d.ts → api-B4fwp5a2.d.ts} +4 -4
  16. package/dist/runtime/bootstrap-BISQSn_O.js +916 -0
  17. package/dist/runtime/bootstrap-BISQSn_O.js.map +1 -0
  18. package/dist/runtime/bootstrap-BTFScKAc.d.ts +545 -0
  19. package/dist/runtime/client.d.ts +50 -15
  20. package/dist/runtime/client.js +7 -1158
  21. package/dist/runtime/client.js.map +1 -1
  22. package/dist/runtime/{descriptor-DCCz5AHd-_nhlnu8U.js → descriptor-CTY4mtwS-cS43EbwS.js} +3 -32
  23. package/dist/runtime/descriptor-CTY4mtwS-cS43EbwS.js.map +1 -0
  24. package/dist/runtime/{id-Bt9XWRGL.js → id--1m0NuUL.js} +4 -4
  25. package/dist/runtime/id--1m0NuUL.js.map +1 -0
  26. package/dist/runtime/{id-BzFHf3Wo-DGPCjgrf.d.ts → id-7an3nxTu-DZJSM5xh.d.ts} +2 -2
  27. package/dist/runtime/id-CBOt2kDo.d.ts +1 -0
  28. package/dist/runtime/identity-QjtJRxBD.d.ts +2 -0
  29. package/dist/runtime/image-Djtjy4Z8.js +19 -0
  30. package/dist/runtime/image-Djtjy4Z8.js.map +1 -0
  31. package/dist/runtime/{index-DWU-7TIh.d.ts → index-D4seNHlX.d.ts} +3 -4
  32. package/dist/runtime/internal/api.d.ts +1 -1
  33. package/dist/runtime/internal/api.js +30 -1
  34. package/dist/runtime/internal/api.js.map +1 -0
  35. package/dist/runtime/internal/bootstrap.d.ts +2 -0
  36. package/dist/runtime/internal/bootstrap.js +2 -0
  37. package/dist/runtime/internal/client.d.ts +2 -0
  38. package/dist/runtime/internal/client.js +75 -0
  39. package/dist/runtime/internal/client.js.map +1 -0
  40. package/dist/runtime/internal/host.d.ts +6 -7
  41. package/dist/runtime/internal/host.js +5 -4
  42. package/dist/runtime/internal/host.js.map +1 -1
  43. package/dist/runtime/internal/routes.d.ts +2 -0
  44. package/dist/runtime/internal/routes.js +2 -0
  45. package/dist/runtime/internal/server.d.ts +1 -1
  46. package/dist/runtime/internal/server.js +1 -1
  47. package/dist/runtime/internal/types.d.ts +2 -2
  48. package/dist/runtime/internal/types.js +1 -1
  49. package/dist/runtime/pagination-CBOt2kDo.d.ts +1 -0
  50. package/dist/runtime/pagination-D3qd6s9N.js +33 -0
  51. package/dist/runtime/pagination-D3qd6s9N.js.map +1 -0
  52. package/dist/runtime/result-BkziOG1L.d.ts +1 -0
  53. package/dist/runtime/router-BSBI1oN1.js +2377 -0
  54. package/dist/runtime/router-BSBI1oN1.js.map +1 -0
  55. package/dist/runtime/routes-Ce8TVP-T.js +690 -0
  56. package/dist/runtime/routes-Ce8TVP-T.js.map +1 -0
  57. package/dist/runtime/{schema-DqogEydG.js → schema-D1wOqiNH.js} +4 -3
  58. package/dist/runtime/schema-D1wOqiNH.js.map +1 -0
  59. package/dist/runtime/server.d.ts +5 -6
  60. package/dist/runtime/server.js +2 -2
  61. package/dist/runtime/{sync-Bs8J3fIr.d.ts → sync-D-GK2sv9.d.ts} +3 -2
  62. package/dist/runtime/{api-CAgKDij7.js → sync-DzUwA8W9.js} +22 -41
  63. package/dist/runtime/sync-DzUwA8W9.js.map +1 -0
  64. package/dist/runtime/{types-C1iDP2Yf-BnkfBOQf.d.ts → types-DeCCyqLU-BIm7rU-0.d.ts} +123 -6
  65. package/package.json +30 -5
  66. package/src/cli/agent-files.ts +10 -8
  67. package/src/cli/build/managed-client.ts +411 -0
  68. package/src/cli/build/managed-server.ts +294 -0
  69. package/src/cli/build/managed.ts +67 -0
  70. package/src/cli/build/output.ts +47 -0
  71. package/src/cli/build/server.ts +49 -247
  72. package/src/cli/client-config.ts +1 -140
  73. package/src/cli/client-styles.ts +1 -0
  74. package/src/cli/codegen.ts +9 -4
  75. package/src/cli/command.ts +9 -9
  76. package/src/cli/control-client.ts +88 -103
  77. package/src/cli/deploy.ts +120 -184
  78. package/src/cli/dev.ts +506 -107
  79. package/src/cli/image-assets.ts +499 -0
  80. package/src/cli/managed-client-boundaries.ts +103 -0
  81. package/src/cli/managed-dev-platform.ts +118 -0
  82. package/src/cli/managed-exports.ts +219 -0
  83. package/src/cli/managed-release-bin.ts +13 -0
  84. package/src/cli/managed-release.ts +260 -0
  85. package/src/cli/module-boundaries.ts +11 -1
  86. package/src/cli/new-app.ts +111 -87
  87. package/src/cli/route-codegen.ts +311 -0
  88. package/src/cli/route-static.ts +710 -0
  89. package/src/client/bootstrap.ts +110 -0
  90. package/src/client/errors.ts +13 -7
  91. package/src/client/files.ts +64 -0
  92. package/src/client/id.ts +9 -5
  93. package/src/client/image.ts +28 -0
  94. package/src/client/index.ts +25 -2
  95. package/src/client/managed-client.ts +729 -0
  96. package/src/client/managed-upgrade.ts +283 -0
  97. package/src/client/recovery-journal.ts +195 -0
  98. package/src/client/route-boundaries.ts +184 -0
  99. package/src/client/router-history.ts +152 -0
  100. package/src/client/router-store.ts +644 -0
  101. package/src/client/router.ts +324 -0
  102. package/src/client/routes.ts +28 -0
  103. package/src/client/sync.ts +65 -591
  104. package/src/dev-runtime/database.ts +2 -2
  105. package/src/dev-runtime/functions.ts +3 -3
  106. package/src/dev-runtime/managed-functions.ts +255 -0
  107. package/src/dev-runtime/managed-sync.ts +263 -0
  108. package/src/dev-runtime/managed-websocket.ts +71 -0
  109. package/src/dev-runtime/migrations.ts +11 -0
  110. package/src/dev-runtime/sync.ts +236 -236
  111. package/src/image-assets.d.ts +36 -0
  112. package/src/internal/client.ts +186 -0
  113. package/src/internal/http-paths.ts +0 -3
  114. package/src/internal/routes.ts +45 -0
  115. package/dist/runtime/api-CAgKDij7.js.map +0 -1
  116. package/dist/runtime/descriptor-DCCz5AHd-_nhlnu8U.js.map +0 -1
  117. package/dist/runtime/id-Bt9XWRGL.js.map +0 -1
  118. package/dist/runtime/id-E7JKqQ9r.d.ts +0 -1
  119. package/dist/runtime/pagination-CpYCaRYD-C2Rpp4Cw.d.ts +0 -122
  120. package/dist/runtime/pagination-E7JKqQ9r.d.ts +0 -1
  121. package/dist/runtime/result-DKAA4gpS.d.ts +0 -1
  122. package/dist/runtime/schema-DqogEydG.js.map +0 -1
  123. package/src/cli/build/client.ts +0 -119
  124. package/src/cli/build/public.ts +0 -186
  125. package/src/cli/client-entry.ts +0 -152
  126. package/src/cli/client-plugin.ts +0 -136
  127. package/src/client/app.ts +0 -15
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema-DqogEydG.js","names":["utf8ByteLength","Result$1"],"sources":["../../../contracts/dist/schema/values.js","../../../contracts/dist/runtime/schema.js","../../../contracts/dist/schema/index.js"],"sourcesContent":["import { GeneratedId } from \"../runtime/id.js\";\nimport { FileFormat, constrainedFileValue, fileFormats, fileLimits } from \"./file.js\";\nimport { ErrorBrand } from \"../runtime/result.js\";\nimport { UserId } from \"../id.js\";\nimport { c as getValueDescriptor, f as validateFieldRenames, p as withValueChildren, r as attachValueDescriptor, s as descriptorFields } from \"../descriptor-DCCz5AHd.js\";\nimport { PaginationCursor, PaginationPageSize } from \"../runtime/pagination.js\";\nimport { Redacted, 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\tvalidateFieldRenames(tableFields);\n\tconst make = (indexes, schema = withValueChildren(attachValueDescriptor(Schema.Struct(tableFields), {\n\t\ttype: \"object\",\n\t\tfields: descriptorFields(tableFields)\n\t}), {\n\t\ttype: \"object\",\n\t\tfields: tableFields\n\t})) => {\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}, schema);\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\tfrom: (previous, convert) => make(indexes, schema.from(previous, convert)),\n\t\t\tindex,\n\t\t\tindexes,\n\t\t\tschema\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 file = (options = {}) => {\n\tconst formats = options.formats ?? fileFormats;\n\tif (formats.length === 0) throw new Error(\"File format lists cannot be empty.\");\n\tSchema.decodeUnknownSync(Schema.Array(FileFormat))(formats);\n\tif (new Set(formats).size !== formats.length) throw new Error(\"File format lists cannot contain duplicates.\");\n\tconst maxBytes = options.maxBytes ?? fileLimits.fileBytes;\n\tif (!Number.isSafeInteger(maxBytes) || maxBytes <= 0 || maxBytes > fileLimits.fileBytes) throw new Error(`File sizes must be between 1 and ${fileLimits.fileBytes} bytes.`);\n\treturn attachValueDescriptor(constrainedFileValue(formats, maxBytes), {\n\t\ttype: \"file\",\n\t\tformats: [...formats],\n\t\tmaxBytes\n\t});\n};\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 userId = () => attachValueDescriptor(fresh(UserId), { type: \"userId\" });\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 withValueChildren(attachValueDescriptor(Schema.Array(value), {\n\t\ttype: \"array\",\n\t\tvalue: requireDescriptor(value)\n\t}), {\n\t\ttype: \"array\",\n\t\tvalue\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\tvalidateFieldRenames(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 = withValueChildren(attachValueDescriptor(Schema.Struct(fields), {\n\t\ttype: \"object\",\n\t\tfields: descriptorFields(fields)\n\t}), {\n\t\ttype: \"object\",\n\t\tfields\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 withValueChildren(attachValueDescriptor(Schema.optional(value), {\n\t\ttype: \"optional\",\n\t\tvalue: requireDescriptor(value)\n\t}), {\n\t\ttype: \"optional\",\n\t\tvalue\n\t});\n};\nconst nullable = (value) => {\n\treturn withValueChildren(attachValueDescriptor(Schema.NullOr(value), {\n\t\ttype: \"nullable\",\n\t\tvalue: requireDescriptor(value)\n\t}), {\n\t\ttype: \"nullable\",\n\t\tvalue\n\t});\n};\nconst record = (value) => {\n\treturn withValueChildren(attachValueDescriptor(Schema.Record(Schema.String, value), {\n\t\ttype: \"record\",\n\t\tvalue: requireDescriptor(value)\n\t}), {\n\t\ttype: \"record\",\n\t\tvalue\n\t});\n};\nconst union = (...members) => {\n\treturn withValueChildren(attachValueDescriptor(Schema.Union(members), {\n\t\ttype: \"union\",\n\t\tmembers: members.map(requireDescriptor)\n\t}), {\n\t\ttype: \"union\",\n\t\tmembers\n\t});\n};\nconst Secret = {\n\tisSecret: Redacted.isRedacted,\n\tvalue: Redacted.value\n};\nfunction secret(value = string()) {\n\treturn attachValueDescriptor(Schema.RedactedFromValue(value, { disallowEncode: true }), {\n\t\ttype: \"secret\",\n\t\tvalue: requireDescriptor(value)\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\tuserId,\n\tarray,\n\tboolean,\n\tdate,\n\tfile,\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 environmentValues = {\n\tarray,\n\tboolean,\n\tdate,\n\tinteger,\n\tliteral,\n\tliterals,\n\tnever,\n\tnull: nullValue,\n\tnullable,\n\tnumber,\n\tobject,\n\toptional,\n\trecord,\n\tsecret,\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 { Secret, bindValues, environmentValues, schemaIndexLimits, table, values };\n\n//# sourceMappingURL=values.js.map","//#region src/runtime/schema.ts\nconst FunctionSchemaTypeId = Symbol.for(\"ignotum/runtime/schema/FunctionSchema\");\nconst FunctionEnvironmentTypeId = Symbol.for(\"ignotum/runtime/schema/FunctionEnvironment\");\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];\nconst attachFunctionEnvironment = (environment) => (definition) => {\n\tObject.defineProperty(definition, FunctionEnvironmentTypeId, {\n\t\tconfigurable: false,\n\t\tenumerable: false,\n\t\tvalue: environment,\n\t\twritable: false\n\t});\n\treturn definition;\n};\nconst getFunctionEnvironment = (value) => value[FunctionEnvironmentTypeId];\n//#endregion\nexport { FunctionEnvironmentTypeId, FunctionSchemaTypeId, attachFunctionEnvironment, attachFunctionSchema, getFunctionEnvironment, getFunctionSchema };\n\n//# sourceMappingURL=schema.js.map","import { FileFormat, FileId, FileValue, FileValueTypeId, fileFormats, fileLimits, fileMimeTypes, isFileValue } from \"./file.js\";\nimport { Result } from \"../runtime/result.js\";\nimport { a as descriptorContainsFile, c as getValueDescriptor, d as evolveStoredValue, i as descriptorAllowedInEnvironment, l as applyValueDefaults, n as ValueDescriptorTypeId, o as descriptorContainsSecret, s as descriptorFields, t as ValueDescriptor, u as evolveStoredFields } from \"../descriptor-DCCz5AHd.js\";\nimport { Secret, bindValues, environmentValues, schemaIndexLimits, table, values } from \"./values.js\";\nimport { attachFunctionEnvironment, attachFunctionSchema } from \"../runtime/schema.js\";\nimport { Effect, Predicate, Result as Result$1, Schema } 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/environment.ts\nconst EnvironmentDefinitionTypeId = Symbol.for(\"ignotum/schema/EnvironmentDefinition\");\nconst EnvironmentDecoderTypeId = Symbol.for(\"ignotum/schema/EnvironmentDecoder\");\nconst environmentLimits = {\n\tbytes: 65536,\n\tvariables: 128\n};\nvar EnvironmentValueInvalid = class extends Schema.TaggedError()(\"EnvironmentValueInvalid\", {\n\tkey: Schema.optional(Schema.String),\n\tmessage: Schema.String\n}) {};\nconst environmentName = /^[A-Z_][A-Z0-9_]*$/;\nconst defineEnv = (define) => {\n\tconst fields = define({ values: environmentValues });\n\tif (Reflect.ownKeys(fields).length > environmentLimits.variables) throw new Error(`Environments cannot declare more than ${environmentLimits.variables} variables.`);\n\tfor (const name of Reflect.ownKeys(fields)) {\n\t\tif (!Predicate.isString(name)) throw new Error(\"Environment variable names must be strings.\");\n\t\tif (!environmentName.test(name)) throw new Error(`Environment variable '${name}' must match ${environmentName.source}.`);\n\t\tif (name.startsWith(\"IGNOTUM_\")) throw new Error(`Environment variable '${name}' uses the reserved IGNOTUM_ prefix.`);\n\t}\n\tconst descriptors = descriptorFields(fields);\n\tfor (const field of descriptors) if (!descriptorAllowedInEnvironment(field.value)) throw new Error(`Environment variable '${field.name}' uses an unsupported validator.`);\n\tconst environment = {\n\t\t_tag: \"Environment\",\n\t\tfields,\n\t\tdescriptors,\n\t\tschema: Schema.Struct(fields),\n\t\t[EnvironmentDefinitionTypeId]: fields\n\t};\n\tObject.defineProperty(environment, EnvironmentDecoderTypeId, {\n\t\tenumerable: false,\n\t\tvalue: (raw) => decodeEnvironment(environment, raw)\n\t});\n\treturn Object.freeze(environment);\n};\nconst emptyEnv = defineEnv(() => ({}));\nconst isDefinedEnv = (value) => value._tag === \"Environment\" && Predicate.isObject(value[EnvironmentDefinitionTypeId]);\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 invalidValue = (key) => EnvironmentValueInvalid.make({\n\tkey,\n\tmessage: `Environment variable '${key}' does not match its declaration.`\n});\nconst decodeEnvironment = Effect.fn(\"Environment.decode\")(function* (environment, raw) {\n\tconst declared = new Set(Object.keys(environment.fields));\n\tconst supplied = Object.keys(raw);\n\tif (supplied.length > environmentLimits.variables) return yield* EnvironmentValueInvalid.make({ message: `Environments cannot contain more than ${environmentLimits.variables} variables.` });\n\tconst rawJson = JSON.stringify(raw);\n\tif (utf8ByteLength(rawJson) > environmentLimits.bytes) return yield* EnvironmentValueInvalid.make({ message: `Environments cannot exceed ${environmentLimits.bytes} UTF-8 bytes.` });\n\tfor (const key of supplied) if (!declared.has(key)) return yield* EnvironmentValueInvalid.make({\n\t\tkey,\n\t\tmessage: `Environment variable '${key}' is not declared in server/env.ts.`\n\t});\n\tconst decoded = {};\n\tfor (const [key, field] of Object.entries(environment.fields)) {\n\t\tconst input = Object.hasOwn(raw, key) ? raw[key] : void 0;\n\t\tconst direct = yield* Effect.result(Schema.decodeUnknownEffect(field)(input));\n\t\tif (Result$1.isSuccess(direct)) {\n\t\t\tif (direct.success !== void 0) Reflect.set(decoded, key, direct.success);\n\t\t\tcontinue;\n\t\t}\n\t\tif (input === void 0) return yield* invalidValue(key);\n\t\tconst parsed = yield* Effect.result(Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))(input));\n\t\tif (Result$1.isFailure(parsed)) return yield* invalidValue(key);\n\t\tconst fromJson = yield* Effect.result(Schema.decodeUnknownEffect(field)(parsed.success));\n\t\tif (Result$1.isFailure(fromJson)) return yield* invalidValue(key);\n\t\tif (fromJson.success !== void 0) Reflect.set(decoded, key, fromJson.success);\n\t}\n\treturn Object.freeze(decoded);\n});\nconst decodeDefinedEnvironment = (environment, raw) => environment[EnvironmentDecoderTypeId](raw);\n//#endregion\n//#region src/schema/server.ts\nconst makeFunctionBuilder = (schema, environment, kind) => {\n\tconst define = (definition) => attachFunctionEnvironment(environment)(attachFunctionSchema(schema)({\n\t\t_tag: kind,\n\t\t...definition\n\t}));\n\treturn define;\n};\nconst makeFunctionBuilders = (schema, environment) => ({\n\tmutation: makeFunctionBuilder(schema, environment, \"Mutation\"),\n\tquery: makeFunctionBuilder(schema, environment, \"Query\")\n});\nfunction bindSchema(schema, environment = emptyEnv) {\n\treturn {\n\t\tvalues: bindValues(schema[SchemaDefinitionTypeId]),\n\t\t...makeFunctionBuilders(schema, environment)\n\t};\n}\n//#endregion\nexport { EnvironmentDefinitionTypeId, EnvironmentValueInvalid, FileFormat, FileId, FileValue, FileValueTypeId, Result, SchemaDefinitionTypeId, Secret, ValueDescriptor, ValueDescriptorTypeId, applyValueDefaults, bindSchema, bindValues, decodeDefinedEnvironment, decodeEnvironment, defineEnv, defineSchema, descriptorAllowedInEnvironment, descriptorContainsFile, descriptorContainsSecret, descriptorFields, emptyEnv, environmentLimits, environmentValues, evolveStoredFields, evolveStoredValue, fileFormats, fileLimits, fileMimeTypes, getValueDescriptor, isDefinedEnv, isDefinedSchema, isFileValue, schemaIndexLimits, table, values };\n\n//# sourceMappingURL=index.js.map"],"mappings":"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"}
@@ -1,119 +0,0 @@
1
- import { Array, Effect, FileSystem, Path, String } from "effect";
2
- import tailwindcss from "@tailwindcss/vite";
3
- import { ClientManifest, clientShellPath } from "@ignotum/contracts/deployment";
4
- import { artifactReference, encodeCanonical, sha256, utf8Bytes } from "@ignotum/deployment";
5
-
6
- import { resolveClientBuildConfig, validateClientFiles } from "../client-config.js";
7
- import { loadClientEntryTitle } from "../client-entry.js";
8
- import { clientEntryId, ignotumClientPlugin, renderClientDocument } from "../client-plugin.js";
9
- import { moduleBoundariesPlugin } from "../module-boundaries.js";
10
- import { InvalidBuildOutput, runViteBuild } from "./artifact.js";
11
- import { copyPublicFiles } from "./public.js";
12
-
13
- export interface ClientBuildResult {
14
- readonly assets: number;
15
- readonly manifestPath: string;
16
- readonly shellPath: string;
17
- }
18
-
19
- export const buildClient = Effect.fn("Deploy.buildClient")(function* (
20
- appDirectory: string,
21
- outputDirectory: string,
22
- ) {
23
- const fileSystem = yield* FileSystem.FileSystem;
24
- const path = yield* Path.Path;
25
- const clientFiles = yield* validateClientFiles(appDirectory);
26
- const clientDirectory = clientFiles.clientDirectory;
27
- const title = yield* loadClientEntryTitle(clientFiles.entryPath);
28
- const clientConfig = yield* resolveClientBuildConfig(false);
29
- const boundaries = yield* moduleBoundariesPlugin("Client", appDirectory);
30
-
31
- yield* fileSystem.makeDirectory(outputDirectory, { recursive: true });
32
-
33
- const output = yield* runViteBuild("client", {
34
- appType: "spa",
35
- build: {
36
- assetsDir: "assets",
37
- emptyOutDir: true,
38
- outDir: outputDirectory,
39
- rolldownOptions: {
40
- input: clientEntryId,
41
- output: {
42
- assetFileNames: (asset) =>
43
- asset.names.some((name) => name.endsWith(".css"))
44
- ? "assets/styles-[hash][extname]"
45
- : "assets/[name]-[hash][extname]",
46
- chunkFileNames: "assets/chunks/[name]-[hash].js",
47
- entryFileNames: "assets/main-[hash].js",
48
- },
49
- },
50
- sourcemap: false,
51
- },
52
- configFile: false,
53
- logLevel: "warn",
54
- mode: "production",
55
- oxc: {
56
- jsx: {
57
- importSource: "ignotum/client",
58
- runtime: "automatic",
59
- },
60
- },
61
- plugins: [
62
- boundaries,
63
- ignotumClientPlugin({ development: false, icon: undefined, loadTitle: undefined }),
64
- tailwindcss(),
65
- ],
66
- publicDir: false,
67
- resolve: {
68
- alias: clientConfig.aliases,
69
- conditions: [...clientConfig.conditions],
70
- dedupe: ["preact"],
71
- tsconfigPaths: true,
72
- },
73
- root: clientDirectory,
74
- });
75
- const entry = Array.findFirst(output, (item) => item.type === "chunk" && item.isEntry);
76
- const entryFile = yield* Effect.fromOption(entry, () =>
77
- InvalidBuildOutput.make({ message: "The client build did not emit an entry chunk." }),
78
- ).pipe(Effect.map((item) => item.fileName));
79
- const styles = Array.sort(String.Order)(
80
- Array.map(
81
- Array.filter(output, (item) => item.type === "asset" && item.fileName.endsWith(".css")),
82
- (item) => item.fileName,
83
- ),
84
- );
85
- let icon: string | undefined;
86
- if (clientFiles.iconPath !== undefined) {
87
- const bytes = yield* fileSystem.readFile(clientFiles.iconPath);
88
- const digest = yield* sha256(bytes);
89
- const fileName = `icon-${digest.slice(0, 16)}.svg`;
90
- const assetsDirectory = path.join(outputDirectory, "assets");
91
- yield* fileSystem.makeDirectory(assetsDirectory, { recursive: true });
92
- yield* fileSystem.writeFile(path.join(assetsDirectory, fileName), bytes);
93
- icon = `/_ignotum/assets/${fileName}`;
94
- }
95
- const shellPath = path.join(outputDirectory, "shell.html");
96
- const document = renderClientDocument({
97
- icon,
98
- scripts: [{ source: `_ignotum/${entryFile}`, type: "External" }],
99
- styles: styles.map((style) => `_ignotum/${style}`),
100
- title,
101
- });
102
-
103
- const shellBytes = utf8Bytes(document);
104
- yield* fileSystem.writeFile(shellPath, shellBytes);
105
- const publicBuild = yield* copyPublicFiles(appDirectory, outputDirectory);
106
- const manifest = {
107
- formatVersion: 1,
108
- shell: yield* artifactReference(clientShellPath, shellBytes),
109
- routes: publicBuild.routes,
110
- } satisfies ClientManifest;
111
- const manifestPath = path.join(outputDirectory, "manifest.json");
112
- yield* fileSystem.writeFileString(manifestPath, `${encodeCanonical(ClientManifest, manifest)}\n`);
113
-
114
- return {
115
- assets: output.length + (icon === undefined ? 0 : 1) + publicBuild.files,
116
- manifestPath,
117
- shellPath,
118
- } satisfies ClientBuildResult;
119
- });
@@ -1,186 +0,0 @@
1
- import {
2
- ArtifactPath,
3
- ClientPath,
4
- clientPublicFileExtensions,
5
- deploymentArtifactLimits,
6
- type ClientRoute,
7
- } from "@ignotum/contracts/deployment";
8
- import { artifactReference } from "@ignotum/deployment";
9
- import { Effect, FileSystem, Option, Path, Schema } from "effect";
10
-
11
- export class InvalidPublicFile extends Schema.TaggedError<InvalidPublicFile>()(
12
- "InvalidPublicFile",
13
- {
14
- message: Schema.String,
15
- path: Schema.String,
16
- },
17
- ) {}
18
-
19
- export interface PublicBuildResult {
20
- readonly files: number;
21
- readonly routes: ReadonlyArray<ClientRoute>;
22
- }
23
-
24
- interface PublicFile {
25
- readonly bytes: Uint8Array;
26
- readonly destination: string;
27
- readonly route: ClientRoute;
28
- readonly source: string;
29
- }
30
-
31
- const pathSegmentPattern = /^[A-Za-z0-9._~-]+$/;
32
-
33
- const startsWith = (bytes: Uint8Array, signature: ReadonlyArray<number>, offset = 0): boolean =>
34
- signature.every((byte, index) => bytes[offset + index] === byte);
35
-
36
- const asciiAt = (bytes: Uint8Array, value: string, offset = 0): boolean =>
37
- startsWith(
38
- bytes,
39
- globalThis.Array.from(value, (character) => character.charCodeAt(0)),
40
- offset,
41
- );
42
-
43
- const hasValidSignature = (extension: string, bytes: Uint8Array): boolean => {
44
- switch (extension) {
45
- case ".avif": {
46
- if (!asciiAt(bytes, "ftyp", 4)) return false;
47
- const headerLength = Math.min(bytes.length, 64);
48
- for (let offset = 8; offset + 4 <= headerLength; offset += 4) {
49
- if (asciiAt(bytes, "avif", offset) || asciiAt(bytes, "avis", offset)) return true;
50
- }
51
- return false;
52
- }
53
- case ".gif":
54
- return asciiAt(bytes, "GIF87a") || asciiAt(bytes, "GIF89a");
55
- case ".ico":
56
- return startsWith(bytes, [0x00, 0x00, 0x01, 0x00]);
57
- case ".jpeg":
58
- case ".jpg":
59
- return startsWith(bytes, [0xff, 0xd8, 0xff]);
60
- case ".pdf":
61
- return asciiAt(bytes, "%PDF-");
62
- case ".png":
63
- return startsWith(bytes, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
64
- case ".webp":
65
- return asciiAt(bytes, "RIFF") && asciiAt(bytes, "WEBP", 8);
66
- default:
67
- return false;
68
- }
69
- };
70
-
71
- const invalid = (path: string, message: string) => InvalidPublicFile.make({ message, path });
72
-
73
- export const copyPublicFiles = Effect.fn("Deploy.copyPublicFiles")(function* (
74
- appDirectory: string,
75
- outputDirectory: string,
76
- ) {
77
- const fileSystem = yield* FileSystem.FileSystem;
78
- const path = yield* Path.Path;
79
- const publicDirectory = path.join(appDirectory, "public");
80
- if (!(yield* fileSystem.exists(publicDirectory))) {
81
- return { files: 0, routes: [] } satisfies PublicBuildResult;
82
- }
83
-
84
- if (Option.isSome(yield* Effect.option(fileSystem.readLink(publicDirectory)))) {
85
- return yield* invalid(
86
- publicDirectory,
87
- "The top-level public directory cannot be a symbolic link.",
88
- );
89
- }
90
- const publicInfo = yield* fileSystem.stat(publicDirectory);
91
- if (publicInfo.type !== "Directory") {
92
- return yield* invalid(publicDirectory, "The top-level public path must be a directory.");
93
- }
94
-
95
- const entries = (yield* fileSystem.readDirectory(publicDirectory, {
96
- recursive: true,
97
- })).toSorted();
98
- const publicFiles = yield* Effect.forEach(entries, (entry) =>
99
- Effect.gen(function* () {
100
- const relativePath = entry.replaceAll("\\", "/");
101
- const source = path.join(publicDirectory, entry);
102
- if (Option.isSome(yield* Effect.option(fileSystem.readLink(source)))) {
103
- return yield* invalid(source, "Public entries cannot be symbolic links.");
104
- }
105
- const info = yield* fileSystem.stat(source);
106
- if (info.type === "Directory") return undefined;
107
- if (info.type !== "File") {
108
- return yield* invalid(source, "Public entries must be regular files or directories.");
109
- }
110
-
111
- const segments = relativePath.split("/");
112
- if (segments.some((segment) => !pathSegmentPattern.test(segment))) {
113
- return yield* invalid(
114
- source,
115
- "Public file paths may only contain letters, numbers, dots, underscores, tildes, hyphens, and directory separators.",
116
- );
117
- }
118
- if (segments[0] === "_ignotum") {
119
- return yield* invalid(source, "The /_ignotum namespace is reserved by the platform.");
120
- }
121
-
122
- const extension = path.extname(relativePath).toLowerCase();
123
- if (!clientPublicFileExtensions.some((allowedExtension) => allowedExtension === extension)) {
124
- return yield* invalid(
125
- source,
126
- `Unsupported public file type '${extension || "(none)"}'. Allowed types: ${clientPublicFileExtensions.join(", ")}.`,
127
- );
128
- }
129
- if (info.size > BigInt(deploymentArtifactLimits.fileBytes)) {
130
- return yield* invalid(
131
- source,
132
- `Public files cannot exceed ${deploymentArtifactLimits.fileBytes} bytes.`,
133
- );
134
- }
135
-
136
- const bytes = yield* fileSystem.readFile(source);
137
- if (!hasValidSignature(extension, bytes)) {
138
- return yield* invalid(
139
- source,
140
- `The contents do not match the '${extension}' file extension.`,
141
- );
142
- }
143
-
144
- const pathname = `/${relativePath}`;
145
- return {
146
- bytes,
147
- destination: path.join(outputDirectory, "routes", entry),
148
- route: {
149
- pathname: ClientPath.make(pathname),
150
- artifact: yield* artifactReference(
151
- ArtifactPath.make(`client/routes/${relativePath}`),
152
- bytes,
153
- ),
154
- },
155
- source,
156
- } satisfies PublicFile;
157
- }),
158
- );
159
- const files = publicFiles.filter((file): file is PublicFile => file !== undefined);
160
-
161
- yield* Effect.forEach(files, (file) =>
162
- Effect.gen(function* () {
163
- if (yield* fileSystem.exists(file.destination)) {
164
- return yield* invalid(
165
- file.source,
166
- `Public route '${file.route.pathname}' overlaps generated client output.`,
167
- );
168
- }
169
- }),
170
- );
171
-
172
- yield* Effect.forEach(
173
- files,
174
- (file) =>
175
- Effect.gen(function* () {
176
- yield* fileSystem.makeDirectory(path.dirname(file.destination), { recursive: true });
177
- yield* fileSystem.writeFile(file.destination, file.bytes);
178
- }),
179
- { discard: true },
180
- );
181
-
182
- return {
183
- files: files.length,
184
- routes: files.map((file) => file.route),
185
- } satisfies PublicBuildResult;
186
- });
@@ -1,152 +0,0 @@
1
- import { Effect, FileSystem, Predicate, Result, Schema } from "effect";
2
- import { parseSync, type Node, type ObjectProperty, type ObjectPropertyKind } from "oxc-parser";
3
-
4
- export class InvalidClientEntry extends Schema.TaggedError<InvalidClientEntry>()(
5
- "InvalidClientEntry",
6
- {
7
- column: Schema.Int,
8
- line: Schema.Int,
9
- message: Schema.String,
10
- path: Schema.String,
11
- },
12
- ) {}
13
-
14
- export interface ClientEntrySource {
15
- readonly path: string;
16
- readonly source: string;
17
- }
18
-
19
- const requiredForm = 'export default app({ title: "My App", component: App });';
20
-
21
- const location = (source: string, offset: number) => {
22
- const prefix = source.slice(0, offset);
23
- const line = prefix.split("\n").length;
24
- const lastNewline = prefix.lastIndexOf("\n");
25
- return { column: offset - lastNewline, line };
26
- };
27
-
28
- const invalid = (entry: ClientEntrySource, node: Pick<Node, "start">, detail: string) => {
29
- const position = location(entry.source, node.start);
30
- return InvalidClientEntry.make({
31
- ...position,
32
- message: `${entry.path}:${position.line}:${position.column}: ${detail} Required form: ${requiredForm}`,
33
- path: entry.path,
34
- });
35
- };
36
-
37
- const isNamedProperty = (property: ObjectProperty, name: string): boolean =>
38
- property.kind === "init" &&
39
- !property.computed &&
40
- !property.method &&
41
- !property.shorthand &&
42
- property.key.type === "Identifier" &&
43
- property.key.name === name;
44
-
45
- const isObjectProperty = (property: ObjectPropertyKind): property is ObjectProperty =>
46
- property.type === "Property";
47
-
48
- export const extractClientEntryTitle = (
49
- entry: ClientEntrySource,
50
- ): Result.Result<string, InvalidClientEntry> => {
51
- const parsed = parseSync(entry.path, entry.source, {
52
- lang: "tsx",
53
- preserveParens: true,
54
- showSemanticErrors: true,
55
- sourceType: "module",
56
- });
57
- const parserError = parsed.errors[0];
58
- if (parserError !== undefined) {
59
- const label = parserError.labels[0];
60
- return Result.fail(
61
- invalid(
62
- entry,
63
- { start: label?.start ?? 0 },
64
- `The client entry is invalid: ${parserError.message}.`,
65
- ),
66
- );
67
- }
68
-
69
- const importsApp = parsed.program.body.some(
70
- (statement) =>
71
- statement.type === "ImportDeclaration" &&
72
- statement.source.value === "ignotum/client" &&
73
- statement.importKind !== "type" &&
74
- statement.specifiers.some(
75
- (specifier) =>
76
- specifier.type === "ImportSpecifier" &&
77
- specifier.importKind !== "type" &&
78
- specifier.imported.type === "Identifier" &&
79
- specifier.imported.name === "app" &&
80
- specifier.local.name === "app",
81
- ),
82
- );
83
- if (!importsApp) {
84
- return Result.fail(
85
- invalid(entry, parsed.program, 'Import { app } from "ignotum/client" without an alias.'),
86
- );
87
- }
88
-
89
- const defaultExports = parsed.program.body.filter(
90
- (statement) => statement.type === "ExportDefaultDeclaration",
91
- );
92
- const defaultExport = defaultExports[0];
93
- if (defaultExports.length !== 1 || defaultExport === undefined) {
94
- return Result.fail(
95
- invalid(entry, parsed.program, "The client entry needs one default export."),
96
- );
97
- }
98
- const call = defaultExport.declaration;
99
- if (
100
- call.type !== "CallExpression" ||
101
- call.optional ||
102
- call.typeArguments != null ||
103
- call.callee.type !== "Identifier" ||
104
- call.callee.name !== "app" ||
105
- call.arguments.length !== 1
106
- ) {
107
- return Result.fail(invalid(entry, defaultExport, "The default export must be an app call."));
108
- }
109
- const definition = call.arguments[0];
110
- if (definition?.type !== "ObjectExpression" || definition.properties.length !== 2) {
111
- return Result.fail(
112
- invalid(entry, call, "The app call needs exactly title and component properties."),
113
- );
114
- }
115
- const properties = definition.properties;
116
- if (!properties.every(isObjectProperty)) {
117
- return Result.fail(invalid(entry, definition, "Spread properties are not supported."));
118
- }
119
- const titleProperties = properties.filter((property) => isNamedProperty(property, "title"));
120
- const componentProperties = properties.filter((property) =>
121
- isNamedProperty(property, "component"),
122
- );
123
- if (titleProperties.length !== 1 || componentProperties.length !== 1) {
124
- return Result.fail(
125
- invalid(entry, definition, "Use unquoted title and component properties with no extras."),
126
- );
127
- }
128
- const titleProperty = titleProperties[0];
129
- if (titleProperty === undefined) {
130
- return Result.fail(invalid(entry, definition, "The title property is missing."));
131
- }
132
- const title = titleProperty.value;
133
- if (
134
- title.type !== "Literal" ||
135
- !Predicate.isString(title.value) ||
136
- (title.raw?.startsWith('"') !== true && title.raw?.startsWith("'") !== true)
137
- ) {
138
- return Result.fail(invalid(entry, title, "The title must be a quoted string literal."));
139
- }
140
- if (title.value.trim().length === 0) {
141
- return Result.fail(invalid(entry, title, "The title must contain a non-whitespace character."));
142
- }
143
- return Result.succeed(title.value);
144
- };
145
-
146
- export const loadClientEntryTitle = Effect.fn("ClientEntry.loadTitle")(function* (path: string) {
147
- const fileSystem = yield* FileSystem.FileSystem;
148
- const source = yield* fileSystem.readFileString(path);
149
- const extracted = extractClientEntryTitle({ path, source });
150
- if (Result.isFailure(extracted)) return yield* extracted.failure;
151
- return extracted.success;
152
- });
@@ -1,136 +0,0 @@
1
- import type { Plugin } from "vite";
2
-
3
- export const clientEntryId = "virtual:ignotum/client-entry";
4
- const resolvedClientEntryId = `\0${clientEntryId}`;
5
- export const clientStylesId = "virtual:ignotum/_styles.css";
6
- const resolvedClientStylesId = `\0${clientStylesId}`;
7
- export const clientStylesSource = '@import "tailwindcss";\n';
8
-
9
- interface ExternalClientScript {
10
- readonly source: string;
11
- readonly type: "External";
12
- }
13
-
14
- interface InlineClientScript {
15
- readonly source: string;
16
- readonly type: "Inline";
17
- }
18
-
19
- interface ClientDocumentOptions {
20
- readonly icon: string | undefined;
21
- readonly scripts: ReadonlyArray<ExternalClientScript | InlineClientScript>;
22
- readonly styles: ReadonlyArray<string>;
23
- readonly title: string;
24
- }
25
-
26
- export interface ClientPluginOptions {
27
- readonly development: boolean;
28
- readonly icon: string | undefined;
29
- readonly loadTitle: (() => Promise<string>) | undefined;
30
- }
31
-
32
- const escapeHtml = (value: string): string =>
33
- value
34
- .replaceAll("&", "&amp;")
35
- .replaceAll("<", "&lt;")
36
- .replaceAll(">", "&gt;")
37
- .replaceAll('"', "&quot;")
38
- .replaceAll("'", "&#39;");
39
-
40
- export const renderClientDocument = (options: ClientDocumentOptions): string => `<!doctype html>
41
- <html lang="en">
42
- <head>
43
- <meta charset="UTF-8" />
44
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
45
- <title>${escapeHtml(options.title)}</title>
46
- ${options.icon === undefined ? "" : ` <link rel="icon" type="image/svg+xml" href="${escapeHtml(options.icon)}" />`}
47
- ${options.styles.map((href) => ` <link rel="stylesheet" crossorigin href="/${escapeHtml(href)}" />`).join("\n")}
48
- </head>
49
- <body>
50
- <div id="app"></div>
51
- ${options.scripts
52
- .map((script) =>
53
- script.type === "External"
54
- ? ` <script type="module" crossorigin src="/${escapeHtml(script.source)}"></script>`
55
- : ` <script type="module">\n ${script.source}\n </script>`,
56
- )
57
- .join("\n")}
58
- </body>
59
- </html>`;
60
-
61
- export const renderClientEntry = (
62
- development: boolean,
63
- ): string => `${development ? 'import "preact/debug"\n' : ""}import { render } from "preact"
64
- import { jsx } from "preact/jsx-runtime"
65
-
66
- import "${clientStylesId}"
67
- import application from "/index.tsx"
68
-
69
- const root = document.getElementById("app")
70
-
71
- if (root === null) {
72
- throw new Error("Ignotum mount element is missing.")
73
- }
74
-
75
- document.title = application.title
76
- render(jsx(application.component, {}), root)
77
- `;
78
-
79
- const loadClientModule = (id: string, development: boolean): string | undefined => {
80
- if (id === resolvedClientEntryId) return renderClientEntry(development);
81
- if (id === resolvedClientStylesId) return clientStylesSource;
82
- return undefined;
83
- };
84
-
85
- export const resolveClientModule = (id: string): string | undefined => {
86
- if (id === clientEntryId) return resolvedClientEntryId;
87
- if (id === clientStylesId) return resolvedClientStylesId;
88
- return undefined;
89
- };
90
-
91
- export const ignotumClientPlugin = (options: ClientPluginOptions): Plugin => ({
92
- name: "ignotum:client",
93
-
94
- configureServer: (server) => {
95
- server.middlewares.use((request, response, next) => {
96
- const acceptsHtml = request.headers.accept?.includes("text/html") === true;
97
- const isNavigation = request.method === "GET" || request.method === "HEAD";
98
-
99
- if (!acceptsHtml || !isNavigation) {
100
- next();
101
- return;
102
- }
103
-
104
- const requestUrl = request.originalUrl ?? request.url ?? "/";
105
-
106
- const loadTitle = options.loadTitle;
107
- if (loadTitle === undefined) {
108
- next(new Error("Ignotum's development title loader is missing."));
109
- return;
110
- }
111
-
112
- void loadTitle()
113
- .then((title) =>
114
- server.transformIndexHtml(
115
- requestUrl,
116
- renderClientDocument({
117
- icon: options.icon,
118
- scripts: [{ source: `import "${clientEntryId}"`, type: "Inline" }],
119
- styles: [],
120
- title,
121
- }),
122
- ),
123
- )
124
- .then((html) => {
125
- response.statusCode = 200;
126
- response.setHeader("Content-Type", "text/html; charset=utf-8");
127
- response.end(request.method === "HEAD" ? undefined : html);
128
- })
129
- .catch(next);
130
- });
131
- },
132
-
133
- load: (id) => loadClientModule(id, options.development),
134
-
135
- resolveId: resolveClientModule,
136
- });