(options: LocalExecutorOptions = {})
| 157 | ); |
| 158 | |
| 159 | const createLocalExecutorLayer = (options: LocalExecutorOptions = {}) => { |
| 160 | const storage = resolveStorage(); |
| 161 | |
| 162 | return Layer.effect(LocalExecutorTag)( |
| 163 | Effect.gen(function* () { |
| 164 | const { cwd, plugins } = yield* loadLocalPlugins(options); |
| 165 | const tenantId = makeTenantId(cwd); |
| 166 | const tables = collectTables(); |
| 167 | |
| 168 | // A borrowed handle is owned by its opener, so it is used as-is and left |
| 169 | // open on release; only a handle opened here is closed here. |
| 170 | const owned = options.borrowedDb |
| 171 | ? options.borrowedDb |
| 172 | : yield* Effect.acquireRelease( |
| 173 | Effect.tryPromise({ |
| 174 | try: () => |
| 175 | openOwnedLocalDatabase({ |
| 176 | dataDir: storage.dataDir, |
| 177 | tables, |
| 178 | namespace: localNamespace, |
| 179 | tenantId, |
| 180 | }), |
| 181 | catch: (cause) => |
| 182 | new LocalExecutorCreateError({ |
| 183 | message: CREATE_SQLITE_ERROR_MESSAGE, |
| 184 | cause, |
| 185 | }), |
| 186 | }), |
| 187 | (database) => Effect.promise(() => database.close()).pipe(Effect.ignore), |
| 188 | ); |
| 189 | const sqlite = owned.db; |
| 190 | const migration = owned.migration; |
| 191 | |
| 192 | // Boot-time data migrations: each registry entry runs once and is |
| 193 | // stamped in the `data_migration` ledger; stamped entries are skipped |
| 194 | // without touching the data. |
| 195 | yield* runSqliteDataMigrations(sqlite.client, localDataMigrations).pipe( |
| 196 | Effect.mapError( |
| 197 | (cause) => |
| 198 | new LocalExecutorCreateError({ |
| 199 | message: CREATE_SQLITE_ERROR_MESSAGE, |
| 200 | cause, |
| 201 | }), |
| 202 | ), |
| 203 | ); |
| 204 | |
| 205 | // webBaseUrl is where the executor's web UI listens — same port as the |
| 206 | // daemon API since the daemon serves both. Mirrors serve.ts's port |
| 207 | // resolution so a custom $PORT flows through. EXECUTOR_WEB_BASE_URL |
| 208 | // overrides entirely for deployments where the UI is on a different host. |
| 209 | const webBaseUrl = |
| 210 | process.env.EXECUTOR_WEB_BASE_URL ?? `http://localhost:${process.env.PORT ?? "4788"}`; |
| 211 | |
| 212 | const executor = yield* createExecutor({ |
| 213 | tenant: Tenant.make(tenantId), |
| 214 | subject: Subject.make(LOCAL_SUBJECT), |
| 215 | db: sqlite.db, |
| 216 | plugins, |
no test coverage detected