@fragno-dev/project-connector-fragment 0.0.0-stage → 0.0.1

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 (77) hide show
  1. package/LICENSE.md +16 -0
  2. package/README.md +285 -2
  3. package/bin/run.js +4 -0
  4. package/dist/browser/client/react.d.ts +174 -0
  5. package/dist/browser/client/react.d.ts.map +1 -0
  6. package/dist/browser/client/react.js +195 -0
  7. package/dist/browser/client/react.js.map +1 -0
  8. package/dist/browser/client/solid.d.ts +177 -0
  9. package/dist/browser/client/solid.d.ts.map +1 -0
  10. package/dist/browser/client/solid.js +130 -0
  11. package/dist/browser/client/solid.js.map +1 -0
  12. package/dist/browser/client/svelte.d.ts +177 -0
  13. package/dist/browser/client/svelte.d.ts.map +1 -0
  14. package/dist/browser/client/svelte.js +132 -0
  15. package/dist/browser/client/svelte.js.map +1 -0
  16. package/dist/browser/client/vanilla.d.ts +204 -0
  17. package/dist/browser/client/vanilla.d.ts.map +1 -0
  18. package/dist/browser/client/vanilla.js +160 -0
  19. package/dist/browser/client/vanilla.js.map +1 -0
  20. package/dist/browser/client/vue.d.ts +177 -0
  21. package/dist/browser/client/vue.d.ts.map +1 -0
  22. package/dist/browser/client/vue.js +128 -0
  23. package/dist/browser/client/vue.js.map +1 -0
  24. package/dist/browser/client-BCzNDSlW.d.ts +711 -0
  25. package/dist/browser/client-BCzNDSlW.d.ts.map +1 -0
  26. package/dist/browser/index.d.ts +504 -0
  27. package/dist/browser/index.d.ts.map +1 -0
  28. package/dist/browser/index.js +2 -0
  29. package/dist/browser/src-CSPQuoKz.js +2286 -0
  30. package/dist/browser/src-CSPQuoKz.js.map +1 -0
  31. package/dist/cli/authorization-browser.js +20 -0
  32. package/dist/cli/authorization-browser.js.map +1 -0
  33. package/dist/cli/cli.d.ts +6 -0
  34. package/dist/cli/cli.d.ts.map +1 -0
  35. package/dist/cli/cli.js +258 -0
  36. package/dist/cli/cli.js.map +1 -0
  37. package/dist/cli/definition.js +13 -0
  38. package/dist/cli/definition.js.map +1 -0
  39. package/dist/cli/index.js +14 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cli/project-connector-client.js +235 -0
  42. package/dist/cli/project-connector-client.js.map +1 -0
  43. package/dist/cli/project-connector-contracts.js +125 -0
  44. package/dist/cli/project-connector-contracts.js.map +1 -0
  45. package/dist/cli/routes.js +449 -0
  46. package/dist/cli/routes.js.map +1 -0
  47. package/dist/cli/schema.js +18 -0
  48. package/dist/cli/schema.js.map +1 -0
  49. package/dist/node/definition.d.ts +170 -0
  50. package/dist/node/definition.d.ts.map +1 -0
  51. package/dist/node/definition.js +13 -0
  52. package/dist/node/definition.js.map +1 -0
  53. package/dist/node/index.d.ts +456 -0
  54. package/dist/node/index.d.ts.map +1 -0
  55. package/dist/node/index.js +36 -0
  56. package/dist/node/index.js.map +1 -0
  57. package/dist/node/project-connector-client.d.ts +13 -0
  58. package/dist/node/project-connector-client.d.ts.map +1 -0
  59. package/dist/node/project-connector-client.js +235 -0
  60. package/dist/node/project-connector-client.js.map +1 -0
  61. package/dist/node/project-connector-contracts.d.ts +179 -0
  62. package/dist/node/project-connector-contracts.d.ts.map +1 -0
  63. package/dist/node/project-connector-contracts.js +125 -0
  64. package/dist/node/project-connector-contracts.js.map +1 -0
  65. package/dist/node/routes.d.ts +307 -0
  66. package/dist/node/routes.d.ts.map +1 -0
  67. package/dist/node/routes.js +449 -0
  68. package/dist/node/routes.js.map +1 -0
  69. package/dist/node/schema.d.ts +49 -0
  70. package/dist/node/schema.d.ts.map +1 -0
  71. package/dist/node/schema.js +18 -0
  72. package/dist/node/schema.js.map +1 -0
  73. package/dist/node/testing/project-connector-test-gateway.d.ts +63 -0
  74. package/dist/node/testing/project-connector-test-gateway.d.ts.map +1 -0
  75. package/dist/node/testing/project-connector-test-gateway.js +370 -0
  76. package/dist/node/testing/project-connector-test-gateway.js.map +1 -0
  77. package/package.json +111 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","names":[],"sources":["../../src/routes.ts"],"sourcesContent":["import { decodeCursor, type Cursor } from \"@fragno-dev/db/cursor\";\nimport { z } from \"zod\";\n\nimport { defineRoutes } from \"@fragno-dev/core\";\n\nimport { projectConnectorFragmentDefinition } from \"./definition\";\nimport {\n confirmProjectConnectorRequest,\n ProjectConnectorClientError,\n} from \"./project-connector-client\";\nimport {\n projectConnectorAccountsSchema,\n projectConnectorNamedConnectionSchema,\n projectConnectorNamedRequestSchema,\n projectConnectorNamedAccountSchema,\n projectConnectorStatusSchema,\n projectConnectorProviderConfigsSchema,\n projectConnectorProviderActionsSchema,\n projectConnectorConnectInputSchema,\n projectConnectorConnectionSchema,\n projectConnectorProfileSchema,\n projectConnectorExecutionSchema,\n type ProjectConnectorConnectionState,\n} from \"./project-connector-contracts\";\nimport { projectConnectorSchema } from \"./schema\";\n\nfunction serializeProjectConnectorRequest(\n saved: Omit<z.output<typeof projectConnectorConnectionSchema>, \"id\"> & {\n id: { toString(): string };\n },\n): z.output<typeof projectConnectorConnectionSchema> {\n return {\n id: saved.id.toString(),\n projectId: saved.projectId,\n providerConfigId: saved.providerConfigId,\n externalUserId: saved.externalUserId,\n service: saved.service,\n connectionName: saved.connectionName,\n authorizationUrl: saved.authorizationUrl,\n expiresAt: saved.expiresAt,\n state: saved.state,\n };\n}\n\n/** Authenticated routes never accept a product user ID or account binding from the browser. */\nexport const projectConnectorRoutes = defineRoutes(projectConnectorFragmentDefinition).create(\n ({ config, deps, defineRoute }) => [\n defineRoute({\n method: \"GET\",\n path: \"/provider-configs\",\n outputSchema: projectConnectorProviderConfigsSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"PROJECT_CONNECTOR_ERROR\"],\n handler: async function ({ headers }, { json, error }) {\n if (!(await config.getExternalUserId(headers))) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n try {\n return json(await deps.projectConnector.listProviderConfigs());\n } catch (cause) {\n if (!(cause instanceof ProjectConnectorClientError)) {\n throw cause;\n }\n return error({ code: \"PROJECT_CONNECTOR_ERROR\", message: cause.message }, 502);\n }\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/provider-configs/:providerConfigId/actions\",\n outputSchema: projectConnectorProviderActionsSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"PROVIDER_CONFIG_NOT_FOUND\", \"PROJECT_CONNECTOR_ERROR\"],\n handler: async function ({ headers, pathParams }, { json, error }) {\n if (!(await config.getExternalUserId(headers))) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n try {\n const actions = await deps.projectConnector.listProviderActions(\n pathParams.providerConfigId,\n );\n if (!actions) {\n return error(\n {\n code: \"PROVIDER_CONFIG_NOT_FOUND\",\n message: \"Provider configuration not found\",\n },\n 404,\n );\n }\n return json(actions);\n } catch (cause) {\n if (!(cause instanceof ProjectConnectorClientError)) {\n throw cause;\n }\n return error({ code: \"PROJECT_CONNECTOR_ERROR\", message: cause.message }, 502);\n }\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/status\",\n outputSchema: projectConnectorStatusSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"PROJECT_CONNECTOR_ERROR\"],\n handler: async function ({ headers }, { json, error }) {\n if (!(await config.getExternalUserId(headers))) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n try {\n return json(await deps.projectConnector.check());\n } catch (cause) {\n if (!(cause instanceof ProjectConnectorClientError)) {\n throw cause;\n }\n return error({ code: \"PROJECT_CONNECTOR_ERROR\", message: cause.message }, 502);\n }\n },\n }),\n defineRoute({\n method: \"POST\",\n path: \"/connection-requests\",\n inputSchema: projectConnectorConnectInputSchema,\n outputSchema: projectConnectorConnectionSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"RETURN_URI_NOT_ALLOWED\", \"PROJECT_CONNECTOR_ERROR\"],\n handler: async function ({ headers, input }, { json, error }) {\n const externalUserId = await config.getExternalUserId(headers);\n if (!externalUserId) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n const body = await input.valid();\n if (!config.allowedReturnUrls(new URL(body.returnUri))) {\n return error(\n { code: \"RETURN_URI_NOT_ALLOWED\", message: \"OAuth return URL is not allowed\" },\n 400,\n );\n }\n try {\n const remote = await deps.projectConnector.connect(externalUserId, body);\n if (\n remote.externalUserId !== externalUserId ||\n remote.connectionName !== body.connectionName ||\n (\"providerConfigId\" in body\n ? remote.providerConfigId !== body.providerConfigId\n : remote.service !== body.service)\n ) {\n throw new ProjectConnectorClientError(\"connection_identity_mismatch\", 502);\n }\n const connection = {\n id: remote.id,\n projectId: remote.projectId,\n providerConfigId: remote.providerConfigId,\n externalUserId,\n service: remote.service,\n connectionName: remote.connectionName,\n authorizationUrl: remote.authorizationUrl,\n expiresAt: remote.expiresAt,\n state: { status: \"initiated\" as const },\n };\n const named = {\n projectId: remote.projectId,\n providerConfigId: remote.providerConfigId,\n connectionName: body.connectionName,\n };\n await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(projectConnectorSchema).findFirst(\"connectedAccount\", (b) =>\n b.whereIndex(\"idx_account_named_connection\", (eb) =>\n eb.and(\n eb(\"externalUserId\", \"=\", externalUserId),\n eb(\"projectId\", \"=\", named.projectId),\n eb(\"providerConfigId\", \"=\", named.providerConfigId),\n eb(\"connectionName\", \"=\", named.connectionName),\n ),\n ),\n ),\n )\n .mutate(({ forSchema, retrieveResult: [account] }) => {\n const uow = forSchema(projectConnectorSchema);\n uow.create(\"connectionRequest\", connection);\n // Another attempt leaves a name that already has a confirmed account ready.\n if (!account) {\n uow.triggerHook(\"onConnectionReadinessChanged\", {\n externalUserId,\n service: remote.service,\n connection: named,\n ready: false,\n });\n }\n })\n .execute();\n return json(connection);\n } catch (cause) {\n if (!(cause instanceof ProjectConnectorClientError)) {\n throw cause;\n }\n return error({ code: \"PROJECT_CONNECTOR_ERROR\", message: cause.message }, 502);\n }\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/connection-requests/by-name\",\n queryParameters: [\"projectId\", \"providerConfigId\", \"connectionName\"],\n outputSchema: projectConnectorNamedRequestSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"INVALID_SELECTOR\", \"CONNECTION_AMBIGUOUS\"],\n handler: async function ({ headers, query }, { json, error }) {\n const externalUserId = await config.getExternalUserId(headers);\n if (!externalUserId) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n const selector = projectConnectorNamedConnectionSchema.safeParse({\n projectId: query.get(\"projectId\"),\n providerConfigId: query.get(\"providerConfigId\"),\n connectionName: query.get(\"connectionName\"),\n });\n if (!selector.success) {\n return error(\n { code: \"INVALID_SELECTOR\", message: \"Invalid named connection selector\" },\n 400,\n );\n }\n const [page] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(projectConnectorSchema).findWithCursor(\"connectionRequest\", (b) =>\n b\n .whereIndex(\"idx_request_named_connection\", (eb) =>\n eb.and(\n eb(\"externalUserId\", \"=\", externalUserId),\n eb(\"projectId\", \"=\", selector.data.projectId),\n eb(\"providerConfigId\", \"=\", selector.data.providerConfigId),\n eb(\"connectionName\", \"=\", selector.data.connectionName),\n ),\n )\n .orderByIndex(\"idx_request_named_connection\", \"asc\")\n .pageSize(2),\n ),\n )\n .execute();\n if (page.items.length > 1) {\n return error(\n {\n code: \"CONNECTION_AMBIGUOUS\",\n message: \"Project Connector named connection matches multiple OAuth requests.\",\n },\n 409,\n );\n }\n const [saved] = page.items;\n return json({ request: saved ? serializeProjectConnectorRequest(saved) : null });\n },\n }),\n defineRoute({\n method: \"POST\",\n path: \"/connection-requests/:requestId/refresh\",\n outputSchema: projectConnectorConnectionSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"REQUEST_NOT_FOUND\", \"PROJECT_CONNECTOR_ERROR\"],\n handler: async function ({ headers, pathParams }, { json, error }) {\n const externalUserId = await config.getExternalUserId(headers);\n if (!externalUserId) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n let confirmed: ProjectConnectorConnectionState | null = null;\n try {\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(projectConnectorSchema)\n .findFirst(\"connectionRequest\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.requestId)),\n )\n // Confirmation supplies the account ID later; acquire owned IDs in the single read phase.\n .find(\"connectedAccount\", (b) =>\n b\n .whereIndex(\"idx_account_external_user_id\", (eb) =>\n eb(\"externalUserId\", \"=\", externalUserId),\n )\n .select([\"id\", \"projectId\", \"providerConfigId\", \"service\", \"connectionName\"]),\n ),\n )\n .afterRetrieve(async (_uow, [saved]) => {\n // OCC retries must not reuse a confirmation prepared for an older snapshot.\n confirmed = null;\n if (\n !saved ||\n saved.externalUserId !== externalUserId ||\n saved.state.status !== \"initiated\"\n ) {\n return;\n }\n const remote = await deps.projectConnector.getConnectionRequest(saved.id.toString());\n confirmed = confirmProjectConnectorRequest(\n { ...saved, id: saved.id.toString() },\n remote,\n );\n })\n .mutate(({ forSchema, retrieveResult: [saved, accounts] }) => {\n if (!saved || saved.externalUserId !== externalUserId) {\n return null;\n }\n const state = confirmed ?? saved.state;\n const uow = forSchema(projectConnectorSchema);\n if (saved.state.status === \"initiated\" && state.status !== \"initiated\") {\n uow.update(\"connectionRequest\", saved.id, (b) => b.set({ state }).check());\n if (state.status === \"connected\") {\n const existing = accounts.find(\n (account) => account.id.toString() === state.connectedAccountId,\n );\n // Reauthorization replaces only the same owned account ID, not other accounts sharing its name.\n if (existing) {\n uow.delete(\"connectedAccount\", existing.id, (b) => b.check());\n }\n // An incoming ID belonging to another user must fail the create, never replace their binding.\n uow.create(\"connectedAccount\", {\n id: state.connectedAccountId,\n projectId: saved.projectId,\n providerConfigId: saved.providerConfigId,\n externalUserId: saved.externalUserId,\n service: saved.service,\n connectionName: saved.connectionName,\n });\n const sameName =\n (named: (typeof accounts)[number] | typeof saved) =>\n (account: (typeof accounts)[number]) =>\n account.projectId === named.projectId &&\n account.providerConfigId === named.providerConfigId &&\n account.connectionName === named.connectionName;\n // Reauthorization can move the account to this name, leaving its old name without one.\n if (\n existing &&\n !sameName(saved)(existing) &&\n !accounts.some((account) => account !== existing && sameName(existing)(account))\n ) {\n uow.triggerHook(\"onConnectionReadinessChanged\", {\n externalUserId,\n service: existing.service,\n connection: {\n projectId: existing.projectId,\n providerConfigId: existing.providerConfigId,\n connectionName: existing.connectionName,\n },\n ready: false,\n });\n }\n const wasReady = accounts.some(sameName(saved));\n if (!wasReady) {\n uow.triggerHook(\"onConnectionReadinessChanged\", {\n externalUserId,\n service: saved.service,\n connection: {\n projectId: saved.projectId,\n providerConfigId: saved.providerConfigId,\n connectionName: saved.connectionName,\n },\n ready: true,\n });\n }\n }\n }\n return serializeProjectConnectorRequest({ ...saved, state });\n })\n .execute();\n if (!result) {\n return error(\n { code: \"REQUEST_NOT_FOUND\", message: \"Connection request not found\" },\n 404,\n );\n }\n return json(result);\n } catch (cause) {\n if (!(cause instanceof ProjectConnectorClientError)) {\n throw cause;\n }\n return error({ code: \"PROJECT_CONNECTOR_ERROR\", message: cause.message }, 502);\n }\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/accounts\",\n queryParameters: [\"cursor\"],\n outputSchema: projectConnectorAccountsSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"INVALID_CURSOR\"],\n handler: async function ({ headers, query }, { json, error }) {\n const externalUserId = await config.getExternalUserId(headers);\n if (!externalUserId) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n let cursor: Cursor | null = null;\n const rawCursor = query.get(\"cursor\");\n if (rawCursor) {\n try {\n cursor = decodeCursor(rawCursor);\n const accountId = cursor.indexValues[\"id\"];\n if (\n cursor.indexName !== \"idx_account_external_user_id\" ||\n cursor.orderDirection !== \"asc\" ||\n cursor.pageSize !== 25 ||\n cursor.indexValues[\"externalUserId\"] !== externalUserId ||\n typeof accountId !== \"string\" ||\n accountId.length === 0\n ) {\n throw new Error(\"Account cursor does not match this user or query\");\n }\n } catch {\n return error({ code: \"INVALID_CURSOR\", message: \"Invalid account cursor\" }, 400);\n }\n }\n const [page] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(projectConnectorSchema).findWithCursor(\"connectedAccount\", (b) => {\n const ordered = b\n .whereIndex(\"idx_account_external_user_id\", (eb) =>\n eb(\"externalUserId\", \"=\", externalUserId),\n )\n .orderByIndex(\"idx_account_external_user_id\", \"asc\")\n .pageSize(25);\n return cursor ? ordered.after(cursor) : ordered;\n }),\n )\n .execute();\n return json({\n accounts: page.items.map((account) => ({\n id: account.id.toString(),\n projectId: account.projectId,\n providerConfigId: account.providerConfigId,\n externalUserId: account.externalUserId,\n service: account.service,\n connectionName: account.connectionName,\n })),\n cursor: page.cursor?.encode() ?? null,\n hasNextPage: page.hasNextPage,\n });\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/accounts/by-name\",\n queryParameters: [\"projectId\", \"providerConfigId\", \"connectionName\"],\n outputSchema: projectConnectorNamedAccountSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"INVALID_SELECTOR\", \"CONNECTION_AMBIGUOUS\"],\n handler: async function ({ headers, query }, { json, error }) {\n const externalUserId = await config.getExternalUserId(headers);\n if (!externalUserId) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n const selector = projectConnectorNamedConnectionSchema.safeParse({\n projectId: query.get(\"projectId\"),\n providerConfigId: query.get(\"providerConfigId\"),\n connectionName: query.get(\"connectionName\"),\n });\n if (!selector.success) {\n return error(\n { code: \"INVALID_SELECTOR\", message: \"Invalid named connection selector\" },\n 400,\n );\n }\n const [page] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(projectConnectorSchema).findWithCursor(\"connectedAccount\", (b) =>\n b\n .whereIndex(\"idx_account_named_connection\", (eb) =>\n eb.and(\n eb(\"externalUserId\", \"=\", externalUserId),\n eb(\"projectId\", \"=\", selector.data.projectId),\n eb(\"providerConfigId\", \"=\", selector.data.providerConfigId),\n eb(\"connectionName\", \"=\", selector.data.connectionName),\n ),\n )\n .orderByIndex(\"idx_account_named_connection\", \"asc\")\n .pageSize(2),\n ),\n )\n .execute();\n if (page.items.length > 1) {\n return error(\n {\n code: \"CONNECTION_AMBIGUOUS\",\n message: \"Project Connector named connection matches multiple confirmed accounts.\",\n },\n 409,\n );\n }\n const [account] = page.items;\n return json({\n account: account\n ? {\n id: account.id.toString(),\n projectId: account.projectId,\n providerConfigId: account.providerConfigId,\n externalUserId: account.externalUserId,\n service: account.service,\n connectionName: account.connectionName,\n }\n : null,\n });\n },\n }),\n defineRoute({\n method: \"GET\",\n path: \"/accounts/:accountId/profile\",\n outputSchema: projectConnectorProfileSchema,\n errorCodes: [\"UNAUTHENTICATED\", \"ACCOUNT_NOT_FOUND\", \"PROJECT_CONNECTOR_ERROR\"],\n handler: async function ({ headers, pathParams }, { json, error }) {\n const externalUserId = await config.getExternalUserId(headers);\n if (!externalUserId) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n const [account] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(projectConnectorSchema).findFirst(\"connectedAccount\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.accountId)),\n ),\n )\n .execute();\n if (!account || account.externalUserId !== externalUserId) {\n return error({ code: \"ACCOUNT_NOT_FOUND\", message: \"Connected account not found\" }, 404);\n }\n try {\n const profile = await deps.projectConnector.getProfile(account.id.toString());\n if (\n profile.connectedAccountId !== account.id.toString() ||\n profile.externalUserId !== externalUserId ||\n profile.service !== account.service\n ) {\n throw new ProjectConnectorClientError(\"account_identity_mismatch\", 502);\n }\n return json(profile);\n } catch (cause) {\n if (!(cause instanceof ProjectConnectorClientError)) {\n throw cause;\n }\n return error({ code: \"PROJECT_CONNECTOR_ERROR\", message: cause.message }, 502);\n }\n },\n }),\n defineRoute({\n method: \"POST\",\n path: \"/accounts/:accountId/actions/:actionId\",\n inputSchema: z.strictObject({ input: z.record(z.string(), z.unknown()) }),\n outputSchema: projectConnectorExecutionSchema,\n errorCodes: [\n \"UNAUTHENTICATED\",\n \"ACCOUNT_NOT_FOUND\",\n \"ACTION_SERVICE_MISMATCH\",\n \"PROJECT_CONNECTOR_ERROR\",\n ],\n handler: async function ({ headers, pathParams, input }, { json, error }) {\n const externalUserId = await config.getExternalUserId(headers);\n if (!externalUserId) {\n return error({ code: \"UNAUTHENTICATED\", message: \"Authentication required\" }, 401);\n }\n const body = await input.valid();\n const [account] = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(projectConnectorSchema).findFirst(\"connectedAccount\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", pathParams.accountId)),\n ),\n )\n .execute();\n if (!account || account.externalUserId !== externalUserId) {\n return error({ code: \"ACCOUNT_NOT_FOUND\", message: \"Connected account not found\" }, 404);\n }\n if (\n !pathParams.actionId.startsWith(`${account.service}.`) ||\n !/^[a-z0-9_-]+\\.[a-z0-9_-]+$/.test(pathParams.actionId)\n ) {\n return error(\n {\n code: \"ACTION_SERVICE_MISMATCH\",\n message: \"Action must belong to the connected account service\",\n },\n 400,\n );\n }\n try {\n return json(\n await deps.projectConnector.execute(\n { ...account, id: account.id.toString() },\n pathParams.actionId,\n body.input,\n ),\n );\n } catch (cause) {\n if (!(cause instanceof ProjectConnectorClientError)) {\n throw cause;\n }\n return error({ code: \"PROJECT_CONNECTOR_ERROR\", message: cause.message }, 502);\n }\n },\n }),\n ],\n);\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { column, idColumn, schema } from "@fragno-dev/db/schema";
2
+ //#region src/schema.ts
3
+ /** Product-user bindings and OAuth requests; upstream credentials stay in ProjectConnector. */
4
+ const projectConnectorSchema = schema("project-connector-fragment", (s) => s.addTable("connectionRequest", (t) => t.addColumn("id", idColumn()).addColumn("projectId", column("string")).addColumn("providerConfigId", column("string")).addColumn("externalUserId", column("string")).addColumn("service", column("string")).addColumn("connectionName", column("string").nullable()).addColumn("authorizationUrl", column("text")).addColumn("expiresAt", column("string")).addColumn("state", column("json"))).addTable("connectedAccount", (t) => t.addColumn("id", idColumn()).addColumn("projectId", column("string")).addColumn("providerConfigId", column("string")).addColumn("externalUserId", column("string")).addColumn("service", column("string")).addColumn("connectionName", column("string").nullable()).createIndex("idx_account_external_user_id", ["externalUserId", "id"])).alterTable("connectionRequest", (t) => t.createIndex("idx_request_named_connection", [
5
+ "externalUserId",
6
+ "projectId",
7
+ "providerConfigId",
8
+ "connectionName"
9
+ ])).alterTable("connectedAccount", (t) => t.createIndex("idx_account_named_connection", [
10
+ "externalUserId",
11
+ "projectId",
12
+ "providerConfigId",
13
+ "connectionName"
14
+ ])).alterTable("connectionRequest", (t) => t.alterColumn("connectionName").nullable(false)).alterTable("connectedAccount", (t) => t.alterColumn("connectionName").nullable(false)));
15
+ //#endregion
16
+ export { projectConnectorSchema };
17
+
18
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../src/schema.ts"],"sourcesContent":["import { column, idColumn, schema, type Column } from \"@fragno-dev/db/schema\";\n\nimport type { ProjectConnectorConnectionState } from \"./project-connector-contracts\";\n\n/** Product-user bindings and OAuth requests; upstream credentials stay in ProjectConnector. */\nexport const projectConnectorSchema = schema(\"project-connector-fragment\", (s) =>\n s\n .addTable(\"connectionRequest\", (t) =>\n t\n .addColumn(\"id\", idColumn())\n .addColumn(\"projectId\", column(\"string\"))\n .addColumn(\"providerConfigId\", column(\"string\"))\n .addColumn(\"externalUserId\", column(\"string\"))\n .addColumn(\"service\", column(\"string\"))\n .addColumn(\"connectionName\", column(\"string\").nullable())\n .addColumn(\"authorizationUrl\", column(\"text\"))\n .addColumn(\"expiresAt\", column(\"string\"))\n .addColumn(\n \"state\",\n column(\"json\") as Column<\n \"json\",\n ProjectConnectorConnectionState,\n ProjectConnectorConnectionState\n >,\n ),\n )\n .addTable(\"connectedAccount\", (t) =>\n t\n .addColumn(\"id\", idColumn())\n .addColumn(\"projectId\", column(\"string\"))\n .addColumn(\"providerConfigId\", column(\"string\"))\n .addColumn(\"externalUserId\", column(\"string\"))\n .addColumn(\"service\", column(\"string\"))\n .addColumn(\"connectionName\", column(\"string\").nullable())\n .createIndex(\"idx_account_external_user_id\", [\"externalUserId\", \"id\"]),\n )\n .alterTable(\"connectionRequest\", (t) =>\n t.createIndex(\"idx_request_named_connection\", [\n \"externalUserId\",\n \"projectId\",\n \"providerConfigId\",\n \"connectionName\",\n ]),\n )\n .alterTable(\"connectedAccount\", (t) =>\n t.createIndex(\"idx_account_named_connection\", [\n \"externalUserId\",\n \"projectId\",\n \"providerConfigId\",\n \"connectionName\",\n ]),\n )\n // Every start has required a name, so no stored row is expected to hold null.\n .alterTable(\"connectionRequest\", (t) => t.alterColumn(\"connectionName\").nullable(false))\n .alterTable(\"connectedAccount\", (t) => t.alterColumn(\"connectionName\").nullable(false)),\n);\n"],"mappings":";;;AAKA,MAAa,yBAAyB,OAAO,+BAA+B,MAC1E,EACG,SAAS,sBAAsB,MAC9B,EACG,UAAU,MAAM,SAAS,CAAC,CAAC,CAC3B,UAAU,aAAa,OAAO,QAAQ,CAAC,CAAC,CACxC,UAAU,oBAAoB,OAAO,QAAQ,CAAC,CAAC,CAC/C,UAAU,kBAAkB,OAAO,QAAQ,CAAC,CAAC,CAC7C,UAAU,WAAW,OAAO,QAAQ,CAAC,CAAC,CACtC,UAAU,kBAAkB,OAAO,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CACxD,UAAU,oBAAoB,OAAO,MAAM,CAAC,CAAC,CAC7C,UAAU,aAAa,OAAO,QAAQ,CAAC,CAAC,CACxC,UACC,SACA,OAAO,MAAM,CAKf,CACJ,CAAC,CACA,SAAS,qBAAqB,MAC7B,EACG,UAAU,MAAM,SAAS,CAAC,CAAC,CAC3B,UAAU,aAAa,OAAO,QAAQ,CAAC,CAAC,CACxC,UAAU,oBAAoB,OAAO,QAAQ,CAAC,CAAC,CAC/C,UAAU,kBAAkB,OAAO,QAAQ,CAAC,CAAC,CAC7C,UAAU,WAAW,OAAO,QAAQ,CAAC,CAAC,CACtC,UAAU,kBAAkB,OAAO,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,CACxD,YAAY,gCAAgC,CAAC,kBAAkB,IAAI,CAAC,CACzE,CAAC,CACA,WAAW,sBAAsB,MAChC,EAAE,YAAY,gCAAgC;CAC5C;CACA;CACA;CACA;AACF,CAAC,CACH,CAAC,CACA,WAAW,qBAAqB,MAC/B,EAAE,YAAY,gCAAgC;CAC5C;CACA;CACA;CACA;AACF,CAAC,CACH,CAAC,CAEA,WAAW,sBAAsB,MAAM,EAAE,YAAY,gBAAgB,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CACvF,WAAW,qBAAqB,MAAM,EAAE,YAAY,gBAAgB,CAAC,CAAC,SAAS,KAAK,CAAC,CAC1F"}
@@ -0,0 +1,170 @@
1
+ import { projectConnectorConnectInputSchema, projectConnectorNamedConnectionSchema } from "./project-connector-contracts.js";
2
+ import { ProjectConnectorClientConfig } from "./project-connector-client.js";
3
+ import { HookContext, HookFn } from "@fragno-dev/db";
4
+ import { z } from "zod";
5
+ //#region src/definition.d.ts
6
+ interface ProjectConnectorConnectionReadinessChangedPayload {
7
+ externalUserId: string;
8
+ /** Provider service of the named connection's configuration, e.g. gmail. */
9
+ service: string;
10
+ connection: z.output<typeof projectConnectorNamedConnectionSchema>;
11
+ /** Whether a confirmed account exists under this name. */
12
+ ready: boolean;
13
+ }
14
+ /** Integrators own authentication and restrict OAuth return URLs; project keys remain server-only. */
15
+ type ProjectConnectorFragmentConfig = ProjectConnectorClientConfig & {
16
+ getExternalUserId: (headers: Headers) => string | null | Promise<string | null>;
17
+ allowedReturnUrls: (url: URL) => boolean;
18
+ /**
19
+ * Fires when a write changes whether a named connection has a confirmed account: not ready when
20
+ * the first request for the name starts, ready when a refresh confirms its first account, and not
21
+ * ready for a name left without an account when a refresh moves its account ID to another name.
22
+ * The gateway does not report consent or revocation, so both are noticed only through refresh.
23
+ */
24
+ onConnectionReadinessChanged?: (payload: ProjectConnectorConnectionReadinessChangedPayload, context: HookContext) => Promise<void> | void;
25
+ };
26
+ type ProjectConnectorHooksMap = {
27
+ onConnectionReadinessChanged: HookFn<ProjectConnectorConnectionReadinessChangedPayload>;
28
+ };
29
+ /** OOMOL Project Connector dependencies and scoped account persistence. */
30
+ declare const projectConnectorFragmentDefinition: import("@fragno-dev/core").FragmentDefinition<ProjectConnectorFragmentConfig, import("@fragno-dev/db").FragnoPublicConfigWithDatabase, {
31
+ projectConnector: {
32
+ listProviderConfigs(): Promise<{
33
+ projectId: string;
34
+ providerConfigs: {
35
+ id: string;
36
+ service: string;
37
+ displayName: string;
38
+ callbackUrl: string;
39
+ effectiveScopes: string[];
40
+ proxyAvailable: boolean;
41
+ }[];
42
+ }>;
43
+ listProviderActions(providerConfigId: string): Promise<{
44
+ projectId: string;
45
+ providerConfigId: string;
46
+ actions: {
47
+ id: string;
48
+ service: string;
49
+ name: string;
50
+ description: string | null;
51
+ inputSchema: Record<string, unknown>;
52
+ outputSchema: Record<string, unknown>;
53
+ }[];
54
+ } | null>;
55
+ check(): Promise<{
56
+ authenticated: true;
57
+ }>;
58
+ connect(externalUserId: string, input: z.infer<typeof projectConnectorConnectInputSchema>): Promise<{
59
+ id: string;
60
+ projectId: string;
61
+ providerConfigId: string;
62
+ externalUserId: string;
63
+ service: string;
64
+ connectionName: string | null;
65
+ authorizationUrl: string;
66
+ expiresAt: string;
67
+ } & ({
68
+ status: "initiated";
69
+ } | {
70
+ status: "connected";
71
+ connectedAccountId: string;
72
+ } | {
73
+ status: "failed";
74
+ errorCode: string | null;
75
+ errorMessage: string | null;
76
+ } | {
77
+ status: "expired";
78
+ })>;
79
+ getConnectionRequest(requestId: string): Promise<{
80
+ id: string;
81
+ projectId: string;
82
+ providerConfigId: string;
83
+ externalUserId: string;
84
+ service: string;
85
+ connectionName: string | null;
86
+ authorizationUrl: string;
87
+ expiresAt: string;
88
+ } & ({
89
+ status: "initiated";
90
+ } | {
91
+ status: "connected";
92
+ connectedAccountId: string;
93
+ } | {
94
+ status: "failed";
95
+ errorCode: string | null;
96
+ errorMessage: string | null;
97
+ } | {
98
+ status: "expired";
99
+ })>;
100
+ getProfile(accountId: string): Promise<{
101
+ connectedAccountId: string;
102
+ externalUserId: string;
103
+ service: string;
104
+ profile: {
105
+ id: string;
106
+ kind: string;
107
+ username: string | null;
108
+ displayName: string | null;
109
+ avatarUrl: string | null;
110
+ email: string | null;
111
+ metadata: Record<string, unknown>;
112
+ };
113
+ fetchedAt: number;
114
+ }>;
115
+ execute(account: {
116
+ externalUserId: string;
117
+ providerConfigId: string;
118
+ id: string;
119
+ }, actionId: string, input: Record<string, unknown>): Promise<{
120
+ executionId: string;
121
+ actionId: string;
122
+ output: {} | null;
123
+ }>;
124
+ };
125
+ } & import("@fragno-dev/db").ImplicitDatabaseDependencies<import("@fragno-dev/db/schema").Schema<{
126
+ connectionRequest: import("@fragno-dev/db/schema").Table<{
127
+ id: import("@fragno-dev/db/schema").IdColumn<"varchar(128)", string | import("@fragno-dev/db/schema").FragnoId | null, import("@fragno-dev/db/schema").FragnoId>;
128
+ projectId: import("@fragno-dev/db/schema").Column<"string", string, string>;
129
+ providerConfigId: import("@fragno-dev/db/schema").Column<"string", string, string>;
130
+ externalUserId: import("@fragno-dev/db/schema").Column<"string", string, string>;
131
+ service: import("@fragno-dev/db/schema").Column<"string", string, string>;
132
+ authorizationUrl: import("@fragno-dev/db/schema").Column<"text", string, string>;
133
+ expiresAt: import("@fragno-dev/db/schema").Column<"string", string, string>;
134
+ state: import("@fragno-dev/db/schema").Column<"json", {
135
+ status: "initiated";
136
+ } | {
137
+ status: "connected";
138
+ connectedAccountId: string;
139
+ } | {
140
+ status: "failed";
141
+ errorCode: string | null;
142
+ errorMessage: string | null;
143
+ } | {
144
+ status: "expired";
145
+ }, {
146
+ status: "initiated";
147
+ } | {
148
+ status: "connected";
149
+ connectedAccountId: string;
150
+ } | {
151
+ status: "failed";
152
+ errorCode: string | null;
153
+ errorMessage: string | null;
154
+ } | {
155
+ status: "expired";
156
+ }>;
157
+ connectionName: import("@fragno-dev/db/schema").Column<"string", string, string>;
158
+ }, Record<"idx_request_named_connection", import("@fragno-dev/db/schema").Index<readonly [import("@fragno-dev/db/schema").Column<"string", string, string>, import("@fragno-dev/db/schema").Column<"string", string, string>, import("@fragno-dev/db/schema").Column<"string", string, string>, import("@fragno-dev/db/schema").Column<"string", string | null, string | null>] & import("@fragno-dev/db/schema").AnyColumn[], readonly ["externalUserId", "projectId", "providerConfigId", "connectionName"]>>>;
159
+ connectedAccount: import("@fragno-dev/db/schema").Table<{
160
+ id: import("@fragno-dev/db/schema").IdColumn<"varchar(128)", string | import("@fragno-dev/db/schema").FragnoId | null, import("@fragno-dev/db/schema").FragnoId>;
161
+ projectId: import("@fragno-dev/db/schema").Column<"string", string, string>;
162
+ providerConfigId: import("@fragno-dev/db/schema").Column<"string", string, string>;
163
+ externalUserId: import("@fragno-dev/db/schema").Column<"string", string, string>;
164
+ service: import("@fragno-dev/db/schema").Column<"string", string, string>;
165
+ connectionName: import("@fragno-dev/db/schema").Column<"string", string, string>;
166
+ }, Record<"idx_account_external_user_id", import("@fragno-dev/db/schema").Index<readonly [import("@fragno-dev/db/schema").Column<"string", string, string>, import("@fragno-dev/db/schema").IdColumn<"varchar(128)", string | import("@fragno-dev/db/schema").FragnoId | null, import("@fragno-dev/db/schema").FragnoId>] & import("@fragno-dev/db/schema").AnyColumn[], readonly ["externalUserId", "id"]>> & Record<"idx_account_named_connection", import("@fragno-dev/db/schema").Index<readonly [import("@fragno-dev/db/schema").Column<"string", string, string>, import("@fragno-dev/db/schema").Column<"string", string, string>, import("@fragno-dev/db/schema").Column<"string", string, string>, import("@fragno-dev/db/schema").Column<"string", string | null, string | null>] & import("@fragno-dev/db/schema").AnyColumn[], readonly ["externalUserId", "projectId", "providerConfigId", "connectionName"]>>>;
167
+ }>>, {}, {}, {}, {}, import("@fragno-dev/db").DatabaseServiceContext<ProjectConnectorHooksMap>, import("@fragno-dev/db").DatabaseRequestContext<ProjectConnectorHooksMap>, import("@fragno-dev/db/fragment-definition-builder").DatabaseRequestStorage, []>;
168
+ //#endregion
169
+ export { ProjectConnectorConnectionReadinessChangedPayload, ProjectConnectorFragmentConfig, projectConnectorFragmentDefinition };
170
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","names":[],"sources":["../../src/definition.ts"],"mappings":";;;;;UAYiB;EACf;;EAEA;EACA,YAAY,EAAE,cAAc;;EAE5B;;;KAIU,iCAAiC;EAC3C,oBAAoB,SAAS,4BAA4B;EACzD,oBAAoB,KAAK;;;;;;;EAOzB,gCACE,SAAS,mDACT,SAAS,gBACN;;KAGF;EACH,8BAA8B,OAAO;;;cAI1B,+DAAkC,mBAAA,yDAAA"}
@@ -0,0 +1,13 @@
1
+ import { createProjectConnectorClient } from "./project-connector-client.js";
2
+ import { projectConnectorSchema } from "./schema.js";
3
+ import { defineFragment } from "@fragno-dev/core";
4
+ import { withDatabase } from "@fragno-dev/db";
5
+ //#region src/definition.ts
6
+ /** OOMOL Project Connector dependencies and scoped account persistence. */
7
+ const projectConnectorFragmentDefinition = defineFragment("project-connector-fragment").extend(withDatabase(projectConnectorSchema)).withDependencies(({ config }) => ({ projectConnector: createProjectConnectorClient(config) })).provideHooks(({ defineHook, config }) => ({ onConnectionReadinessChanged: defineHook(async function(payload) {
8
+ await config.onConnectionReadinessChanged?.(payload, this);
9
+ }) })).build();
10
+ //#endregion
11
+ export { projectConnectorFragmentDefinition };
12
+
13
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.js","names":[],"sources":["../../src/definition.ts"],"sourcesContent":["import type { z } from \"zod\";\n\nimport { defineFragment } from \"@fragno-dev/core\";\nimport { withDatabase, type HookContext, type HookFn } from \"@fragno-dev/db\";\n\nimport {\n createProjectConnectorClient,\n type ProjectConnectorClientConfig,\n} from \"./project-connector-client\";\nimport type { projectConnectorNamedConnectionSchema } from \"./project-connector-contracts\";\nimport { projectConnectorSchema } from \"./schema\";\n\nexport interface ProjectConnectorConnectionReadinessChangedPayload {\n externalUserId: string;\n /** Provider service of the named connection's configuration, e.g. gmail. */\n service: string;\n connection: z.output<typeof projectConnectorNamedConnectionSchema>;\n /** Whether a confirmed account exists under this name. */\n ready: boolean;\n}\n\n/** Integrators own authentication and restrict OAuth return URLs; project keys remain server-only. */\nexport type ProjectConnectorFragmentConfig = ProjectConnectorClientConfig & {\n getExternalUserId: (headers: Headers) => string | null | Promise<string | null>;\n allowedReturnUrls: (url: URL) => boolean;\n /**\n * Fires when a write changes whether a named connection has a confirmed account: not ready when\n * the first request for the name starts, ready when a refresh confirms its first account, and not\n * ready for a name left without an account when a refresh moves its account ID to another name.\n * The gateway does not report consent or revocation, so both are noticed only through refresh.\n */\n onConnectionReadinessChanged?: (\n payload: ProjectConnectorConnectionReadinessChangedPayload,\n context: HookContext,\n ) => Promise<void> | void;\n};\n\ntype ProjectConnectorHooksMap = {\n onConnectionReadinessChanged: HookFn<ProjectConnectorConnectionReadinessChangedPayload>;\n};\n\n/** OOMOL Project Connector dependencies and scoped account persistence. */\nexport const projectConnectorFragmentDefinition = defineFragment<ProjectConnectorFragmentConfig>(\n \"project-connector-fragment\",\n)\n .extend(withDatabase(projectConnectorSchema))\n .withDependencies(({ config }) => ({\n projectConnector: createProjectConnectorClient(config),\n }))\n .provideHooks<ProjectConnectorHooksMap>(({ defineHook, config }) => ({\n onConnectionReadinessChanged: defineHook(async function (payload) {\n await config.onConnectionReadinessChanged?.(payload, this);\n }),\n }))\n .build();\n"],"mappings":";;;;;;AA0CA,MAAa,qCAAqC,eAChD,4BACF,CAAC,CACE,OAAO,aAAa,sBAAsB,CAAC,CAAC,CAC5C,kBAAkB,EAAE,cAAc,EACjC,kBAAkB,6BAA6B,MAAM,EACvD,EAAE,CAAC,CACF,cAAwC,EAAE,YAAY,cAAc,EACnE,8BAA8B,WAAW,eAAgB,SAAS;CAChE,MAAM,OAAO,+BAA+B,SAAS,IAAI;AAC3D,CAAC,EACH,EAAE,CAAC,CACF,MAAM"}