| 1688 | }; |
| 1689 | |
| 1690 | export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = readonly []>( |
| 1691 | config: ExecutorConfig<TPlugins>, |
| 1692 | ): Effect.Effect<Executor<TPlugins>, StorageFailure> => |
| 1693 | Effect.gen(function* () { |
| 1694 | const defaultPlugins = (): TPlugins => { |
| 1695 | const empty: readonly AnyPlugin[] = []; |
| 1696 | return empty as TPlugins; |
| 1697 | }; |
| 1698 | const { plugins: userPlugins = defaultPlugins() } = config; |
| 1699 | |
| 1700 | const tenant = String(config.tenant); |
| 1701 | const subject = config.subject != null ? String(config.subject) : null; |
| 1702 | |
| 1703 | const ownerBinding: OwnerBinding = { |
| 1704 | tenant: config.tenant, |
| 1705 | subject: config.subject ?? null, |
| 1706 | }; |
| 1707 | |
| 1708 | const ownedKeys = (owner: Owner): OwnedKeys => { |
| 1709 | if (owner === "org") return { tenant, owner, subject: ORG_SUBJECT }; |
| 1710 | if (subject == null) { |
| 1711 | // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: programmer error caught and surfaced as StorageError below by callers |
| 1712 | throw new StorageError({ |
| 1713 | message: `Cannot target owner "user": executor has no subject.`, |
| 1714 | cause: undefined, |
| 1715 | }); |
| 1716 | } |
| 1717 | return { tenant, owner, subject }; |
| 1718 | }; |
| 1719 | |
| 1720 | const requireUserSubject = (owner: Owner): Effect.Effect<void, StorageFailure> => |
| 1721 | owner === "user" && subject == null |
| 1722 | ? Effect.fail( |
| 1723 | new StorageError({ |
| 1724 | message: `Cannot target owner "user": executor has no subject.`, |
| 1725 | cause: undefined, |
| 1726 | }), |
| 1727 | ) |
| 1728 | : Effect.void; |
| 1729 | |
| 1730 | // Built-in core-tools plugin: agent-facing static tools over the v2 surface. |
| 1731 | const plugins: readonly AnyPlugin[] = config.coreTools |
| 1732 | ? ([ |
| 1733 | coreToolsPlugin({ |
| 1734 | webBaseUrl: config.coreTools.webBaseUrl, |
| 1735 | orgSlug: config.coreTools.orgSlug, |
| 1736 | includeProviders: config.coreTools.includeProviders, |
| 1737 | }), |
| 1738 | ...userPlugins, |
| 1739 | ] as readonly AnyPlugin[]) |
| 1740 | : (userPlugins as readonly AnyPlugin[]); |
| 1741 | |
| 1742 | const tables = yield* Effect.try({ |
| 1743 | try: () => collectTables(), |
| 1744 | catch: (cause) => storageFailureFromUnknown("Failed to collect executor tables", cause), |
| 1745 | }); |
| 1746 | const dbInput = yield* Effect.suspend(() => { |
| 1747 | if (!config.db) return Effect.succeed(createDefaultMemoryDb(tables)); |