@gettersethya/mira 0.1.0-alpha.2 → 0.1.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -0
- package/dist/src/app/app.d.ts +45 -26
- package/dist/src/app/app.d.ts.map +1 -1
- package/dist/src/app/app.js +138 -41
- package/dist/src/app/app.js.map +1 -1
- package/dist/src/app/builder.d.ts +56 -15
- package/dist/src/app/builder.d.ts.map +1 -1
- package/dist/src/app/builder.js +56 -4
- package/dist/src/app/builder.js.map +1 -1
- package/dist/src/app/define-rule.d.ts +70 -0
- package/dist/src/app/define-rule.d.ts.map +1 -0
- package/dist/src/app/define-rule.js +42 -0
- package/dist/src/app/define-rule.js.map +1 -0
- package/dist/src/app/index.d.ts +8 -3
- package/dist/src/app/index.d.ts.map +1 -1
- package/dist/src/app/index.js +3 -0
- package/dist/src/app/index.js.map +1 -1
- package/dist/src/app/plugin.d.ts +83 -0
- package/dist/src/app/plugin.d.ts.map +1 -0
- package/dist/src/app/plugin.js +20 -0
- package/dist/src/app/plugin.js.map +1 -0
- package/dist/src/app/types.d.ts +4 -4
- package/dist/src/app/types.d.ts.map +1 -1
- package/dist/src/cache/cached-collection.d.ts +7 -5
- package/dist/src/cache/cached-collection.d.ts.map +1 -1
- package/dist/src/cache/cached-collection.js +8 -5
- package/dist/src/cache/cached-collection.js.map +1 -1
- package/dist/src/cache/collection-cache.d.ts +1 -1
- package/dist/src/cache/collection-cache.d.ts.map +1 -1
- package/dist/src/cache/collection-cache.js +1 -1
- package/dist/src/cache/collection-cache.js.map +1 -1
- package/dist/src/cache/ctx-key.d.ts +15 -0
- package/dist/src/cache/ctx-key.d.ts.map +1 -0
- package/dist/src/cache/ctx-key.js +37 -0
- package/dist/src/cache/ctx-key.js.map +1 -0
- package/dist/src/cache/index.d.ts +2 -1
- package/dist/src/cache/index.d.ts.map +1 -1
- package/dist/src/cache/index.js +2 -1
- package/dist/src/cache/index.js.map +1 -1
- package/dist/src/collection-service/collection-service.d.ts +7 -5
- package/dist/src/collection-service/collection-service.d.ts.map +1 -1
- package/dist/src/collection-service/collection-service.js +201 -51
- package/dist/src/collection-service/collection-service.js.map +1 -1
- package/dist/src/collection-service/context.d.ts +2 -0
- package/dist/src/collection-service/context.d.ts.map +1 -1
- package/dist/src/collection-service/decode.d.ts +4 -2
- package/dist/src/collection-service/decode.d.ts.map +1 -1
- package/dist/src/collection-service/decode.js +32 -16
- package/dist/src/collection-service/decode.js.map +1 -1
- package/dist/src/collection-service/errors.d.ts +1 -1
- package/dist/src/collection-service/errors.d.ts.map +1 -1
- package/dist/src/collection-service/errors.js +1 -1
- package/dist/src/collection-service/errors.js.map +1 -1
- package/dist/src/collection-service/index.d.ts +1 -1
- package/dist/src/collection-service/index.d.ts.map +1 -1
- package/dist/src/collection-service/index.js.map +1 -1
- package/dist/src/collection-service/input-schema.d.ts +5 -4
- package/dist/src/collection-service/input-schema.d.ts.map +1 -1
- package/dist/src/collection-service/input-schema.js +31 -18
- package/dist/src/collection-service/input-schema.js.map +1 -1
- package/dist/src/collection-service/where.d.ts +14 -2
- package/dist/src/collection-service/where.d.ts.map +1 -1
- package/dist/src/collection-service/where.js +35 -1
- package/dist/src/collection-service/where.js.map +1 -1
- package/dist/src/config/config.d.ts +4 -4
- package/dist/src/config/config.d.ts.map +1 -1
- package/dist/src/config/config.js +34 -5
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/types.d.ts +9 -0
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/cron/cron-service.d.ts +14 -0
- package/dist/src/cron/cron-service.d.ts.map +1 -0
- package/dist/src/cron/cron-service.js +135 -0
- package/dist/src/cron/cron-service.js.map +1 -0
- package/dist/src/cron/index.d.ts +4 -0
- package/dist/src/cron/index.d.ts.map +1 -0
- package/dist/src/cron/index.js +3 -0
- package/dist/src/cron/index.js.map +1 -0
- package/dist/src/cron/persistence.d.ts +22 -0
- package/dist/src/cron/persistence.d.ts.map +1 -0
- package/dist/src/cron/persistence.js +48 -0
- package/dist/src/cron/persistence.js.map +1 -0
- package/dist/src/cron/types.d.ts +51 -0
- package/dist/src/cron/types.d.ts.map +1 -0
- package/dist/src/cron/types.js +4 -0
- package/dist/src/cron/types.js.map +1 -0
- package/dist/src/crypto/crypto.d.ts +3 -2
- package/dist/src/crypto/crypto.d.ts.map +1 -1
- package/dist/src/crypto/crypto.js +1 -1
- package/dist/src/crypto/crypto.js.map +1 -1
- package/dist/src/crypto/node.d.ts.map +1 -1
- package/dist/src/crypto/node.js.map +1 -1
- package/dist/src/databases/sqlite.d.ts.map +1 -1
- package/dist/src/databases/sqlite.js +2 -2
- package/dist/src/databases/sqlite.js.map +1 -1
- package/dist/src/dialect/dialect-sqlite.d.ts +9 -0
- package/dist/src/dialect/dialect-sqlite.d.ts.map +1 -0
- package/dist/src/dialect/dialect-sqlite.js +109 -0
- package/dist/src/dialect/dialect-sqlite.js.map +1 -0
- package/dist/src/dialect/dialect.d.ts +26 -0
- package/dist/src/dialect/dialect.d.ts.map +1 -0
- package/dist/src/dialect/dialect.js +5 -0
- package/dist/src/dialect/dialect.js.map +1 -0
- package/dist/src/hooks/hook-collection.d.ts +5 -0
- package/dist/src/hooks/hook-collection.d.ts.map +1 -0
- package/dist/src/hooks/hook-collection.js +77 -0
- package/dist/src/hooks/hook-collection.js.map +1 -0
- package/dist/src/hooks/hook-service.d.ts +38 -0
- package/dist/src/hooks/hook-service.d.ts.map +1 -0
- package/dist/src/hooks/hook-service.js +150 -0
- package/dist/src/hooks/hook-service.js.map +1 -0
- package/dist/src/hooks/index.d.ts +4 -0
- package/dist/src/hooks/index.d.ts.map +1 -0
- package/dist/src/hooks/index.js +3 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/types.d.ts +74 -0
- package/dist/src/hooks/types.d.ts.map +1 -0
- package/dist/src/hooks/types.js +2 -0
- package/dist/src/hooks/types.js.map +1 -0
- package/dist/src/http/auth-node.d.ts.map +1 -1
- package/dist/src/http/auth-node.js +1 -1
- package/dist/src/http/auth-node.js.map +1 -1
- package/dist/src/http/auth.d.ts +3 -1
- package/dist/src/http/auth.d.ts.map +1 -1
- package/dist/src/http/auth.js +12 -2
- package/dist/src/http/auth.js.map +1 -1
- package/dist/src/http/cors.d.ts +94 -0
- package/dist/src/http/cors.d.ts.map +1 -0
- package/dist/src/http/cors.js +57 -0
- package/dist/src/http/cors.js.map +1 -0
- package/dist/src/http/errors.d.ts +1 -1
- package/dist/src/http/errors.d.ts.map +1 -1
- package/dist/src/http/errors.js +7 -7
- package/dist/src/http/errors.js.map +1 -1
- package/dist/src/http/file-serve.d.ts +4 -4
- package/dist/src/http/file-serve.d.ts.map +1 -1
- package/dist/src/http/file-serve.js +39 -34
- package/dist/src/http/file-serve.js.map +1 -1
- package/dist/src/http/file-token.d.ts +4 -3
- package/dist/src/http/file-token.d.ts.map +1 -1
- package/dist/src/http/file-token.js +19 -17
- package/dist/src/http/file-token.js.map +1 -1
- package/dist/src/http/files.d.ts +3 -3
- package/dist/src/http/files.d.ts.map +1 -1
- package/dist/src/http/files.js +5 -5
- package/dist/src/http/files.js.map +1 -1
- package/dist/src/http/index.d.ts +8 -5
- package/dist/src/http/index.d.ts.map +1 -1
- package/dist/src/http/index.js +5 -3
- package/dist/src/http/index.js.map +1 -1
- package/dist/src/http/ip-middleware.d.ts +3 -2
- package/dist/src/http/ip-middleware.d.ts.map +1 -1
- package/dist/src/http/ip-middleware.js +7 -4
- package/dist/src/http/ip-middleware.js.map +1 -1
- package/dist/src/http/params.d.ts +3 -3
- package/dist/src/http/params.d.ts.map +1 -1
- package/dist/src/http/params.js +2 -2
- package/dist/src/http/params.js.map +1 -1
- package/dist/src/http/port-retry.d.ts +18 -0
- package/dist/src/http/port-retry.d.ts.map +1 -0
- package/dist/src/http/port-retry.js +43 -0
- package/dist/src/http/port-retry.js.map +1 -0
- package/dist/src/http/router.d.ts +10 -7
- package/dist/src/http/router.d.ts.map +1 -1
- package/dist/src/http/router.js +184 -63
- package/dist/src/http/router.js.map +1 -1
- package/dist/src/http/schema.d.ts +5 -0
- package/dist/src/http/schema.d.ts.map +1 -0
- package/dist/src/http/schema.js +18 -0
- package/dist/src/http/schema.js.map +1 -0
- package/dist/src/http/server-factory-node.d.ts.map +1 -1
- package/dist/src/http/server-factory-node.js +1 -1
- package/dist/src/http/server-factory-node.js.map +1 -1
- package/dist/src/http/server-factory.d.ts +3 -3
- package/dist/src/http/server-factory.d.ts.map +1 -1
- package/dist/src/http/server-factory.js +1 -1
- package/dist/src/http/server-factory.js.map +1 -1
- package/dist/src/http/telemetry-routes.d.ts +5 -0
- package/dist/src/http/telemetry-routes.d.ts.map +1 -0
- package/dist/src/http/telemetry-routes.js +220 -0
- package/dist/src/http/telemetry-routes.js.map +1 -0
- package/dist/src/index.d.ts +18 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +14 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/migrator/dialect-sqlite.d.ts.map +1 -1
- package/dist/src/migrator/dialect-sqlite.js +7 -1
- package/dist/src/migrator/dialect-sqlite.js.map +1 -1
- package/dist/src/migrator/index.d.ts +4 -4
- package/dist/src/migrator/index.d.ts.map +1 -1
- package/dist/src/migrator/index.js +2 -2
- package/dist/src/migrator/index.js.map +1 -1
- package/dist/src/migrator/migrator.d.ts +8 -8
- package/dist/src/migrator/migrator.d.ts.map +1 -1
- package/dist/src/migrator/migrator.js +16 -13
- package/dist/src/migrator/migrator.js.map +1 -1
- package/dist/src/migrator/schema-diff.d.ts +2 -2
- package/dist/src/migrator/schema-diff.d.ts.map +1 -1
- package/dist/src/migrator/schema-diff.js.map +1 -1
- package/dist/src/migrator/types.d.ts +5 -5
- package/dist/src/migrator/types.d.ts.map +1 -1
- package/dist/src/migrator/types.js +6 -7
- package/dist/src/migrator/types.js.map +1 -1
- package/dist/src/platforms/node.d.ts +1 -1
- package/dist/src/platforms/node.d.ts.map +1 -1
- package/dist/src/platforms/node.js +1 -1
- package/dist/src/platforms/node.js.map +1 -1
- package/dist/src/repository/id.d.ts +1 -1
- package/dist/src/repository/id.d.ts.map +1 -1
- package/dist/src/repository/id.js +15 -3
- package/dist/src/repository/id.js.map +1 -1
- package/dist/src/repository/repository.d.ts +3 -2
- package/dist/src/repository/repository.d.ts.map +1 -1
- package/dist/src/repository/repository.js +11 -7
- package/dist/src/repository/repository.js.map +1 -1
- package/dist/src/rule/compiler.d.ts.map +1 -1
- package/dist/src/rule/compiler.js +2 -0
- package/dist/src/rule/compiler.js.map +1 -1
- package/dist/src/rule/enforcer.d.ts.map +1 -1
- package/dist/src/rule/enforcer.js.map +1 -1
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.d.ts.map +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/index.js.map +1 -1
- package/dist/src/storage/local-preset.d.ts.map +1 -1
- package/dist/src/storage/local-preset.js.map +1 -1
- package/dist/src/storage/storage.d.ts +2 -2
- package/dist/src/storage/storage.d.ts.map +1 -1
- package/dist/src/storage/storage.js +8 -26
- package/dist/src/storage/storage.js.map +1 -1
- package/dist/src/telemetry/collections.d.ts +4 -0
- package/dist/src/telemetry/collections.d.ts.map +1 -0
- package/dist/src/telemetry/collections.js +19 -0
- package/dist/src/telemetry/collections.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +17 -3
- package/dist/src/telemetry/index.d.ts.map +1 -1
- package/dist/src/telemetry/index.js +15 -5
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/logger.d.ts +29 -2
- package/dist/src/telemetry/logger.d.ts.map +1 -1
- package/dist/src/telemetry/logger.js +52 -15
- package/dist/src/telemetry/logger.js.map +1 -1
- package/dist/src/telemetry/sqlite-logger.d.ts +36 -0
- package/dist/src/telemetry/sqlite-logger.d.ts.map +1 -0
- package/dist/src/telemetry/sqlite-logger.js +193 -0
- package/dist/src/telemetry/sqlite-logger.js.map +1 -0
- package/dist/src/telemetry/telemetry-sql-client.d.ts +11 -0
- package/dist/src/telemetry/telemetry-sql-client.d.ts.map +1 -0
- package/dist/src/telemetry/telemetry-sql-client.js +8 -0
- package/dist/src/telemetry/telemetry-sql-client.js.map +1 -0
- package/dist/src/telemetry/tracer.d.ts +16 -1
- package/dist/src/telemetry/tracer.d.ts.map +1 -1
- package/dist/src/telemetry/tracer.js +87 -70
- package/dist/src/telemetry/tracer.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +11 -0
- package/dist/src/telemetry/types.d.ts.map +1 -0
- package/dist/src/telemetry/types.js +2 -0
- package/dist/src/telemetry/types.js.map +1 -0
- package/dist/src/thumbnail/index.d.ts +2 -2
- package/dist/src/thumbnail/index.d.ts.map +1 -1
- package/dist/src/thumbnail/index.js +1 -1
- package/dist/src/thumbnail/index.js.map +1 -1
- package/dist/src/thumbnail/photon.d.ts.map +1 -1
- package/dist/src/thumbnail/photon.js +1 -1
- package/dist/src/thumbnail/photon.js.map +1 -1
- package/dist/src/thumbnail/types.d.ts +1 -1
- package/dist/src/thumbnail/types.d.ts.map +1 -1
- package/dist/src/thumbnail/types.js +2 -2
- package/dist/src/thumbnail/types.js.map +1 -1
- package/dist/tests/app/app.test.js +101 -26
- package/dist/tests/app/app.test.js.map +1 -1
- package/dist/tests/app/builder.test.js +77 -9
- package/dist/tests/app/builder.test.js.map +1 -1
- package/dist/tests/app/define-rule.test.d.ts +2 -0
- package/dist/tests/app/define-rule.test.d.ts.map +1 -0
- package/dist/tests/app/define-rule.test.js +147 -0
- package/dist/tests/app/define-rule.test.js.map +1 -0
- package/dist/tests/cache/cached-collection.test.js +200 -40
- package/dist/tests/cache/cached-collection.test.js.map +1 -1
- package/dist/tests/cache/collection-cache.test.js +1 -1
- package/dist/tests/cache/collection-cache.test.js.map +1 -1
- package/dist/tests/collection-service/auth-credentials.test.d.ts +2 -0
- package/dist/tests/collection-service/auth-credentials.test.d.ts.map +1 -0
- package/dist/tests/collection-service/auth-credentials.test.js +172 -0
- package/dist/tests/collection-service/auth-credentials.test.js.map +1 -0
- package/dist/tests/collection-service/collection-service.test.js +374 -174
- package/dist/tests/collection-service/collection-service.test.js.map +1 -1
- package/dist/tests/collection-service/decode.test.d.ts +2 -0
- package/dist/tests/collection-service/decode.test.d.ts.map +1 -0
- package/dist/tests/collection-service/decode.test.js +37 -0
- package/dist/tests/collection-service/decode.test.js.map +1 -0
- package/dist/tests/collection-service/input-schema.test.js +162 -95
- package/dist/tests/collection-service/input-schema.test.js.map +1 -1
- package/dist/tests/config/config.test.js +15 -4
- package/dist/tests/config/config.test.js.map +1 -1
- package/dist/tests/cron/cron-integration.test.d.ts +2 -0
- package/dist/tests/cron/cron-integration.test.d.ts.map +1 -0
- package/dist/tests/cron/cron-integration.test.js +109 -0
- package/dist/tests/cron/cron-integration.test.js.map +1 -0
- package/dist/tests/cron/cron-persistence.test.d.ts +2 -0
- package/dist/tests/cron/cron-persistence.test.d.ts.map +1 -0
- package/dist/tests/cron/cron-persistence.test.js +123 -0
- package/dist/tests/cron/cron-persistence.test.js.map +1 -0
- package/dist/tests/cron/cron-service.test.d.ts +2 -0
- package/dist/tests/cron/cron-service.test.d.ts.map +1 -0
- package/dist/tests/cron/cron-service.test.js +124 -0
- package/dist/tests/cron/cron-service.test.js.map +1 -0
- package/dist/tests/crypto/crypto.test.js +2 -2
- package/dist/tests/crypto/crypto.test.js.map +1 -1
- package/dist/tests/hooks/hook-collection.test.d.ts +2 -0
- package/dist/tests/hooks/hook-collection.test.d.ts.map +1 -0
- package/dist/tests/hooks/hook-collection.test.js +110 -0
- package/dist/tests/hooks/hook-collection.test.js.map +1 -0
- package/dist/tests/hooks/hook-service.test.d.ts +2 -0
- package/dist/tests/hooks/hook-service.test.d.ts.map +1 -0
- package/dist/tests/hooks/hook-service.test.js +220 -0
- package/dist/tests/hooks/hook-service.test.js.map +1 -0
- package/dist/tests/http/cors.test.d.ts +2 -0
- package/dist/tests/http/cors.test.d.ts.map +1 -0
- package/dist/tests/http/cors.test.js +211 -0
- package/dist/tests/http/cors.test.js.map +1 -0
- package/dist/tests/http/file-serve.test.js +63 -54
- package/dist/tests/http/file-serve.test.js.map +1 -1
- package/dist/tests/http/file-token.test.js +69 -51
- package/dist/tests/http/file-token.test.js.map +1 -1
- package/dist/tests/http/ip-middleware.test.js +13 -13
- package/dist/tests/http/ip-middleware.test.js.map +1 -1
- package/dist/tests/http/port-retry.test.d.ts +2 -0
- package/dist/tests/http/port-retry.test.d.ts.map +1 -0
- package/dist/tests/http/port-retry.test.js +52 -0
- package/dist/tests/http/port-retry.test.js.map +1 -0
- package/dist/tests/http/router.test.js +260 -85
- package/dist/tests/http/router.test.js.map +1 -1
- package/dist/tests/migrator/dialect-sqlite.test.js +1 -1
- package/dist/tests/migrator/dialect-sqlite.test.js.map +1 -1
- package/dist/tests/migrator/integration.test.js +6 -6
- package/dist/tests/migrator/integration.test.js.map +1 -1
- package/dist/tests/migrator/migrator.test.js +5 -5
- package/dist/tests/migrator/migrator.test.js.map +1 -1
- package/dist/tests/migrator/schema-diff.test.js.map +1 -1
- package/dist/tests/repository/repository.test.js +71 -8
- package/dist/tests/repository/repository.test.js.map +1 -1
- package/dist/tests/rule/compiler.test.js +1 -1
- package/dist/tests/rule/compiler.test.js.map +1 -1
- package/dist/tests/rule/enforcer.test.js +9 -9
- package/dist/tests/rule/enforcer.test.js.map +1 -1
- package/dist/tests/storage/storage.test.js +15 -15
- package/dist/tests/storage/storage.test.js.map +1 -1
- package/dist/tests/telemetry/collections.test.d.ts +2 -0
- package/dist/tests/telemetry/collections.test.d.ts.map +1 -0
- package/dist/tests/telemetry/collections.test.js +67 -0
- package/dist/tests/telemetry/collections.test.js.map +1 -0
- package/dist/tests/telemetry/instrumentation.test.js +27 -20
- package/dist/tests/telemetry/instrumentation.test.js.map +1 -1
- package/dist/tests/telemetry/logger.test.js +38 -6
- package/dist/tests/telemetry/logger.test.js.map +1 -1
- package/dist/tests/telemetry/sqlite-logger.test.d.ts +2 -0
- package/dist/tests/telemetry/sqlite-logger.test.d.ts.map +1 -0
- package/dist/tests/telemetry/sqlite-logger.test.js +272 -0
- package/dist/tests/telemetry/sqlite-logger.test.js.map +1 -0
- package/dist/tests/telemetry/telemetry-routes.test.d.ts +2 -0
- package/dist/tests/telemetry/telemetry-routes.test.d.ts.map +1 -0
- package/dist/tests/telemetry/telemetry-routes.test.js +154 -0
- package/dist/tests/telemetry/telemetry-routes.test.js.map +1 -0
- package/dist/tests/telemetry/tracer.test.js +41 -4
- package/dist/tests/telemetry/tracer.test.js.map +1 -1
- package/dist/tests/thumbnail/photon.test.js +35 -35
- package/dist/tests/thumbnail/photon.test.js.map +1 -1
- package/dist/tests/thumbnail/thumbnail.test.js +7 -7
- package/dist/tests/thumbnail/thumbnail.test.js.map +1 -1
- package/package.json +9 -9
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @gettersethya/mira
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@gettersethya/mira)
|
|
4
|
+
|
|
5
|
+
> **Early pre-alpha.** Breaking changes may occur without notice.
|
|
6
|
+
|
|
7
|
+
Self-hosted backend in TypeScript using [Effect v4](https://effect.website). Define collections, get a full REST API with auth, file storage, access rules, and schema migrations — all with zero config.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @gettersethya/mira @gettersethya/mira-collection effect
|
|
13
|
+
# or
|
|
14
|
+
pnpm add @gettersethya/mira @gettersethya/mira-collection effect
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { defineRule, LocalFileStorage, Mira, NodePlatform, Rule, SqliteDatabase } from "@gettersethya/mira"
|
|
21
|
+
import { Posts, Users } from "./collections.js"
|
|
22
|
+
|
|
23
|
+
const userRules = defineRule(Users, (R) => ({
|
|
24
|
+
list: Rule.public(),
|
|
25
|
+
view: Rule.public(),
|
|
26
|
+
create: Rule.public(),
|
|
27
|
+
update: R.selfId().eq(R.authId(Users)),
|
|
28
|
+
}))
|
|
29
|
+
|
|
30
|
+
const postRules = defineRule(Posts, (R) => ({
|
|
31
|
+
list: R.field("published").eq(R.literal(true)),
|
|
32
|
+
view: R.or(
|
|
33
|
+
R.field("published").eq(R.literal(true)),
|
|
34
|
+
R.field("authorId").eq(R.authId(Users))
|
|
35
|
+
),
|
|
36
|
+
create: R.authId(Users).neq(R.literal("")),
|
|
37
|
+
update: R.field("authorId").eq(R.authId(Users)),
|
|
38
|
+
delete: R.field("authorId").eq(R.authId(Users)),
|
|
39
|
+
}))
|
|
40
|
+
|
|
41
|
+
const app = Mira.builder()
|
|
42
|
+
.platform(NodePlatform)
|
|
43
|
+
.database(SqliteDatabase({ filename: "mira.db" }))
|
|
44
|
+
.storage(LocalFileStorage({ directory: "./uploads" }))
|
|
45
|
+
.collections([Users, Posts])
|
|
46
|
+
.rules([userRules, postRules])
|
|
47
|
+
.build()
|
|
48
|
+
|
|
49
|
+
app.serve({ port: 3000 })
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The builder uses phantom types to enforce step ordering — TypeScript will not let you call `.build()` until all four required steps are complete.
|
|
53
|
+
|
|
54
|
+
On first boot, Mira auto-generates a `jwt_secret`, runs schema migrations, and creates SQL views for view collections. Everything is persisted in the database.
|
|
55
|
+
|
|
56
|
+
## Builder steps
|
|
57
|
+
|
|
58
|
+
| Step | Required | Description |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `.platform(p)` | Yes | Runtime environment (Node.js, etc.) |
|
|
61
|
+
| `.database(d)` | Yes | Database backend |
|
|
62
|
+
| `.storage(s)` | Yes | File storage backend |
|
|
63
|
+
| `.collections(c)` | Yes | Collection definitions |
|
|
64
|
+
| `.rules(r)` | No | Array of `RuleBinding` from `defineRule(collection, cb)` |
|
|
65
|
+
| `.crons(c)` | No | Array of `CronDef` — scheduled tasks using Effect `Schedule` |
|
|
66
|
+
| `.telemetry(layer)` | No | Custom Effect telemetry layer |
|
|
67
|
+
| `.cors(c)` | No | CORS config. Defaults to permissive (`*`), so a separately-hosted frontend works with zero config |
|
|
68
|
+
| `.extend(plugin)` | No | Register a `MiraPlugin` (lifecycle hooks, routes, crons, layers) |
|
|
69
|
+
|
|
70
|
+
## Platforms
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { NodePlatform } from "@gettersethya/mira"
|
|
74
|
+
|
|
75
|
+
// Provides: CryptoService, FileSystem, HttpServerFactory, AuthService
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Databases
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { SqliteDatabase } from "@gettersethya/mira"
|
|
82
|
+
|
|
83
|
+
SqliteDatabase({ filename: "mira.db" })
|
|
84
|
+
SqliteDatabase({ filename: ":memory:" }) // in-memory for tests
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Storage
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { LocalFileStorage } from "@gettersethya/mira"
|
|
91
|
+
|
|
92
|
+
LocalFileStorage({ directory: "./uploads" })
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## CORS
|
|
96
|
+
|
|
97
|
+
By default the server is fully permissive (`Access-Control-Allow-Origin: *`), so a frontend hosted on another origin works with zero configuration. `OPTIONS` preflights are answered automatically, and error responses carry CORS headers too.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
Mira.builder()
|
|
101
|
+
// ... required steps
|
|
102
|
+
.cors({
|
|
103
|
+
allowedOrigins: ["https://app.example.com"], // list, or (origin) => boolean predicate
|
|
104
|
+
credentials: true, // requires explicit origins — never combines with "*"
|
|
105
|
+
// allowedMethods, allowedHeaders, exposedHeaders, maxAge are optional
|
|
106
|
+
})
|
|
107
|
+
.build()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`credentials: true` combined with a wildcard origin throws at build time.
|
|
111
|
+
|
|
112
|
+
## Auto-generated endpoints
|
|
113
|
+
|
|
114
|
+
Each collection gets a full set of REST endpoints:
|
|
115
|
+
|
|
116
|
+
| Method | Path | Description |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `GET` | `/api/collections/:collection` | List (filter, sort, cursor, expand, select) |
|
|
119
|
+
| `GET` | `/api/collections/:collection/:id` | Get one |
|
|
120
|
+
| `POST` | `/api/collections/:collection` | Create |
|
|
121
|
+
| `PATCH` | `/api/collections/:collection/:id` | Update |
|
|
122
|
+
| `DELETE` | `/api/collections/:collection/:id` | Delete |
|
|
123
|
+
| `POST` | `/api/collections/:collection/auth-with-password` | Login (auth collections only) |
|
|
124
|
+
| `GET` | `/api/auth/me` | Current authenticated record |
|
|
125
|
+
| `POST` | `/api/auth/logout` | Logout |
|
|
126
|
+
| `POST` | `/api/files/token` | Request protected file token |
|
|
127
|
+
| `GET` | `/api/files/:collection/:id/:filename` | Serve file |
|
|
128
|
+
| `GET` | `/api/_schema` | Schema introspection |
|
|
129
|
+
|
|
130
|
+
## Cron jobs
|
|
131
|
+
|
|
132
|
+
Register scheduled tasks via the `.crons()` builder step. Each cron uses an Effect `Schedule` to define its recurrence.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { Schedule } from "effect"
|
|
136
|
+
import { CronService } from "@gettersethya/mira"
|
|
137
|
+
|
|
138
|
+
const app = Mira.builder()
|
|
139
|
+
.platform(NodePlatform)
|
|
140
|
+
.database(SqliteDatabase({ filename: "mira.db" }))
|
|
141
|
+
.storage(LocalFileStorage({ directory: "./uploads" }))
|
|
142
|
+
.collections([Users, Posts])
|
|
143
|
+
.crons([
|
|
144
|
+
{
|
|
145
|
+
name: "cleanup",
|
|
146
|
+
schedule: Schedule.fixed("1 hour"),
|
|
147
|
+
handler: () => Effect.log("[cron] cleaning up..."),
|
|
148
|
+
},
|
|
149
|
+
])
|
|
150
|
+
.build()
|
|
151
|
+
.serve()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Cron names must be globally unique. Use `CronService.getAll()` to inspect state and `CronService.runNow(name)` to trigger immediate execution. Plugins can declare crons via `crons` and hook into `onCronStart`/`onCronExecute`/`onCronSuccess`/`onCronError`/`onCronFinished`.
|
|
155
|
+
|
|
156
|
+
See the [Mira root README](https://github.com/gettersethya/mira#cron-jobs) for full cron documentation.
|
|
157
|
+
|
|
158
|
+
## Testing with the service layer
|
|
159
|
+
|
|
160
|
+
Use `.buildServiceLayer()` to get an Effect `Layer` for all services without starting an HTTP server:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { Effect, Layer } from "effect"
|
|
164
|
+
|
|
165
|
+
const serviceLayer = app.buildServiceLayer()
|
|
166
|
+
|
|
167
|
+
const test = Effect.gen(function* () {
|
|
168
|
+
// inject and use services directly
|
|
169
|
+
}).pipe(Effect.provide(serviceLayer))
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## More
|
|
173
|
+
|
|
174
|
+
See the [Mira root README](https://github.com/gettersethya/mira) for collection definitions, field types, rules, filter DSL, and client usage.
|
package/dist/src/app/app.d.ts
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AnyCollectionDef } from "@gettersethya/mira-client";
|
|
2
2
|
import { Layer } from "effect";
|
|
3
|
-
import { Migrator } from "../migrator/migrator.js";
|
|
4
3
|
import { AppConfig } from "../config/index.js";
|
|
4
|
+
import { Migrator } from "../migrator/migrator.js";
|
|
5
5
|
import type { MiraAppConfig } from "./builder.js";
|
|
6
|
+
import type { RuleBinding } from "./define-rule.js";
|
|
7
|
+
import type { MiraPlugin } from "./plugin.js";
|
|
8
|
+
export declare function applyRulesToCollections<C extends AnyCollectionDef>(collections: ReadonlyArray<C>, rules: ReadonlyArray<RuleBinding>): Array<C>;
|
|
9
|
+
/**
|
|
10
|
+
* Options for `MiraApp.serve()` and `MiraApp.buildLayer()`.
|
|
11
|
+
*/
|
|
12
|
+
export interface ServeOptions {
|
|
13
|
+
/** Port to listen on. Defaults to the port from `AppConfig`. */
|
|
14
|
+
port?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Total number of ports to try when the requested port is already in use.
|
|
17
|
+
* The server increments the port and retries until a free one is found.
|
|
18
|
+
* Defaults to 10. Pass `1` to disable retrying.
|
|
19
|
+
*/
|
|
20
|
+
maxPortAttempts?: number;
|
|
21
|
+
}
|
|
6
22
|
/**
|
|
7
23
|
* The assembled Mira application, ready to serve.
|
|
8
24
|
*
|
|
@@ -11,7 +27,7 @@ import type { MiraAppConfig } from "./builder.js";
|
|
|
11
27
|
*
|
|
12
28
|
* `MiraApp` wires all layers (database, storage, collection service, HTTP server,
|
|
13
29
|
* telemetry, auto-migration) and provides `serve()` to start the server.
|
|
14
|
-
* Use `extend()` to add
|
|
30
|
+
* Use `extend()` to add plugins before serving.
|
|
15
31
|
*
|
|
16
32
|
* @example
|
|
17
33
|
* const app = Mira.builder()
|
|
@@ -24,38 +40,40 @@ import type { MiraAppConfig } from "./builder.js";
|
|
|
24
40
|
* app.serve()
|
|
25
41
|
*
|
|
26
42
|
* @example
|
|
27
|
-
* // With
|
|
28
|
-
* app.extend(
|
|
43
|
+
* // With plugin
|
|
44
|
+
* app.extend(MiraDashboard).serve({ port: 8080 })
|
|
29
45
|
*
|
|
30
46
|
* @see MiraBuilder — builds MiraApp
|
|
31
47
|
* @see Mira — entry point: Mira.builder()
|
|
32
48
|
*/
|
|
33
|
-
export declare class MiraApp {
|
|
49
|
+
export declare class MiraApp<R = never> {
|
|
34
50
|
#private;
|
|
35
51
|
constructor(config: MiraAppConfig);
|
|
36
52
|
/** @internal for tests only */
|
|
37
53
|
_getConfig(): MiraAppConfig;
|
|
38
54
|
/** @internal for tests only */
|
|
39
|
-
_getExtras(): ReadonlyArray<
|
|
55
|
+
_getExtras(): ReadonlyArray<MiraPlugin<any>>;
|
|
56
|
+
/** @internal for tests only */
|
|
57
|
+
_resolveAdminCollections(): ReadonlyArray<AnyCollectionDef>;
|
|
40
58
|
/**
|
|
41
|
-
* Add
|
|
42
|
-
*
|
|
43
|
-
*
|
|
59
|
+
* Add a plugin to the application. Plugins can register lifecycle hooks,
|
|
60
|
+
* record-lifecycle hooks, custom routes, service layers, and additional
|
|
61
|
+
* collection definitions.
|
|
44
62
|
*
|
|
45
|
-
* @param
|
|
63
|
+
* @param plugin - A MiraPlugin (use `fromLayer()` to wrap a plain Layer)
|
|
46
64
|
* @returns this (for chaining)
|
|
47
65
|
*
|
|
48
66
|
* @example
|
|
49
|
-
* app.extend(
|
|
67
|
+
* app.extend(MiraDashboard).serve()
|
|
50
68
|
*/
|
|
51
|
-
extend(
|
|
69
|
+
extend(plugin: MiraPlugin<any>): MiraApp<R>;
|
|
52
70
|
/**
|
|
53
71
|
* Build the full service layer without the HTTP server.
|
|
54
72
|
* Useful for testing — you can run Effects against the service layer without
|
|
55
73
|
* starting a network server.
|
|
56
74
|
*
|
|
57
75
|
* Includes: database, storage, telemetry, repository, migrator, app config,
|
|
58
|
-
* collection service (with cache), and auto-migration.
|
|
76
|
+
* collection service (with cache + hooks), and auto-migration.
|
|
59
77
|
*
|
|
60
78
|
* @returns A Layer providing all services
|
|
61
79
|
*
|
|
@@ -65,32 +83,33 @@ export declare class MiraApp {
|
|
|
65
83
|
* Effect.gen(function* () { ... }).pipe(Effect.provide(serviceLayer))
|
|
66
84
|
* )
|
|
67
85
|
*/
|
|
68
|
-
buildServiceLayer(): Layer.Layer<import("../index.js").FileStorage | import("./types.js").PlatformServices | import("./types.js").DatabaseServices | import("../repository/repository.js").Repository | Migrator | import("../
|
|
86
|
+
buildServiceLayer(): Layer.Layer<import("../index.js").FileStorage | import("./types.js").PlatformServices | import("./types.js").DatabaseServices | import("../repository/repository.js").Repository | import("../index.js").CollectionService | AppConfig | Migrator | import("../cron/cron-service.js").CronService | import("../thumbnail/index.js").ThumbnailService, import("effect/sql/SqlError").SqlError | import("effect/Schema").SchemaError, any>;
|
|
69
87
|
/**
|
|
70
88
|
* Build the complete server layer including the HTTP router and server.
|
|
71
89
|
* Accepts an optional port override (otherwise uses the port from AppConfig).
|
|
72
90
|
*
|
|
73
|
-
* @param options
|
|
91
|
+
* @param options - Optional serve options (`port`, `maxPortAttempts`)
|
|
74
92
|
* @returns A Layer ready to be launched
|
|
75
93
|
*
|
|
76
94
|
* @internal Called by serve() — most users should use serve() directly.
|
|
77
95
|
*/
|
|
78
|
-
buildLayer(options?:
|
|
79
|
-
port?: number;
|
|
80
|
-
}): Layer.Layer<HttpServer.HttpServer | import("@effect/platform/HttpPlatform").HttpPlatform | import("@effect/platform/Etag").Generator | import("../index.js").FileStorage | import("./types.js").PlatformServices | import("./types.js").DatabaseServices | import("../repository/repository.js").Repository | Migrator | import("../collection-service/collection-service.js").CollectionService | import("../thumbnail/index.js").ThumbnailService | AppConfig, import("effect/ParseResult").ParseError | import("@effect/platform/HttpServerError").ServeError | import("@effect/sql/SqlError").SqlError, never>;
|
|
96
|
+
buildLayer(options?: ServeOptions): Layer.Layer<import("../index.js").FileStorage | import("./types.js").PlatformServices | import("./types.js").DatabaseServices | import("../repository/repository.js").Repository | import("../index.js").CollectionService | AppConfig | Migrator | import("../cron/cron-service.js").CronService | import("../thumbnail/index.js").ThumbnailService, import("effect/http/HttpServerError").ServeError | import("effect/sql/SqlError").SqlError | import("effect/Schema").SchemaError, any>;
|
|
81
97
|
/**
|
|
82
98
|
* Start the Mira HTTP server.
|
|
83
|
-
* Sets up all services, runs auto-migration,
|
|
99
|
+
* Sets up all services, runs auto-migration, runs plugin lifecycle hooks,
|
|
100
|
+
* and listens for incoming requests.
|
|
84
101
|
* Blocks the main thread until the server is shut down.
|
|
85
102
|
*
|
|
86
|
-
*
|
|
103
|
+
* If the requested port is already in use, the server automatically retries
|
|
104
|
+
* on the next available port (up to `maxPortAttempts`, default 10).
|
|
105
|
+
*
|
|
106
|
+
* @param options - Optional serve options (`port`, `maxPortAttempts`)
|
|
87
107
|
*
|
|
88
108
|
* @example
|
|
89
|
-
* app.serve()
|
|
90
|
-
* app.serve({ port: 8080 })
|
|
109
|
+
* app.serve() // default port, auto-increment if busy
|
|
110
|
+
* app.serve({ port: 8080 }) // explicit port, auto-increment if busy
|
|
111
|
+
* app.serve({ port: 8080, maxPortAttempts: 1 }) // fail instead of incrementing
|
|
91
112
|
*/
|
|
92
|
-
serve(options?:
|
|
93
|
-
port?: number;
|
|
94
|
-
}): void;
|
|
113
|
+
serve(options?: ServeOptions): void;
|
|
95
114
|
}
|
|
96
115
|
//# sourceMappingURL=app.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../src/app/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../src/app/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAA;AAItC,OAAO,EAAE,SAAS,EAAiB,MAAM,mBAAmB,CAAA;AAW5D,OAAO,EAAE,QAAQ,EAAgB,MAAM,wBAAwB,CAAA;AAK/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAY7C,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,gBAAgB,EAChE,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,EAC7B,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,GAChC,KAAK,CAAC,CAAC,CAAC,CAkBV;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,OAAO,CAAC,CAAC,GAAG,KAAK;;gBAGhB,MAAM,EAAE,aAAa;IAKjC,+BAA+B;IAC/B,UAAU,IAAI,aAAa;IAI3B,+BAA+B;IAC/B,UAAU,IAAI,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAI5C,+BAA+B;IAC/B,wBAAwB,IAAI,aAAa,CAAC,gBAAgB,CAAC;IAI3D;;;;;;;;;;OAUG;IACH,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAiC3C;;;;;;;;;;;;;;;OAeG;IACH,iBAAiB;IAsDjB;;;;;;;;OAQG;IACH,UAAU,CAAC,OAAO,CAAC,EAAE,YAAY;IAyBjC;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI;CAqBpC"}
|
package/dist/src/app/app.js
CHANGED
|
@@ -1,13 +1,45 @@
|
|
|
1
|
-
import { HttpServer } from "@effect/platform";
|
|
2
1
|
import { Effect, Layer } from "effect";
|
|
3
|
-
import {
|
|
4
|
-
import { Migrator, MigratorLive } from "../migrator/migrator.js";
|
|
2
|
+
import { HttpRouter } from "effect/http";
|
|
5
3
|
import { makeCachedCollectionServiceLayer } from "../cache/index.js";
|
|
6
|
-
import { makeCollectionRouter } from "../http/router.js";
|
|
7
|
-
import { ThumbnailServicePhotonLive } from "../thumbnail/index.js";
|
|
8
|
-
import { ipAnnotationMiddleware } from "../http/ip-middleware.js";
|
|
9
4
|
import { AppConfig, AppConfigLive } from "../config/index.js";
|
|
5
|
+
import { makeCronServiceLayer } from "../cron/cron-service.js";
|
|
6
|
+
import { makeHookCollectionServiceLayer } from "../hooks/hook-collection.js";
|
|
7
|
+
import { makeHookServiceLayer } from "../hooks/hook-service.js";
|
|
8
|
+
import { HookService } from "../hooks/hook-service.js";
|
|
9
|
+
import { defaultCorsConfig, makeCorsMiddleware } from "../http/cors.js";
|
|
10
|
+
import { ipAnnotationMiddleware } from "../http/ip-middleware.js";
|
|
11
|
+
import { makePortRetryServerLayer } from "../http/port-retry.js";
|
|
12
|
+
import { makeCollectionRouter } from "../http/router.js";
|
|
10
13
|
import { HttpServerFactory } from "../http/server-factory.js";
|
|
14
|
+
import { Migrator, MigratorLive } from "../migrator/migrator.js";
|
|
15
|
+
import { RepositoryLive } from "../repository/repository.js";
|
|
16
|
+
import { ThumbnailServicePhotonLive } from "../thumbnail/index.js";
|
|
17
|
+
function assertUniqueCronNames(defs) {
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
for (const def of defs) {
|
|
20
|
+
if (seen.has(def.name)) {
|
|
21
|
+
throw new Error(`Duplicate cron name: "${def.name}". Cron names must be globally unique.`);
|
|
22
|
+
}
|
|
23
|
+
seen.add(def.name);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function applyRulesToCollections(collections, rules) {
|
|
27
|
+
const collectionNames = new Set(collections.map((c) => c.name));
|
|
28
|
+
for (const rb of rules) {
|
|
29
|
+
if (!collectionNames.has(rb.collectionName)) {
|
|
30
|
+
throw new Error(`RuleBinding references unknown collection "${rb.collectionName}". ` +
|
|
31
|
+
`Available collections: ${[...collectionNames].join(", ")}.`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const ruleMap = new Map(rules.map((r) => [r.collectionName, r.ruleMap]));
|
|
35
|
+
return collections.map((c) => {
|
|
36
|
+
const rm = ruleMap.get(c.name);
|
|
37
|
+
if (rm) {
|
|
38
|
+
return { ...c, schema: { ...c.schema, "x-rules": rm } };
|
|
39
|
+
}
|
|
40
|
+
return c;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
11
43
|
/**
|
|
12
44
|
* The assembled Mira application, ready to serve.
|
|
13
45
|
*
|
|
@@ -16,7 +48,7 @@ import { HttpServerFactory } from "../http/server-factory.js";
|
|
|
16
48
|
*
|
|
17
49
|
* `MiraApp` wires all layers (database, storage, collection service, HTTP server,
|
|
18
50
|
* telemetry, auto-migration) and provides `serve()` to start the server.
|
|
19
|
-
* Use `extend()` to add
|
|
51
|
+
* Use `extend()` to add plugins before serving.
|
|
20
52
|
*
|
|
21
53
|
* @example
|
|
22
54
|
* const app = Mira.builder()
|
|
@@ -29,8 +61,8 @@ import { HttpServerFactory } from "../http/server-factory.js";
|
|
|
29
61
|
* app.serve()
|
|
30
62
|
*
|
|
31
63
|
* @example
|
|
32
|
-
* // With
|
|
33
|
-
* app.extend(
|
|
64
|
+
* // With plugin
|
|
65
|
+
* app.extend(MiraDashboard).serve({ port: 8080 })
|
|
34
66
|
*
|
|
35
67
|
* @see MiraBuilder — builds MiraApp
|
|
36
68
|
* @see Mira — entry point: Mira.builder()
|
|
@@ -50,28 +82,56 @@ export class MiraApp {
|
|
|
50
82
|
_getExtras() {
|
|
51
83
|
return this.#extras;
|
|
52
84
|
}
|
|
85
|
+
/** @internal for tests only */
|
|
86
|
+
_resolveAdminCollections() {
|
|
87
|
+
return this.#getAdminCollections();
|
|
88
|
+
}
|
|
53
89
|
/**
|
|
54
|
-
* Add
|
|
55
|
-
*
|
|
56
|
-
*
|
|
90
|
+
* Add a plugin to the application. Plugins can register lifecycle hooks,
|
|
91
|
+
* record-lifecycle hooks, custom routes, service layers, and additional
|
|
92
|
+
* collection definitions.
|
|
57
93
|
*
|
|
58
|
-
* @param
|
|
94
|
+
* @param plugin - A MiraPlugin (use `fromLayer()` to wrap a plain Layer)
|
|
59
95
|
* @returns this (for chaining)
|
|
60
96
|
*
|
|
61
97
|
* @example
|
|
62
|
-
* app.extend(
|
|
98
|
+
* app.extend(MiraDashboard).serve()
|
|
63
99
|
*/
|
|
64
|
-
extend(
|
|
65
|
-
this.#extras.push(
|
|
100
|
+
extend(plugin) {
|
|
101
|
+
this.#extras.push(plugin);
|
|
66
102
|
return this;
|
|
67
103
|
}
|
|
104
|
+
#getAllCollections() {
|
|
105
|
+
const configCollections = applyRulesToCollections(this.#config.collections, this.#config.rules ?? []);
|
|
106
|
+
const all = [
|
|
107
|
+
...configCollections,
|
|
108
|
+
...this.#extras.flatMap((p) => p.collections ?? []),
|
|
109
|
+
...this.#getAdminCollections()
|
|
110
|
+
];
|
|
111
|
+
const byName = new Map();
|
|
112
|
+
for (const c of all) {
|
|
113
|
+
if (!byName.has(c.name)) {
|
|
114
|
+
byName.set(c.name, c);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return [...byName.values()];
|
|
118
|
+
}
|
|
119
|
+
#getAllPlugins() {
|
|
120
|
+
return this.#extras;
|
|
121
|
+
}
|
|
122
|
+
#getAllCrons() {
|
|
123
|
+
return [...this.#config.crons, ...this.#extras.flatMap((p) => p.crons ?? [])];
|
|
124
|
+
}
|
|
125
|
+
#getAdminCollections() {
|
|
126
|
+
return this.#extras.flatMap((p) => p.adminCollections ?? []);
|
|
127
|
+
}
|
|
68
128
|
/**
|
|
69
129
|
* Build the full service layer without the HTTP server.
|
|
70
130
|
* Useful for testing — you can run Effects against the service layer without
|
|
71
131
|
* starting a network server.
|
|
72
132
|
*
|
|
73
133
|
* Includes: database, storage, telemetry, repository, migrator, app config,
|
|
74
|
-
* collection service (with cache), and auto-migration.
|
|
134
|
+
* collection service (with cache + hooks), and auto-migration.
|
|
75
135
|
*
|
|
76
136
|
* @returns A Layer providing all services
|
|
77
137
|
*
|
|
@@ -82,58 +142,95 @@ export class MiraApp {
|
|
|
82
142
|
* )
|
|
83
143
|
*/
|
|
84
144
|
buildServiceLayer() {
|
|
85
|
-
const {
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
145
|
+
const { database, platform, storage, telemetry } = this.#config;
|
|
146
|
+
const allCollections = this.#getAllCollections();
|
|
147
|
+
const allPlugins = this.#getAllPlugins();
|
|
148
|
+
const allCronDefs = this.#getAllCrons();
|
|
149
|
+
assertUniqueCronNames(allCronDefs);
|
|
150
|
+
const pluginLayers = allPlugins.filter((p) => p.layer !== undefined).map((p) => p.layer);
|
|
151
|
+
const extrasLayer = pluginLayers.length > 0 ? pluginLayers.reduce((acc, l) => Layer.merge(acc, l)) : Layer.empty;
|
|
152
|
+
// Foundation: database + storage + thumbnail + telemetry, wired on platform
|
|
153
|
+
const foundation = Layer.mergeAll(database.layer, storage.layer, ThumbnailServicePhotonLive, telemetry).pipe(Layer.provideMerge(platform.layer));
|
|
92
154
|
// Mid: Repository + Migrator + AppConfig, wired on foundation
|
|
93
155
|
const mid = Layer.mergeAll(RepositoryLive, MigratorLive, AppConfigLive).pipe(Layer.provideMerge(foundation));
|
|
156
|
+
// Extras: plugin layers run after mid so they can depend on AppConfig + platform services
|
|
157
|
+
const extrasProvided = extrasLayer.pipe(Layer.provide(mid));
|
|
158
|
+
const fullMid = Layer.merge(mid, extrasProvided);
|
|
94
159
|
// Auto-migrate on boot: runs during layer initialization before requests are served
|
|
95
|
-
const schemas =
|
|
160
|
+
const schemas = allCollections.map((c) => ({ name: c.name, schema: c.schema }));
|
|
96
161
|
const autoMigrateLayer = Layer.effectDiscard(Effect.gen(function* () {
|
|
97
162
|
const migrator = yield* Migrator;
|
|
98
163
|
yield* migrator.migrate(schemas);
|
|
99
|
-
}).pipe(Effect.orDie)).pipe(Layer.provide(
|
|
100
|
-
//
|
|
101
|
-
|
|
164
|
+
}).pipe(Effect.orDie)).pipe(Layer.provide(fullMid));
|
|
165
|
+
// Core collection service (cached)
|
|
166
|
+
const cachedCollectionLayer = makeCachedCollectionServiceLayer(allCollections);
|
|
167
|
+
// Hook service layer (collects all plugin hooks)
|
|
168
|
+
const hookServiceLayer = makeHookServiceLayer(allPlugins);
|
|
169
|
+
// Hook collection service decorator: wraps cached collection service with hooks
|
|
170
|
+
const hookCollectionLayer = makeHookCollectionServiceLayer().pipe(Layer.provide(Layer.mergeAll(cachedCollectionLayer, hookServiceLayer)));
|
|
171
|
+
// Full top layer: hook-wrapped collection service + all mid services + auto-migration side effect
|
|
172
|
+
const topLayer = hookCollectionLayer.pipe(Layer.provideMerge(Layer.merge(fullMid, autoMigrateLayer)));
|
|
173
|
+
// Cron service: scoped fibers die when server stops; provided with full service stack + hook service
|
|
174
|
+
const cronServiceLayer = makeCronServiceLayer(allCronDefs).pipe(Layer.provide(Layer.mergeAll(topLayer, hookServiceLayer)));
|
|
175
|
+
return Layer.merge(topLayer, cronServiceLayer);
|
|
102
176
|
}
|
|
103
177
|
/**
|
|
104
178
|
* Build the complete server layer including the HTTP router and server.
|
|
105
179
|
* Accepts an optional port override (otherwise uses the port from AppConfig).
|
|
106
180
|
*
|
|
107
|
-
* @param options
|
|
181
|
+
* @param options - Optional serve options (`port`, `maxPortAttempts`)
|
|
108
182
|
* @returns A Layer ready to be launched
|
|
109
183
|
*
|
|
110
184
|
* @internal Called by serve() — most users should use serve() directly.
|
|
111
185
|
*/
|
|
112
186
|
buildLayer(options) {
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
const
|
|
187
|
+
const allCollections = this.#getAllCollections();
|
|
188
|
+
const adminCollections = this.#getAdminCollections().map((c) => c.name);
|
|
189
|
+
const collectionRoutes = makeCollectionRouter(allCollections, adminCollections);
|
|
190
|
+
const pluginRoutes = this.#extras.flatMap((p) => p.routes ?? []);
|
|
191
|
+
const routes = [...collectionRoutes, ...pluginRoutes];
|
|
116
192
|
const serviceLayer = this.buildServiceLayer();
|
|
117
|
-
const serverLayer = Layer.
|
|
193
|
+
const serverLayer = Layer.unwrap(Effect.gen(function* () {
|
|
118
194
|
const cfg = yield* AppConfig;
|
|
119
195
|
const factory = yield* HttpServerFactory;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
196
|
+
const effectivePort = options?.port ?? cfg.port;
|
|
197
|
+
return makePortRetryServerLayer(factory, effectivePort, options?.maxPortAttempts, (boundPort) => cfg.updateBoundPort?.(boundPort));
|
|
198
|
+
})).pipe(Layer.provide(serviceLayer));
|
|
199
|
+
return HttpRouter.serve(HttpRouter.addAll(routes), {
|
|
200
|
+
middleware: (effect) => ipAnnotationMiddleware(makeCorsMiddleware(this.#config.cors)(effect))
|
|
201
|
+
}).pipe(Layer.provide(serverLayer), Layer.provideMerge(serviceLayer));
|
|
123
202
|
}
|
|
124
203
|
/**
|
|
125
204
|
* Start the Mira HTTP server.
|
|
126
|
-
* Sets up all services, runs auto-migration,
|
|
205
|
+
* Sets up all services, runs auto-migration, runs plugin lifecycle hooks,
|
|
206
|
+
* and listens for incoming requests.
|
|
127
207
|
* Blocks the main thread until the server is shut down.
|
|
128
208
|
*
|
|
129
|
-
*
|
|
209
|
+
* If the requested port is already in use, the server automatically retries
|
|
210
|
+
* on the next available port (up to `maxPortAttempts`, default 10).
|
|
211
|
+
*
|
|
212
|
+
* @param options - Optional serve options (`port`, `maxPortAttempts`)
|
|
130
213
|
*
|
|
131
214
|
* @example
|
|
132
|
-
* app.serve()
|
|
133
|
-
* app.serve({ port: 8080 })
|
|
215
|
+
* app.serve() // default port, auto-increment if busy
|
|
216
|
+
* app.serve({ port: 8080 }) // explicit port, auto-increment if busy
|
|
217
|
+
* app.serve({ port: 8080, maxPortAttempts: 1 }) // fail instead of incrementing
|
|
134
218
|
*/
|
|
135
219
|
serve(options) {
|
|
136
|
-
this.#
|
|
220
|
+
const allPlugins = this.#getAllPlugins();
|
|
221
|
+
const hookServiceLayer = makeHookServiceLayer(allPlugins);
|
|
222
|
+
const fullLayer = this.buildLayer(options);
|
|
223
|
+
const usingDefaultCors = this.#config.cors === defaultCorsConfig;
|
|
224
|
+
this.#config.platform.runMain(Effect.gen(function* () {
|
|
225
|
+
if (usingDefaultCors) {
|
|
226
|
+
yield* Effect.logWarning("CORS: using the permissive default — every Origin is reflected and credentials are allowed. " +
|
|
227
|
+
"Configure Mira.builder().cors({ allowedOrigins, credentials }) for production.");
|
|
228
|
+
}
|
|
229
|
+
const hookService = yield* HookService.pipe(Effect.provide(hookServiceLayer));
|
|
230
|
+
const bootstrapLayer = Layer.effectDiscard(hookService.runBootstrap());
|
|
231
|
+
yield* Layer.launch(bootstrapLayer.pipe(Layer.provideMerge(fullLayer)));
|
|
232
|
+
yield* hookService.runServe();
|
|
233
|
+
}));
|
|
137
234
|
}
|
|
138
235
|
}
|
|
139
236
|
//# sourceMappingURL=app.js.map
|
package/dist/src/app/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/app/app.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/app/app.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,gCAAgC,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAE7D,OAAO,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAA;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAA;AAMjE,SAAS,qBAAqB,CAAC,IAAiC;IAC9D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,CAAC,IAAI,wCAAwC,CAAC,CAAA;QAC5F,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACpB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,WAA6B,EAC7B,KAAiC;IAEjC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/D,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CACb,8CAA8C,EAAE,CAAC,cAAc,KAAK;gBAClE,0BAA0B,CAAC,GAAG,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC/D,CAAA;QACH,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAkB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACzF,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAK,EAAE;QAC9B,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,EAAE,EAAE,CAAC;YACP,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,CAAA;QACzD,CAAC;QACD,OAAO,CAAC,CAAA;IACV,CAAC,CAAC,CAAA;AACJ,CAAC;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,OAAO,OAAO;IACT,OAAO,CAAe;IACtB,OAAO,CAAwB;IACxC,YAAY,MAAqB;QAC/B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;IACnB,CAAC;IAED,+BAA+B;IAC/B,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,+BAA+B;IAC/B,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,+BAA+B;IAC/B,wBAAwB;QACtB,OAAO,IAAI,CAAC,oBAAoB,EAAE,CAAA;IACpC,CAAC;IAED;;;;;;;;;;OAUG;IACH,MAAM,CAAC,MAAuB;QAC5B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACzB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,kBAAkB;QAChB,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;QACrG,MAAM,GAAG,GAAG;YACV,GAAG,iBAAiB;YACpB,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;YACnD,GAAG,IAAI,CAAC,oBAAoB,EAAE;SAC/B,CAAA;QACD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAA;QAClD,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IAED,YAAY;QACV,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAA;IAC/E,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAA;IAC9D,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,iBAAiB;QACf,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,OAAO,CAAA;QAC/D,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QACxC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,CAAA;QACvC,qBAAqB,CAAC,WAAW,CAAC,CAAA;QAElC,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAM,CAAC,CAAA;QAEzF,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAA;QAEhH,4EAA4E;QAC5E,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,0BAA0B,EAAE,SAAS,CAAC,CAAC,IAAI,CAC1G,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,CACnC,CAAA;QAED,8DAA8D;QAC9D,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAA;QAE5G,0FAA0F;QAC1F,MAAM,cAAc,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;QAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,cAAc,CAAC,CAAA;QAEhD,oFAAoF;QACpF,MAAM,OAAO,GAAuB,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACnG,MAAM,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAC1C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAA;YAChC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CACtB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;QAE9B,mCAAmC;QACnC,MAAM,qBAAqB,GAAG,gCAAgC,CAAC,cAAc,CAAC,CAAA;QAE9E,iDAAiD;QACjD,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAA;QAEzD,gFAAgF;QAChF,MAAM,mBAAmB,GAAG,8BAA8B,EAAE,CAAC,IAAI,CAC/D,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,CAAC,CACvE,CAAA;QAED,kGAAkG;QAClG,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAA;QAErG,qGAAqG;QACrG,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC,IAAI,CAC7D,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAC1D,CAAA;QAED,OAAO,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAA;IAChD,CAAC;IAED;;;;;;;;OAQG;IACH,UAAU,CAAC,OAAsB;QAC/B,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAA;QAChD,MAAM,gBAAgB,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACvE,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAA;QAC/E,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAA;QAChE,MAAM,MAAM,GAAG,CAAC,GAAG,gBAAgB,EAAE,GAAG,YAAY,CAAC,CAAA;QAErD,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAA;QAE7C,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAC9B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAA;YAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,iBAAiB,CAAA;YACxC,MAAM,aAAa,GAAG,OAAO,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,CAAA;YAC/C,OAAO,wBAAwB,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,SAAS,EAAE,EAAE,CAC9F,GAAG,CAAC,eAAe,EAAE,CAAC,SAAS,CAAC,CACjC,CAAA;QACH,CAAC,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA;QAEnC,OAAO,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;YACjD,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;SAC9F,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAA;IACvE,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,OAAsB;QAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QACxC,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAA;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAC1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,iBAAiB,CAAA;QAEhE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAC3B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,IAAI,gBAAgB,EAAE,CAAC;gBACrB,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CACtB,8FAA8F;oBAC5F,gFAAgF,CACnF,CAAA;YACH,CAAC;YACD,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAA;YAC7E,MAAM,cAAc,GAAG,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,CAAA;YACtE,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;YACvE,KAAK,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAA;QAC/B,CAAC,CAAuC,CACzC,CAAA;IACH,CAAC;CACF"}
|