@emisso/sii-api 0.1.1 → 0.1.3
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/dist/adapters/next.cjs +58 -60
- package/dist/adapters/next.cjs.map +1 -1
- package/dist/adapters/next.js +2 -4
- package/dist/adapters/next.js.map +1 -1
- package/dist/index.cjs +58 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -6
- package/dist/index.d.ts +2 -6
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/db/schema/index.ts","../src/db/schema/credentials.ts","../src/db/schema/token-cache.ts","../src/db/schema/invoices.ts","../src/db/schema/sync-jobs.ts","../src/core/effect/app-error.ts","../src/core/effect/http-response.ts","../src/core/effect/repo-helpers.ts","../src/core/bridge.ts","../src/validation/schemas.ts","../src/repos/credential-repo.ts","../src/repos/token-cache-repo.ts","../src/repos/invoice-repo.ts","../src/repos/sync-job-repo.ts","../src/services/credential-service.ts","../src/services/auth-service.ts","../src/services/invoice-service.ts","../src/handlers/router.ts","../src/handlers/auth-handlers.ts","../src/handlers/handler-utils.ts","../src/handlers/invoice-handlers.ts"],"sourcesContent":["// ── Schema exports ──\nexport { siiSchema } from \"./db/schema/index.js\";\nexport * from \"./db/schema/index.js\";\n\n// ── Core ──\nexport {\n NotFoundError,\n ValidationError,\n ForbiddenError,\n DbError,\n ConflictError,\n SiiAuthError,\n isAppError,\n serializeAppError,\n type AppError,\n} from \"./core/effect/app-error.js\";\nexport {\n toErrorResponse,\n toErrorResponseFromUnknown,\n handleEffect,\n jsonResponse,\n createdResponse,\n noContentResponse,\n} from \"./core/effect/http-response.js\";\nexport { queryOneOrFail } from \"./core/effect/repo-helpers.js\";\nexport { invoiceToRow, rowToInvoice } from \"./core/bridge.js\";\n\n// ── Validation ──\nexport {\n SaveCredentialsSchema,\n SyncInvoicesSchema,\n ListInvoicesQuerySchema,\n SyncStatusQuerySchema,\n} from \"./validation/schemas.js\";\nexport type {\n SaveCredentialsInput,\n SyncInvoicesInput,\n ListInvoicesQuery,\n} from \"./validation/schemas.js\";\n\n// ── Repos ──\nexport { createCredentialRepo, type CredentialRepo } from \"./repos/credential-repo.js\";\nexport { createTokenCacheRepo, type TokenCacheRepo } from \"./repos/token-cache-repo.js\";\nexport { createInvoiceRepo, type InvoiceRepo } from \"./repos/invoice-repo.js\";\nexport { createSyncJobRepo, type SyncJobRepo } from \"./repos/sync-job-repo.js\";\n\n// ── Services ──\nexport { createCredentialService, type CredentialService } from \"./services/credential-service.js\";\nexport { createAuthService, type AuthService } from \"./services/auth-service.js\";\nexport { createInvoiceService, type InvoiceService } from \"./services/invoice-service.js\";\n\n// ── Handlers ──\nexport { createRouter, type Route, type HandlerFn, type HandlerContext } from \"./handlers/router.js\";\nexport { createAuthHandlers } from \"./handlers/auth-handlers.js\";\nexport { createInvoiceHandlers } from \"./handlers/invoice-handlers.js\";\n","/**\n * @emisso/sii-api — Drizzle schema exports\n * All tables live in the PostgreSQL `sii` schema.\n */\n\nimport { pgSchema } from \"drizzle-orm/pg-core\";\n\nexport const siiSchema = pgSchema(\"sii\");\n\nexport { credentials } from \"./credentials.js\";\nexport type { Credential, NewCredential } from \"./credentials.js\";\n\nexport { tokenCache } from \"./token-cache.js\";\nexport type { TokenCacheEntry, NewTokenCacheEntry } from \"./token-cache.js\";\n\nexport { invoices } from \"./invoices.js\";\nexport type { InvoiceRow, NewInvoiceRow } from \"./invoices.js\";\n\nexport { syncJobs } from \"./sync-jobs.js\";\nexport type { SyncJob, NewSyncJob, SyncJobStatus } from \"./sync-jobs.js\";\n","import {\n text,\n timestamp,\n unique,\n uuid,\n} from \"drizzle-orm/pg-core\";\nimport type { SiiEnv } from \"@emisso/sii\";\nimport { siiSchema } from \"./index.js\";\n\nexport const credentials = siiSchema.table(\n \"credentials\",\n {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n tenantId: uuid(\"tenant_id\").notNull(),\n // NOTE: `env` is typed as SiiEnv at the application layer via Drizzle's $type<>().\n // A DB-level CHECK constraint (env IN ('production','certification')) should be\n // added via a future migration to enforce this at the database level as well.\n env: text(\"env\").notNull().$type<SiiEnv>(),\n // TODO: ENCRYPT AT REST — these fields store sensitive SII credentials.\n // Must implement application-level encryption (AES-256-GCM) before production.\n certBase64: text(\"cert_base64\"),\n certPassword: text(\"cert_password\"),\n portalRut: text(\"portal_rut\"),\n // TODO: ENCRYPT AT REST — portal password stores sensitive SII credentials.\n // Must implement application-level encryption (AES-256-GCM) before production.\n portalPassword: text(\"portal_password\"),\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\").notNull().defaultNow(),\n },\n (table) => [unique(\"uq_credentials_tenant_env\").on(table.tenantId, table.env)],\n);\n\nexport type Credential = typeof credentials.$inferSelect;\nexport type NewCredential = typeof credentials.$inferInsert;\n","import {\n text,\n timestamp,\n unique,\n uuid,\n} from \"drizzle-orm/pg-core\";\nimport { siiSchema } from \"./index.js\";\nimport { credentials } from \"./credentials.js\";\n\nexport const tokenCache = siiSchema.table(\n \"token_cache\",\n {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n credentialId: uuid(\"credential_id\")\n .notNull()\n .references(() => credentials.id, { onDelete: \"cascade\" }),\n tokenType: text(\"token_type\").notNull().$type<\"soap\" | \"portal\">(),\n tokenValue: text(\"token_value\").notNull(),\n expiresAt: timestamp(\"expires_at\", { withTimezone: true }).notNull(),\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\n },\n (table) => [unique(\"uq_token_cache_cred_type\").on(table.credentialId, table.tokenType)],\n);\n\nexport type TokenCacheEntry = typeof tokenCache.$inferSelect;\nexport type NewTokenCacheEntry = typeof tokenCache.$inferInsert;\n","import {\n date,\n index,\n integer,\n jsonb,\n numeric,\n text,\n timestamp,\n unique,\n uuid,\n} from \"drizzle-orm/pg-core\";\nimport type { DteType, IssueType, ConfirmationStatus } from \"@emisso/sii\";\nimport { siiSchema } from \"./index.js\";\n\nexport const invoices = siiSchema.table(\n \"invoices\",\n {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n tenantId: uuid(\"tenant_id\").notNull(),\n documentType: text(\"document_type\").notNull().$type<DteType>(),\n number: integer(\"number\").notNull(),\n issuerRut: text(\"issuer_rut\"),\n issuerName: text(\"issuer_name\"),\n receiverRut: text(\"receiver_rut\"),\n receiverName: text(\"receiver_name\"),\n date: date(\"date\"),\n netAmount: numeric(\"net_amount\", { precision: 16, scale: 0 }),\n exemptAmount: numeric(\"exempt_amount\", { precision: 16, scale: 0 }),\n vatAmount: numeric(\"vat_amount\", { precision: 16, scale: 0 }),\n totalAmount: numeric(\"total_amount\", { precision: 16, scale: 0 }),\n taxPeriodYear: integer(\"tax_period_year\").notNull(),\n taxPeriodMonth: integer(\"tax_period_month\").notNull(),\n issueType: text(\"issue_type\").notNull().$type<IssueType>(),\n confirmationStatus: text(\"confirmation_status\").$type<ConfirmationStatus>(),\n raw: jsonb(\"raw\").$type<Record<string, string>>(),\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\").notNull().defaultNow(),\n },\n (table) => [\n unique(\"uq_invoices_natural_key\").on(\n table.tenantId,\n table.documentType,\n table.number,\n table.issuerRut,\n table.receiverRut,\n table.issueType,\n ),\n index(\"idx_invoices_tenant_period\").on(\n table.tenantId,\n table.taxPeriodYear,\n table.taxPeriodMonth,\n ),\n ],\n);\n\nexport type InvoiceRow = typeof invoices.$inferSelect;\nexport type NewInvoiceRow = typeof invoices.$inferInsert;\n","import {\n integer,\n text,\n timestamp,\n uuid,\n} from \"drizzle-orm/pg-core\";\nimport type { IssueType } from \"@emisso/sii\";\nimport { siiSchema } from \"./index.js\";\n\nexport type SyncJobStatus = \"pending\" | \"running\" | \"completed\" | \"failed\";\n\nexport const syncJobs = siiSchema.table(\"sync_jobs\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n tenantId: uuid(\"tenant_id\").notNull(),\n operation: text(\"operation\").notNull().$type<\"rcv_sync\">(),\n periodYear: integer(\"period_year\").notNull(),\n periodMonth: integer(\"period_month\").notNull(),\n issueType: text(\"issue_type\").notNull().$type<IssueType>(),\n status: text(\"status\").notNull().default(\"pending\").$type<SyncJobStatus>(),\n startedAt: timestamp(\"started_at\"),\n completedAt: timestamp(\"completed_at\"),\n recordsFetched: integer(\"records_fetched\"),\n errorMessage: text(\"error_message\"),\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\n});\n\nexport type SyncJob = typeof syncJobs.$inferSelect;\nexport type NewSyncJob = typeof syncJobs.$inferInsert;\n","/**\n * Application errors for Effect-based SII API logic.\n * Uses Data.TaggedError which automatically sets `_tag` as the discriminator.\n */\n\nimport { Data } from \"effect\";\n\n// ============================================================================\n// ERROR TYPES\n// ============================================================================\n\nexport class NotFoundError extends Data.TaggedError(\"NotFoundError\")<{\n readonly message: string;\n readonly entity?: string;\n readonly entityId?: string;\n}> {\n static make(entity: string, entityId?: string): NotFoundError {\n return new NotFoundError({\n message: `${entity} not found${entityId ? `: ${entityId}` : \"\"}`,\n entity,\n entityId,\n });\n }\n}\n\nexport class ValidationError extends Data.TaggedError(\"ValidationError\")<{\n readonly message: string;\n readonly field?: string;\n readonly details?: Record<string, unknown>;\n readonly fieldErrors?: Array<{ path: string; message: string }>;\n}> {\n static make(\n message: string,\n field?: string,\n details?: Record<string, unknown>,\n ): ValidationError {\n return new ValidationError({\n message,\n field,\n details,\n });\n }\n\n static fromZodErrors(\n message: string,\n issues: Array<{ path: (string | number)[]; message: string }>,\n ): ValidationError {\n return new ValidationError({\n message,\n fieldErrors: issues.map((i) => ({\n path: i.path.join(\".\"),\n message: i.message,\n })),\n });\n }\n}\n\nexport class ForbiddenError extends Data.TaggedError(\"ForbiddenError\")<{\n readonly message: string;\n readonly requiredPermission?: string;\n}> {\n static make(\n message: string = \"Forbidden\",\n requiredPermission?: string,\n ): ForbiddenError {\n return new ForbiddenError({\n message,\n requiredPermission,\n });\n }\n}\n\nexport class DbError extends Data.TaggedError(\"DbError\")<{\n readonly message: string;\n readonly operation?: string;\n readonly cause?: unknown;\n}> {\n static make(operation: string, cause?: unknown): DbError {\n const message =\n cause instanceof Error ? cause.message : \"Database operation failed\";\n return new DbError({\n message,\n operation,\n cause,\n });\n }\n}\n\nexport class ConflictError extends Data.TaggedError(\"ConflictError\")<{\n readonly message: string;\n readonly resource?: string;\n readonly conflictingValue?: string;\n}> {\n static make(\n message: string,\n resource?: string,\n conflictingValue?: string,\n ): ConflictError {\n return new ConflictError({\n message,\n resource,\n conflictingValue,\n });\n }\n}\n\nexport class SiiAuthError extends Data.TaggedError(\"SiiAuthError\")<{\n readonly message: string;\n readonly cause?: unknown;\n}> {\n static make(message: string, cause?: unknown): SiiAuthError {\n return new SiiAuthError({\n message,\n cause,\n });\n }\n}\n\n// ============================================================================\n// UNION TYPE\n// ============================================================================\n\nexport type AppError =\n | NotFoundError\n | ValidationError\n | ForbiddenError\n | DbError\n | ConflictError\n | SiiAuthError;\n\n// ============================================================================\n// TYPE GUARDS\n// ============================================================================\n\nexport function isAppError(error: unknown): error is AppError {\n return (\n error instanceof NotFoundError ||\n error instanceof ValidationError ||\n error instanceof ForbiddenError ||\n error instanceof DbError ||\n error instanceof ConflictError ||\n error instanceof SiiAuthError\n );\n}\n\n// ============================================================================\n// SERIALIZATION\n// ============================================================================\n\nexport function serializeAppError(error: AppError): {\n _type: string;\n message: string;\n [key: string]: unknown;\n} {\n const result: Record<string, unknown> = {\n _type: error._tag,\n message: error.message,\n };\n\n switch (error._tag) {\n case \"NotFoundError\":\n if (error.entity) result.entity = error.entity;\n if (error.entityId) result.entityId = error.entityId;\n break;\n case \"ValidationError\":\n if (error.field) result.field = error.field;\n if (error.details) result.details = error.details;\n if (error.fieldErrors) result.fieldErrors = error.fieldErrors;\n break;\n case \"ForbiddenError\":\n if (error.requiredPermission)\n result.requiredPermission = error.requiredPermission;\n break;\n case \"DbError\":\n if (error.operation) result.operation = error.operation;\n break;\n case \"ConflictError\":\n if (error.resource) result.resource = error.resource;\n if (error.conflictingValue)\n result.conflictingValue = error.conflictingValue;\n break;\n case \"SiiAuthError\":\n break;\n default: {\n const _exhaustive: never = error;\n return result as any;\n }\n }\n\n return result as { _type: string; message: string; [key: string]: unknown };\n}\n","/**\n * Framework-agnostic HTTP response helpers using Web API Response.\n * No dependency on Next.js or any framework.\n */\n\nimport { Effect } from \"effect\";\nimport type { AppError } from \"./app-error.js\";\nimport { isAppError, serializeAppError } from \"./app-error.js\";\n\n// ============================================================================\n// STATUS CODE MAPPING\n// ============================================================================\n\nconst STATUS_MAP: Record<AppError[\"_tag\"], number> = {\n ValidationError: 400,\n ForbiddenError: 403,\n NotFoundError: 404,\n ConflictError: 409,\n SiiAuthError: 502,\n DbError: 500,\n};\n\n// ============================================================================\n// ERROR RESPONSES\n// ============================================================================\n\nexport function toErrorResponse(error: AppError): Response {\n const status = STATUS_MAP[error._tag] ?? 500;\n const body = serializeAppError(error);\n return Response.json({ error: body }, { status });\n}\n\n/**\n * Extracts an AppError from an unknown error, handling Effect's FiberFailure wrapping.\n */\nfunction extractAppError(error: unknown): AppError | null {\n if (isAppError(error)) return error;\n // Handle Effect's FiberFailure — access cause.error\n const cause = (error as any)?.cause;\n if (cause) {\n const inner = cause?.error;\n if (isAppError(inner)) return inner;\n }\n return null;\n}\n\nexport function toErrorResponseFromUnknown(error: unknown): Response {\n const appError = extractAppError(error);\n if (appError) return toErrorResponse(appError);\n console.error(\"[sii-api] Unhandled error:\", error);\n return Response.json(\n { error: { _type: \"InternalError\", message: \"Internal server error\" } },\n { status: 500 },\n );\n}\n\n// ============================================================================\n// EFFECT HANDLER\n// ============================================================================\n\n/**\n * Run an Effect at the handler boundary, converting errors to HTTP responses.\n */\nexport function handleEffect<T>(\n effect: Effect.Effect<T, AppError>,\n toResponse: (data: T) => Response = jsonResponse,\n): Promise<Response> {\n return Effect.runPromise(\n effect.pipe(\n Effect.map(toResponse),\n Effect.catchAll((err) => Effect.succeed(toErrorResponse(err))),\n ),\n );\n}\n\n// ============================================================================\n// SUCCESS RESPONSES\n// ============================================================================\n\nexport function jsonResponse<T>(data: T, status: number = 200): Response {\n return Response.json(data, { status });\n}\n\nexport function createdResponse<T>(data: T): Response {\n return Response.json(data, { status: 201 });\n}\n\nexport function noContentResponse(): Response {\n return new Response(null, { status: 204 });\n}\n","import { Effect } from \"effect\";\nimport { DbError, NotFoundError } from \"./app-error.js\";\n\n/**\n * Query a single row and fail with NotFoundError if not found.\n */\nexport function queryOneOrFail<T>(\n operation: string,\n entity: string,\n entityId: string,\n query: () => Promise<T | undefined>,\n): Effect.Effect<T, DbError | NotFoundError> {\n return Effect.tryPromise({\n try: query,\n catch: (e) => DbError.make(operation, e),\n }).pipe(\n Effect.flatMap((row) =>\n row\n ? Effect.succeed(row)\n : Effect.fail(NotFoundError.make(entity, entityId)),\n ),\n );\n}\n","/**\n * Converts between DB rows and engine Invoice type.\n */\n\nimport type { Invoice, IssueType } from \"@emisso/sii\";\nimport type { InvoiceRow, NewInvoiceRow } from \"../db/schema/index.js\";\n\n/**\n * Convert an engine Invoice to a DB row for upsert.\n */\nexport function invoiceToRow(\n tenantId: string,\n invoice: Invoice,\n issueType: IssueType,\n): Omit<NewInvoiceRow, \"id\" | \"createdAt\" | \"updatedAt\"> {\n return {\n tenantId,\n documentType: invoice.documentType,\n number: invoice.number,\n issuerRut: invoice.issuer.rut || null,\n issuerName: invoice.issuer.name || null,\n receiverRut: invoice.receiver.rut || null,\n receiverName: invoice.receiver.name || null,\n date: invoice.date || null,\n netAmount: String(invoice.netAmount),\n exemptAmount: String(invoice.exemptAmount),\n vatAmount: String(invoice.vatAmount),\n totalAmount: String(invoice.totalAmount),\n taxPeriodYear: invoice.taxPeriod.year,\n taxPeriodMonth: invoice.taxPeriod.month,\n issueType,\n confirmationStatus: invoice.confirmationStatus ?? null,\n raw: invoice.raw ?? null,\n };\n}\n\n/**\n * Convert a DB row back to an engine-compatible Invoice.\n */\nexport function rowToInvoice(row: InvoiceRow): Invoice {\n return {\n id: `${row.documentType}-${row.number}-${row.issuerRut || row.receiverRut || \"\"}`,\n number: row.number,\n issuer: {\n rut: row.issuerRut ?? \"\",\n name: row.issuerName ?? \"\",\n },\n receiver: {\n rut: row.receiverRut ?? \"\",\n name: row.receiverName ?? \"\",\n },\n date: row.date ?? \"\",\n netAmount: Number(row.netAmount ?? 0),\n exemptAmount: Number(row.exemptAmount ?? 0),\n vatAmount: Number(row.vatAmount ?? 0),\n totalAmount: Number(row.totalAmount ?? 0),\n currency: \"CLP\",\n taxPeriod: {\n year: row.taxPeriodYear,\n month: row.taxPeriodMonth,\n },\n documentType: row.documentType,\n confirmationStatus: row.confirmationStatus ?? \"REGISTRO\",\n raw: row.raw ?? {},\n };\n}\n","/**\n * Zod validation schemas for HTTP inputs.\n */\n\nimport { z } from \"zod\";\nimport { SiiEnvSchema, IssueTypeSchema, DteTypeSchema } from \"@emisso/sii\";\n\n// ── Credentials ──\n\nexport const SaveCredentialsSchema = z\n .object({\n env: SiiEnvSchema.default(\"production\"),\n certBase64: z.string().optional(),\n certPassword: z.string().optional(),\n portalRut: z.string().optional(),\n portalPassword: z.string().optional(),\n })\n .refine(\n (d) => (d.certBase64 || d.certPassword) || (d.portalRut || d.portalPassword),\n { message: \"At least one credential pair is required: certificate (certBase64 + certPassword) or portal (portalRut + portalPassword)\" },\n )\n .refine(\n (d) => (!d.certBase64 && !d.certPassword) || (d.certBase64 && d.certPassword),\n { message: \"certBase64 and certPassword must both be provided or both omitted\" },\n )\n .refine(\n (d) => (!d.portalRut && !d.portalPassword) || (d.portalRut && d.portalPassword),\n { message: \"portalRut and portalPassword must both be provided or both omitted\" },\n );\nexport type SaveCredentialsInput = z.infer<typeof SaveCredentialsSchema>;\n\n// ── Invoice sync ──\n\nexport const SyncInvoicesSchema = z.object({\n period: z.string().regex(/^\\d{4}-\\d{2}$/, \"Period must be YYYY-MM format\"),\n type: IssueTypeSchema.default(\"received\"),\n});\nexport type SyncInvoicesInput = z.infer<typeof SyncInvoicesSchema>;\n\n// ── Invoice list query ──\n\nexport const ListInvoicesQuerySchema = z.object({\n period: z.string().regex(/^\\d{4}-\\d{2}$/).optional(),\n type: IssueTypeSchema.optional(),\n documentType: DteTypeSchema.optional(),\n limit: z.coerce.number().int().positive().max(1000).default(100),\n offset: z.coerce.number().int().nonnegative().default(0),\n});\n\n// ── Sync status query ──\n\nexport const SyncStatusQuerySchema = z.object({\n period: z.string().regex(/^\\d{4}-\\d{2}$/).optional(),\n type: IssueTypeSchema.optional(),\n});\nexport type ListInvoicesQuery = z.infer<typeof ListInvoicesQuerySchema>;\n","import { Effect } from \"effect\";\nimport { and, eq } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport type { SiiEnv } from \"@emisso/sii\";\nimport { credentials, type Credential, type NewCredential } from \"../db/schema/index.js\";\nimport { DbError, NotFoundError } from \"../core/effect/app-error.js\";\nimport { queryOneOrFail } from \"../core/effect/repo-helpers.js\";\n\nexport function createCredentialRepo(db: PgDatabase<any>) {\n return {\n getByTenantAndEnv(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<Credential, DbError | NotFoundError> {\n return queryOneOrFail(\n \"credential.getByTenantAndEnv\",\n \"Credential\",\n `${tenantId}/${env}`,\n () =>\n db\n .select()\n .from(credentials)\n .where(\n and(\n eq(credentials.tenantId, tenantId),\n eq(credentials.env, env),\n ),\n )\n .then((rows) => rows[0]),\n );\n },\n\n upsert(\n tenantId: string,\n data: Omit<NewCredential, \"id\" | \"tenantId\" | \"createdAt\" | \"updatedAt\">,\n ): Effect.Effect<Credential, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .insert(credentials)\n .values({ ...data, tenantId })\n .onConflictDoUpdate({\n target: [credentials.tenantId, credentials.env],\n set: { ...data, updatedAt: new Date() },\n })\n .returning()\n .then((rows) => rows[0]!),\n catch: (e) => DbError.make(\"credential.upsert\", e),\n });\n },\n\n delete(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<boolean, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .delete(credentials)\n .where(\n and(\n eq(credentials.tenantId, tenantId),\n eq(credentials.env, env),\n ),\n )\n .returning()\n .then((rows) => rows.length > 0),\n catch: (e) => DbError.make(\"credential.delete\", e),\n });\n },\n };\n}\n\nexport type CredentialRepo = ReturnType<typeof createCredentialRepo>;\n","import { Effect } from \"effect\";\nimport { and, eq } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport { tokenCache, type TokenCacheEntry } from \"../db/schema/index.js\";\nimport { DbError } from \"../core/effect/app-error.js\";\n\nexport function createTokenCacheRepo(db: PgDatabase<any>) {\n return {\n get(\n credentialId: string,\n tokenType: \"soap\" | \"portal\",\n ): Effect.Effect<TokenCacheEntry | null, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .select()\n .from(tokenCache)\n .where(\n and(\n eq(tokenCache.credentialId, credentialId),\n eq(tokenCache.tokenType, tokenType),\n ),\n )\n .then((rows) => rows[0] ?? null),\n catch: (e) => DbError.make(\"tokenCache.get\", e),\n });\n },\n\n upsert(\n credentialId: string,\n tokenType: \"soap\" | \"portal\",\n tokenValue: string,\n expiresAt: Date,\n ): Effect.Effect<TokenCacheEntry, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .insert(tokenCache)\n .values({ credentialId, tokenType, tokenValue, expiresAt })\n .onConflictDoUpdate({\n target: [tokenCache.credentialId, tokenCache.tokenType],\n set: { tokenValue, expiresAt, createdAt: new Date() },\n })\n .returning()\n .then((rows) => rows[0]!),\n catch: (e) => DbError.make(\"tokenCache.upsert\", e),\n });\n },\n\n deleteByCredential(credentialId: string): Effect.Effect<void, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .delete(tokenCache)\n .where(eq(tokenCache.credentialId, credentialId))\n .then(() => undefined),\n catch: (e) => DbError.make(\"tokenCache.deleteByCredential\", e),\n });\n },\n };\n}\n\nexport type TokenCacheRepo = ReturnType<typeof createTokenCacheRepo>;\n","import { Effect } from \"effect\";\nimport { and, eq, sql } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport type { IssueType, DteType } from \"@emisso/sii\";\nimport { invoices, type InvoiceRow, type NewInvoiceRow } from \"../db/schema/index.js\";\nimport { DbError } from \"../core/effect/app-error.js\";\n\nexport function createInvoiceRepo(db: PgDatabase<any>) {\n return {\n list(\n tenantId: string,\n filters?: {\n periodYear?: number;\n periodMonth?: number;\n issueType?: IssueType;\n documentType?: DteType;\n limit?: number;\n offset?: number;\n },\n ): Effect.Effect<InvoiceRow[], DbError> {\n return Effect.tryPromise({\n try: () => {\n const conditions = [eq(invoices.tenantId, tenantId)];\n if (filters?.periodYear !== undefined) {\n conditions.push(eq(invoices.taxPeriodYear, filters.periodYear));\n }\n if (filters?.periodMonth !== undefined) {\n conditions.push(eq(invoices.taxPeriodMonth, filters.periodMonth));\n }\n if (filters?.issueType) {\n conditions.push(eq(invoices.issueType, filters.issueType));\n }\n if (filters?.documentType) {\n conditions.push(eq(invoices.documentType, filters.documentType));\n }\n return db\n .select()\n .from(invoices)\n .where(and(...conditions))\n .limit(filters?.limit ?? 100)\n .offset(filters?.offset ?? 0);\n },\n catch: (e) => DbError.make(\"invoice.list\", e),\n });\n },\n\n upsertMany(\n rows: Omit<NewInvoiceRow, \"id\" | \"createdAt\" | \"updatedAt\">[],\n ): Effect.Effect<number, DbError> {\n if (rows.length === 0) return Effect.succeed(0);\n return Effect.tryPromise({\n try: () =>\n db\n .insert(invoices)\n .values(rows)\n .onConflictDoUpdate({\n target: [\n invoices.tenantId,\n invoices.documentType,\n invoices.number,\n invoices.issuerRut,\n invoices.receiverRut,\n invoices.issueType,\n ],\n set: {\n issuerName: sql`excluded.issuer_name`,\n receiverName: sql`excluded.receiver_name`,\n date: sql`excluded.date`,\n netAmount: sql`excluded.net_amount`,\n exemptAmount: sql`excluded.exempt_amount`,\n vatAmount: sql`excluded.vat_amount`,\n totalAmount: sql`excluded.total_amount`,\n confirmationStatus: sql`excluded.confirmation_status`,\n raw: sql`excluded.raw`,\n updatedAt: new Date(),\n },\n })\n .returning({ id: invoices.id })\n .then((rows) => rows.length),\n catch: (e) => DbError.make(\"invoice.upsertMany\", e),\n });\n },\n\n count(\n tenantId: string,\n filters?: {\n periodYear?: number;\n periodMonth?: number;\n issueType?: IssueType;\n },\n ): Effect.Effect<number, DbError> {\n return Effect.tryPromise({\n try: () => {\n const conditions = [eq(invoices.tenantId, tenantId)];\n if (filters?.periodYear !== undefined) {\n conditions.push(eq(invoices.taxPeriodYear, filters.periodYear));\n }\n if (filters?.periodMonth !== undefined) {\n conditions.push(eq(invoices.taxPeriodMonth, filters.periodMonth));\n }\n if (filters?.issueType) {\n conditions.push(eq(invoices.issueType, filters.issueType));\n }\n return db\n .select({ count: sql<number>`count(*)::int` })\n .from(invoices)\n .where(and(...conditions))\n .then((rows) => rows[0]?.count ?? 0);\n },\n catch: (e) => DbError.make(\"invoice.count\", e),\n });\n },\n };\n}\n\nexport type InvoiceRepo = ReturnType<typeof createInvoiceRepo>;\n","import { Effect } from \"effect\";\nimport { and, eq, desc } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport type { IssueType } from \"@emisso/sii\";\nimport { syncJobs, type SyncJob, type NewSyncJob } from \"../db/schema/index.js\";\nimport { DbError, NotFoundError } from \"../core/effect/app-error.js\";\nimport { queryOneOrFail } from \"../core/effect/repo-helpers.js\";\n\nexport function createSyncJobRepo(db: PgDatabase<any>) {\n return {\n create(\n data: Omit<NewSyncJob, \"id\" | \"createdAt\">,\n ): Effect.Effect<SyncJob, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .insert(syncJobs)\n .values(data)\n .returning()\n .then((rows) => rows[0]!),\n catch: (e) => DbError.make(\"syncJob.create\", e),\n });\n },\n\n getById(id: string): Effect.Effect<SyncJob, DbError | NotFoundError> {\n return queryOneOrFail(\n \"syncJob.getById\",\n \"SyncJob\",\n id,\n () =>\n db\n .select()\n .from(syncJobs)\n .where(eq(syncJobs.id, id))\n .then((rows) => rows[0]),\n );\n },\n\n listByTenant(\n tenantId: string,\n filters?: {\n periodYear?: number;\n periodMonth?: number;\n issueType?: IssueType;\n },\n ): Effect.Effect<SyncJob[], DbError> {\n return Effect.tryPromise({\n try: () => {\n const conditions = [eq(syncJobs.tenantId, tenantId)];\n if (filters?.periodYear !== undefined) {\n conditions.push(eq(syncJobs.periodYear, filters.periodYear));\n }\n if (filters?.periodMonth !== undefined) {\n conditions.push(eq(syncJobs.periodMonth, filters.periodMonth));\n }\n if (filters?.issueType) {\n conditions.push(eq(syncJobs.issueType, filters.issueType));\n }\n return db\n .select()\n .from(syncJobs)\n .where(and(...conditions))\n .orderBy(desc(syncJobs.createdAt))\n .limit(20);\n },\n catch: (e) => DbError.make(\"syncJob.listByTenant\", e),\n });\n },\n\n update(\n id: string,\n data: Partial<Pick<SyncJob, \"status\" | \"startedAt\" | \"completedAt\" | \"recordsFetched\" | \"errorMessage\">>,\n ): Effect.Effect<SyncJob, DbError | NotFoundError> {\n return queryOneOrFail(\n \"syncJob.update\",\n \"SyncJob\",\n id,\n () =>\n db\n .update(syncJobs)\n .set(data)\n .where(eq(syncJobs.id, id))\n .returning()\n .then((rows) => rows[0]),\n );\n },\n };\n}\n\nexport type SyncJobRepo = ReturnType<typeof createSyncJobRepo>;\n","import { Effect } from \"effect\";\nimport type { SiiEnv } from \"@emisso/sii\";\nimport type { CredentialRepo } from \"../repos/credential-repo.js\";\nimport type { TokenCacheRepo } from \"../repos/token-cache-repo.js\";\nimport type { Credential } from \"../db/schema/index.js\";\nimport type { SaveCredentialsInput } from \"../validation/schemas.js\";\nimport { NotFoundError, type AppError } from \"../core/effect/app-error.js\";\n\nexport function createCredentialService(deps: {\n credentialRepo: CredentialRepo;\n tokenCacheRepo: TokenCacheRepo;\n encrypt?: (plaintext: string) => string;\n decrypt?: (ciphertext: string) => string;\n}) {\n const { credentialRepo, tokenCacheRepo } = deps;\n const enc = (v: string | null | undefined) =>\n v && deps.encrypt ? deps.encrypt(v) : v;\n const dec = (v: string | null) =>\n v && deps.decrypt ? deps.decrypt(v) : v;\n\n return {\n save(\n tenantId: string,\n input: SaveCredentialsInput,\n ): Effect.Effect<Credential, AppError> {\n return credentialRepo.upsert(tenantId, {\n env: input.env,\n certBase64: enc(input.certBase64) ?? null,\n certPassword: enc(input.certPassword) ?? null,\n portalRut: input.portalRut ?? null,\n portalPassword: enc(input.portalPassword) ?? null,\n });\n },\n\n getStatus(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<{\n connected: boolean;\n env: string;\n hasCert: boolean;\n hasPortal: boolean;\n portalRut: string | null;\n }, AppError> {\n return credentialRepo.getByTenantAndEnv(tenantId, env).pipe(\n Effect.map((cred) => ({\n connected: true,\n env: cred.env,\n hasCert: !!cred.certBase64,\n hasPortal: !!cred.portalRut && !!cred.portalPassword,\n portalRut: cred.portalRut,\n })),\n Effect.catchTag(\"NotFoundError\", () =>\n Effect.succeed({\n connected: false,\n env,\n hasCert: false,\n hasPortal: false,\n portalRut: null,\n }),\n ),\n );\n },\n\n disconnect(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<void, AppError> {\n return Effect.gen(function* () {\n // Get credential to clean up token cache\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n\n // Token cache cascades on delete, but explicit cleanup is clearer\n yield* tokenCacheRepo.deleteByCredential(cred.id);\n yield* credentialRepo.delete(tenantId, env);\n });\n },\n };\n}\n\nexport type CredentialService = ReturnType<typeof createCredentialService>;\n","import { Effect } from \"effect\";\nimport {\n loadCertFromBase64,\n getSeed,\n signSeedFromCertData,\n getToken,\n portalLogin,\n type SiiToken,\n type PortalSession,\n type PortalLoginOptions,\n type SiiEnv,\n} from \"@emisso/sii\";\nimport type { CredentialRepo } from \"../repos/credential-repo.js\";\nimport type { TokenCacheRepo } from \"../repos/token-cache-repo.js\";\nimport { SiiAuthError, type AppError } from \"../core/effect/app-error.js\";\n\nfunction toMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Authenticate with SII SOAP using base64 certificate data.\n */\nasync function authenticateSoap(\n certBase64: string,\n certPassword: string,\n env: SiiEnv,\n): Promise<SiiToken> {\n const certData = loadCertFromBase64(certBase64, certPassword);\n // certPath and certPassword are required by SiiConfig but unused by getSeed/getToken,\n // which only need `env` to resolve the SOAP endpoint URL. We pass empty strings\n // because authentication is handled via the in-memory certData / signedSeed flow.\n const seed = await getSeed({ certPath: \"\", certPassword: \"\", env });\n const signedSeed = signSeedFromCertData(seed, certData);\n return getToken(signedSeed, { certPath: \"\", certPassword: \"\", env });\n}\n\nexport function createAuthService(deps: {\n credentialRepo: CredentialRepo;\n tokenCacheRepo: TokenCacheRepo;\n decrypt?: (ciphertext: string) => string;\n connectBrowser?: PortalLoginOptions[\"connectBrowser\"];\n}) {\n const { credentialRepo, tokenCacheRepo } = deps;\n const dec = (v: string) => (deps.decrypt ? deps.decrypt(v) : v);\n\n return {\n /**\n * Get a valid SOAP token, using cache if available.\n */\n getSoapToken(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<SiiToken, AppError> {\n return Effect.gen(function* () {\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n\n if (!cred.certBase64 || !cred.certPassword) {\n return yield* Effect.fail(\n SiiAuthError.make(\"No certificate configured for SOAP authentication\"),\n );\n }\n\n // Check cache\n const cached = yield* tokenCacheRepo.get(cred.id, \"soap\");\n if (cached && new Date(cached.expiresAt).getTime() > Date.now()) {\n return { token: cached.tokenValue, expiresAt: new Date(cached.expiresAt) };\n }\n\n // Authenticate with SII (decrypt credentials before use)\n const siiToken = yield* Effect.tryPromise({\n try: () => authenticateSoap(dec(cred.certBase64!), dec(cred.certPassword!), env),\n catch: (e) =>\n SiiAuthError.make(`SOAP authentication failed: ${toMessage(e)}`, e),\n });\n\n // Cache the token\n yield* tokenCacheRepo.upsert(\n cred.id,\n \"soap\",\n siiToken.token,\n siiToken.expiresAt,\n );\n\n return siiToken;\n });\n },\n\n /**\n * Get a portal session via fresh login.\n */\n getPortalSession(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<PortalSession, AppError> {\n return Effect.gen(function* () {\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n\n if (!cred.portalRut || !cred.portalPassword) {\n return yield* Effect.fail(\n SiiAuthError.make(\"No portal credentials configured\"),\n );\n }\n\n // Login to portal (decrypt credentials before use)\n const session = yield* Effect.tryPromise({\n try: () =>\n portalLogin(\n { rut: cred.portalRut!, claveTributaria: dec(cred.portalPassword!), env },\n { connectBrowser: deps.connectBrowser },\n ),\n catch: (e) =>\n SiiAuthError.make(`Portal login failed: ${toMessage(e)}`, e),\n });\n\n return session;\n });\n },\n\n /**\n * Test credentials by attempting authentication.\n * Runs SOAP and portal tests concurrently.\n */\n testConnection(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<{ soap: boolean; portal: boolean; errors: string[] }, AppError> {\n return Effect.gen(function* () {\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n const errors: string[] = [];\n\n // Build test effects\n const soapTest = cred.certBase64 && cred.certPassword\n ? Effect.tryPromise({\n try: () => authenticateSoap(dec(cred.certBase64!), dec(cred.certPassword!), env).then(() => true),\n catch: (e) => toMessage(e),\n }).pipe(Effect.catchAll((msg) => {\n errors.push(`SOAP: ${msg}`);\n return Effect.succeed(false);\n }))\n : Effect.sync(() => {\n errors.push(\"SOAP: No certificate configured\");\n return false;\n });\n\n const portalTest = cred.portalRut && cred.portalPassword\n ? Effect.tryPromise({\n try: () =>\n portalLogin(\n { rut: cred.portalRut!, claveTributaria: dec(cred.portalPassword!), env },\n { connectBrowser: deps.connectBrowser },\n ).then(() => true),\n catch: (e) => toMessage(e),\n }).pipe(Effect.catchAll((msg) => {\n errors.push(`Portal: ${msg}`);\n return Effect.succeed(false);\n }))\n : Effect.sync(() => {\n errors.push(\"Portal: No portal credentials configured\");\n return false;\n });\n\n // Run both tests concurrently\n const [soapOk, portalOk] = yield* Effect.all(\n [soapTest, portalTest],\n { concurrency: 2 },\n );\n\n return { soap: soapOk, portal: portalOk, errors };\n });\n },\n };\n}\n\nexport type AuthService = ReturnType<typeof createAuthService>;\n","import { Effect } from \"effect\";\nimport { listInvoices, type IssueType, type SiiEnv } from \"@emisso/sii\";\nimport type { InvoiceRepo } from \"../repos/invoice-repo.js\";\nimport type { SyncJobRepo } from \"../repos/sync-job-repo.js\";\nimport type { AuthService } from \"./auth-service.js\";\nimport type { CredentialRepo } from \"../repos/credential-repo.js\";\nimport type { SyncJob } from \"../db/schema/index.js\";\nimport { invoiceToRow } from \"../core/bridge.js\";\nimport { SiiAuthError, type AppError } from \"../core/effect/app-error.js\";\n\nexport function createInvoiceService(deps: {\n invoiceRepo: InvoiceRepo;\n syncJobRepo: SyncJobRepo;\n authService: AuthService;\n credentialRepo: CredentialRepo;\n}) {\n const { invoiceRepo, syncJobRepo, authService, credentialRepo } = deps;\n\n return {\n /**\n * Trigger an RCV invoice sync for a given period.\n * Creates a sync job, fetches from SII, upserts into DB.\n */\n sync(\n tenantId: string,\n env: SiiEnv,\n periodYear: number,\n periodMonth: number,\n issueType: IssueType,\n ): Effect.Effect<SyncJob, AppError> {\n return Effect.gen(function* () {\n // Create sync job\n const job = yield* syncJobRepo.create({\n tenantId,\n operation: \"rcv_sync\",\n periodYear,\n periodMonth,\n issueType,\n status: \"running\",\n startedAt: new Date(),\n });\n\n /** Mark job as failed and re-raise the error */\n const failJob = (err: AppError) =>\n syncJobRepo.update(job.id, {\n status: \"failed\",\n completedAt: new Date(),\n errorMessage: err.message,\n }).pipe(Effect.flatMap(() => Effect.fail(err)));\n\n // Get credential to find the RUT\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n if (!cred.portalRut) {\n const err = SiiAuthError.make(\"No portal RUT configured for RCV sync\");\n return yield* failJob(err);\n }\n\n // Get portal session\n const session = yield* authService\n .getPortalSession(tenantId, env)\n .pipe(Effect.catchAll(failJob));\n\n // Fetch invoices from SII\n const siiInvoices = yield* Effect.tryPromise({\n try: () =>\n listInvoices(session, {\n rut: cred.portalRut!,\n issueType,\n period: { year: periodYear, month: periodMonth },\n }),\n catch: (e) =>\n SiiAuthError.make(\n `RCV fetch failed: ${e instanceof Error ? e.message : String(e)}`,\n e,\n ),\n }).pipe(Effect.catchAll(failJob));\n\n // Convert and upsert\n const rows = siiInvoices.map((inv) =>\n invoiceToRow(tenantId, inv, issueType),\n );\n const count = yield* invoiceRepo.upsertMany(rows);\n\n // Complete the job\n return yield* syncJobRepo.update(job.id, {\n status: \"completed\",\n completedAt: new Date(),\n recordsFetched: count,\n });\n });\n },\n };\n}\n\nexport type InvoiceService = ReturnType<typeof createInvoiceService>;\n","/**\n * Simple pattern-matching router for framework-agnostic handlers.\n * Supports `:param` patterns for URL parameters.\n */\n\nexport interface HandlerContext {\n tenantId: string;\n params: Record<string, string>;\n}\n\nexport type HandlerFn = (req: Request, ctx: HandlerContext) => Promise<Response>;\n\nexport interface Route {\n method: string;\n pattern: string;\n handler: HandlerFn;\n}\n\ninterface CompiledRoute {\n method: string;\n regex: RegExp;\n paramNames: string[];\n handler: HandlerFn;\n}\n\nfunction compilePattern(pattern: string): {\n regex: RegExp;\n paramNames: string[];\n} {\n const paramNames: string[] = [];\n const regexStr = pattern\n .split(\"/\")\n .map((segment) => {\n if (segment.startsWith(\":\")) {\n paramNames.push(segment.slice(1));\n return \"([^/]+)\";\n }\n return segment;\n })\n .join(\"/\");\n return { regex: new RegExp(`^${regexStr}$`), paramNames };\n}\n\nexport function createRouter(routes: Route[]) {\n const compiled: CompiledRoute[] = routes.map((r) => {\n const { regex, paramNames } = compilePattern(r.pattern);\n return { method: r.method, regex, paramNames, handler: r.handler };\n });\n\n return async (req: Request, tenantId: string): Promise<Response> => {\n const url = new URL(req.url);\n const method = req.method.toUpperCase();\n const path = url.pathname;\n\n for (const route of compiled) {\n if (route.method !== method) continue;\n const match = path.match(route.regex);\n if (!match) continue;\n\n const params: Record<string, string> = {};\n route.paramNames.forEach((name, i) => {\n params[name] = match[i + 1]!;\n });\n\n return route.handler(req, { tenantId, params });\n }\n\n return Response.json(\n { error: { _type: \"NotFoundError\", message: \"Route not found\" } },\n { status: 404 },\n );\n };\n}\n","import { Effect } from \"effect\";\nimport type { HandlerFn } from \"./router.js\";\nimport { resolveEnv } from \"./handler-utils.js\";\nimport type { CredentialService } from \"../services/credential-service.js\";\nimport type { AuthService } from \"../services/auth-service.js\";\nimport { SaveCredentialsSchema } from \"../validation/schemas.js\";\nimport { ValidationError } from \"../core/effect/app-error.js\";\nimport {\n noContentResponse,\n handleEffect,\n} from \"../core/effect/http-response.js\";\n\nexport function createAuthHandlers(deps: {\n credentialService: CredentialService;\n authService: AuthService;\n}) {\n const { credentialService, authService } = deps;\n\n const saveCredentials: HandlerFn = (req, ctx) =>\n handleEffect(\n Effect.gen(function* () {\n const body = yield* Effect.tryPromise({\n try: () => req.json(),\n catch: () => ValidationError.make(\"Invalid JSON body\"),\n });\n const parsed = SaveCredentialsSchema.safeParse(body);\n if (!parsed.success) {\n return yield* Effect.fail(\n ValidationError.fromZodErrors(\"Invalid credentials data\", parsed.error.issues),\n );\n }\n const result = yield* credentialService.save(ctx.tenantId, parsed.data);\n return {\n id: result.id,\n env: result.env,\n hasCert: !!result.certBase64,\n hasPortal: !!result.portalRut,\n portalRut: result.portalRut,\n createdAt: result.createdAt,\n updatedAt: result.updatedAt,\n };\n }),\n );\n\n const getStatus: HandlerFn = (req, ctx) => {\n const env = resolveEnv(req);\n return handleEffect(credentialService.getStatus(ctx.tenantId, env));\n };\n\n const testConnection: HandlerFn = (req, ctx) => {\n const env = resolveEnv(req);\n return handleEffect(authService.testConnection(ctx.tenantId, env));\n };\n\n const disconnect: HandlerFn = (req, ctx) => {\n const env = resolveEnv(req);\n return handleEffect(\n credentialService.disconnect(ctx.tenantId, env).pipe(Effect.map(() => null)),\n () => noContentResponse(),\n );\n };\n\n return {\n saveCredentials,\n getStatus,\n testConnection,\n disconnect,\n };\n}\n","import type { SiiEnv } from \"@emisso/sii\";\n\n/**\n * Resolve the SII environment from query params, defaulting to \"production\".\n */\nexport function resolveEnv(req: Request): SiiEnv {\n const url = new URL(req.url);\n const env = url.searchParams.get(\"env\");\n return env === \"certification\" ? \"certification\" : \"production\";\n}\n\n/**\n * Parse a \"YYYY-MM\" period string into year and month numbers.\n */\nexport function parsePeriod(period: string): { year: number; month: number } {\n const [y, m] = period.split(\"-\");\n return { year: parseInt(y!, 10), month: parseInt(m!, 10) };\n}\n","import { Effect } from \"effect\";\nimport type { HandlerFn } from \"./router.js\";\nimport { resolveEnv, parsePeriod } from \"./handler-utils.js\";\nimport type { InvoiceService } from \"../services/invoice-service.js\";\nimport type { InvoiceRepo } from \"../repos/invoice-repo.js\";\nimport type { SyncJobRepo } from \"../repos/sync-job-repo.js\";\nimport {\n SyncInvoicesSchema,\n ListInvoicesQuerySchema,\n SyncStatusQuerySchema,\n} from \"../validation/schemas.js\";\nimport { ValidationError } from \"../core/effect/app-error.js\";\nimport { rowToInvoice } from \"../core/bridge.js\";\nimport {\n createdResponse,\n handleEffect,\n} from \"../core/effect/http-response.js\";\n\nexport function createInvoiceHandlers(deps: {\n invoiceService: InvoiceService;\n invoiceRepo: InvoiceRepo;\n syncJobRepo: SyncJobRepo;\n}) {\n const { invoiceService, invoiceRepo, syncJobRepo } = deps;\n\n const listInvoices: HandlerFn = (req, ctx) =>\n handleEffect(\n Effect.gen(function* () {\n const url = new URL(req.url);\n const query = ListInvoicesQuerySchema.safeParse(\n Object.fromEntries(url.searchParams),\n );\n if (!query.success) {\n return yield* Effect.fail(\n ValidationError.fromZodErrors(\"Invalid query parameters\", query.error.issues),\n );\n }\n\n const { period, type, documentType, limit, offset } = query.data;\n const periodParsed = period ? parsePeriod(period) : undefined;\n\n const rows = yield* invoiceRepo.list(ctx.tenantId, {\n periodYear: periodParsed?.year,\n periodMonth: periodParsed?.month,\n issueType: type,\n documentType,\n limit,\n offset,\n });\n\n return { data: rows.map(rowToInvoice), count: rows.length };\n }),\n );\n\n const syncInvoices: HandlerFn = (req, ctx) =>\n handleEffect(\n Effect.gen(function* () {\n const body = yield* Effect.tryPromise({\n try: () => req.json(),\n catch: () => ValidationError.make(\"Invalid JSON body\"),\n });\n const parsed = SyncInvoicesSchema.safeParse(body);\n if (!parsed.success) {\n return yield* Effect.fail(\n ValidationError.fromZodErrors(\"Invalid sync parameters\", parsed.error.issues),\n );\n }\n const { year: periodYear, month: periodMonth } = parsePeriod(parsed.data.period);\n const env = resolveEnv(req);\n return yield* invoiceService.sync(ctx.tenantId, env, periodYear, periodMonth, parsed.data.type);\n }),\n createdResponse,\n );\n\n const getSyncStatus: HandlerFn = (req, ctx) =>\n handleEffect(\n Effect.gen(function* () {\n const url = new URL(req.url);\n const query = SyncStatusQuerySchema.safeParse(\n Object.fromEntries(url.searchParams),\n );\n if (!query.success) {\n return yield* Effect.fail(\n ValidationError.fromZodErrors(\"Invalid query parameters\", query.error.issues),\n );\n }\n const { period, type } = query.data;\n const periodParsed = period ? parsePeriod(period) : undefined;\n const jobs = yield* syncJobRepo.listByTenant(ctx.tenantId, {\n periodYear: periodParsed?.year,\n periodMonth: periodParsed?.month,\n issueType: type,\n });\n return { data: jobs };\n }),\n );\n\n return {\n listInvoices,\n syncInvoices,\n getSyncStatus,\n };\n}\n"],"mappings":"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","names":["import_pg_core","import_pg_core","import_pg_core","import_pg_core","import_effect","import_effect","import_effect","import_effect","import_drizzle_orm","import_effect","import_drizzle_orm","rows","import_effect","import_drizzle_orm","import_effect","import_effect","import_sii","import_effect","import_sii","import_effect","import_effect","listInvoices"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/db/schema/sii-schema.ts","../src/db/schema/credentials.ts","../src/db/schema/token-cache.ts","../src/db/schema/invoices.ts","../src/db/schema/sync-jobs.ts","../src/core/effect/app-error.ts","../src/core/effect/http-response.ts","../src/core/effect/repo-helpers.ts","../src/core/bridge.ts","../src/validation/schemas.ts","../src/repos/credential-repo.ts","../src/repos/token-cache-repo.ts","../src/repos/invoice-repo.ts","../src/repos/sync-job-repo.ts","../src/services/credential-service.ts","../src/services/auth-service.ts","../src/services/invoice-service.ts","../src/handlers/router.ts","../src/handlers/auth-handlers.ts","../src/handlers/handler-utils.ts","../src/handlers/invoice-handlers.ts"],"sourcesContent":["// ── Schema exports ──\nexport { siiSchema } from \"./db/schema/index.js\";\nexport * from \"./db/schema/index.js\";\n\n// ── Core ──\nexport {\n NotFoundError,\n ValidationError,\n ForbiddenError,\n DbError,\n ConflictError,\n SiiAuthError,\n isAppError,\n serializeAppError,\n type AppError,\n} from \"./core/effect/app-error.js\";\nexport {\n toErrorResponse,\n toErrorResponseFromUnknown,\n handleEffect,\n jsonResponse,\n createdResponse,\n noContentResponse,\n} from \"./core/effect/http-response.js\";\nexport { queryOneOrFail } from \"./core/effect/repo-helpers.js\";\nexport { invoiceToRow, rowToInvoice } from \"./core/bridge.js\";\n\n// ── Validation ──\nexport {\n SaveCredentialsSchema,\n SyncInvoicesSchema,\n ListInvoicesQuerySchema,\n SyncStatusQuerySchema,\n} from \"./validation/schemas.js\";\nexport type {\n SaveCredentialsInput,\n SyncInvoicesInput,\n ListInvoicesQuery,\n} from \"./validation/schemas.js\";\n\n// ── Repos ──\nexport { createCredentialRepo, type CredentialRepo } from \"./repos/credential-repo.js\";\nexport { createTokenCacheRepo, type TokenCacheRepo } from \"./repos/token-cache-repo.js\";\nexport { createInvoiceRepo, type InvoiceRepo } from \"./repos/invoice-repo.js\";\nexport { createSyncJobRepo, type SyncJobRepo } from \"./repos/sync-job-repo.js\";\n\n// ── Services ──\nexport { createCredentialService, type CredentialService } from \"./services/credential-service.js\";\nexport { createAuthService, type AuthService } from \"./services/auth-service.js\";\nexport { createInvoiceService, type InvoiceService } from \"./services/invoice-service.js\";\n\n// ── Handlers ──\nexport { createRouter, type Route, type HandlerFn, type HandlerContext } from \"./handlers/router.js\";\nexport { createAuthHandlers } from \"./handlers/auth-handlers.js\";\nexport { createInvoiceHandlers } from \"./handlers/invoice-handlers.js\";\n","import { pgSchema } from \"drizzle-orm/pg-core\";\n\nexport const siiSchema = pgSchema(\"sii\");\n","import {\n text,\n timestamp,\n unique,\n uuid,\n} from \"drizzle-orm/pg-core\";\nimport type { SiiEnv } from \"@emisso/sii\";\nimport { siiSchema } from \"./sii-schema.js\";\n\nexport const credentials = siiSchema.table(\n \"credentials\",\n {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n tenantId: uuid(\"tenant_id\").notNull(),\n // NOTE: `env` is typed as SiiEnv at the application layer via Drizzle's $type<>().\n // A DB-level CHECK constraint (env IN ('production','certification')) should be\n // added via a future migration to enforce this at the database level as well.\n env: text(\"env\").notNull().$type<SiiEnv>(),\n // TODO: ENCRYPT AT REST — these fields store sensitive SII credentials.\n // Must implement application-level encryption (AES-256-GCM) before production.\n certBase64: text(\"cert_base64\"),\n certPassword: text(\"cert_password\"),\n portalRut: text(\"portal_rut\"),\n // TODO: ENCRYPT AT REST — portal password stores sensitive SII credentials.\n // Must implement application-level encryption (AES-256-GCM) before production.\n portalPassword: text(\"portal_password\"),\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\").notNull().defaultNow(),\n },\n (table) => [unique(\"uq_credentials_tenant_env\").on(table.tenantId, table.env)],\n);\n\nexport type Credential = typeof credentials.$inferSelect;\nexport type NewCredential = typeof credentials.$inferInsert;\n","import {\n text,\n timestamp,\n unique,\n uuid,\n} from \"drizzle-orm/pg-core\";\nimport { siiSchema } from \"./sii-schema.js\";\nimport { credentials } from \"./credentials.js\";\n\nexport const tokenCache = siiSchema.table(\n \"token_cache\",\n {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n credentialId: uuid(\"credential_id\")\n .notNull()\n .references(() => credentials.id, { onDelete: \"cascade\" }),\n tokenType: text(\"token_type\").notNull().$type<\"soap\" | \"portal\">(),\n tokenValue: text(\"token_value\").notNull(),\n expiresAt: timestamp(\"expires_at\", { withTimezone: true }).notNull(),\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\n },\n (table) => [unique(\"uq_token_cache_cred_type\").on(table.credentialId, table.tokenType)],\n);\n\nexport type TokenCacheEntry = typeof tokenCache.$inferSelect;\nexport type NewTokenCacheEntry = typeof tokenCache.$inferInsert;\n","import {\n date,\n index,\n integer,\n jsonb,\n numeric,\n text,\n timestamp,\n unique,\n uuid,\n} from \"drizzle-orm/pg-core\";\nimport type { DteType, IssueType, ConfirmationStatus } from \"@emisso/sii\";\nimport { siiSchema } from \"./sii-schema.js\";\n\nexport const invoices = siiSchema.table(\n \"invoices\",\n {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n tenantId: uuid(\"tenant_id\").notNull(),\n documentType: text(\"document_type\").notNull().$type<DteType>(),\n number: integer(\"number\").notNull(),\n issuerRut: text(\"issuer_rut\"),\n issuerName: text(\"issuer_name\"),\n receiverRut: text(\"receiver_rut\"),\n receiverName: text(\"receiver_name\"),\n date: date(\"date\"),\n netAmount: numeric(\"net_amount\", { precision: 16, scale: 0 }),\n exemptAmount: numeric(\"exempt_amount\", { precision: 16, scale: 0 }),\n vatAmount: numeric(\"vat_amount\", { precision: 16, scale: 0 }),\n totalAmount: numeric(\"total_amount\", { precision: 16, scale: 0 }),\n taxPeriodYear: integer(\"tax_period_year\").notNull(),\n taxPeriodMonth: integer(\"tax_period_month\").notNull(),\n issueType: text(\"issue_type\").notNull().$type<IssueType>(),\n confirmationStatus: text(\"confirmation_status\").$type<ConfirmationStatus>(),\n raw: jsonb(\"raw\").$type<Record<string, string>>(),\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\n updatedAt: timestamp(\"updated_at\").notNull().defaultNow(),\n },\n (table) => [\n unique(\"uq_invoices_natural_key\").on(\n table.tenantId,\n table.documentType,\n table.number,\n table.issuerRut,\n table.receiverRut,\n table.issueType,\n ),\n index(\"idx_invoices_tenant_period\").on(\n table.tenantId,\n table.taxPeriodYear,\n table.taxPeriodMonth,\n ),\n ],\n);\n\nexport type InvoiceRow = typeof invoices.$inferSelect;\nexport type NewInvoiceRow = typeof invoices.$inferInsert;\n","import {\n integer,\n text,\n timestamp,\n uuid,\n} from \"drizzle-orm/pg-core\";\nimport type { IssueType } from \"@emisso/sii\";\nimport { siiSchema } from \"./sii-schema.js\";\n\nexport type SyncJobStatus = \"pending\" | \"running\" | \"completed\" | \"failed\";\n\nexport const syncJobs = siiSchema.table(\"sync_jobs\", {\n id: uuid(\"id\").defaultRandom().primaryKey(),\n tenantId: uuid(\"tenant_id\").notNull(),\n operation: text(\"operation\").notNull().$type<\"rcv_sync\">(),\n periodYear: integer(\"period_year\").notNull(),\n periodMonth: integer(\"period_month\").notNull(),\n issueType: text(\"issue_type\").notNull().$type<IssueType>(),\n status: text(\"status\").notNull().default(\"pending\").$type<SyncJobStatus>(),\n startedAt: timestamp(\"started_at\"),\n completedAt: timestamp(\"completed_at\"),\n recordsFetched: integer(\"records_fetched\"),\n errorMessage: text(\"error_message\"),\n createdAt: timestamp(\"created_at\").notNull().defaultNow(),\n});\n\nexport type SyncJob = typeof syncJobs.$inferSelect;\nexport type NewSyncJob = typeof syncJobs.$inferInsert;\n","/**\n * Application errors for Effect-based SII API logic.\n * Uses Data.TaggedError which automatically sets `_tag` as the discriminator.\n */\n\nimport { Data } from \"effect\";\n\n// ============================================================================\n// ERROR TYPES\n// ============================================================================\n\nexport class NotFoundError extends Data.TaggedError(\"NotFoundError\")<{\n readonly message: string;\n readonly entity?: string;\n readonly entityId?: string;\n}> {\n static make(entity: string, entityId?: string): NotFoundError {\n return new NotFoundError({\n message: `${entity} not found${entityId ? `: ${entityId}` : \"\"}`,\n entity,\n entityId,\n });\n }\n}\n\nexport class ValidationError extends Data.TaggedError(\"ValidationError\")<{\n readonly message: string;\n readonly field?: string;\n readonly details?: Record<string, unknown>;\n readonly fieldErrors?: Array<{ path: string; message: string }>;\n}> {\n static make(\n message: string,\n field?: string,\n details?: Record<string, unknown>,\n ): ValidationError {\n return new ValidationError({\n message,\n field,\n details,\n });\n }\n\n static fromZodErrors(\n message: string,\n issues: Array<{ path: (string | number)[]; message: string }>,\n ): ValidationError {\n return new ValidationError({\n message,\n fieldErrors: issues.map((i) => ({\n path: i.path.join(\".\"),\n message: i.message,\n })),\n });\n }\n}\n\nexport class ForbiddenError extends Data.TaggedError(\"ForbiddenError\")<{\n readonly message: string;\n readonly requiredPermission?: string;\n}> {\n static make(\n message: string = \"Forbidden\",\n requiredPermission?: string,\n ): ForbiddenError {\n return new ForbiddenError({\n message,\n requiredPermission,\n });\n }\n}\n\nexport class DbError extends Data.TaggedError(\"DbError\")<{\n readonly message: string;\n readonly operation?: string;\n readonly cause?: unknown;\n}> {\n static make(operation: string, cause?: unknown): DbError {\n const message =\n cause instanceof Error ? cause.message : \"Database operation failed\";\n return new DbError({\n message,\n operation,\n cause,\n });\n }\n}\n\nexport class ConflictError extends Data.TaggedError(\"ConflictError\")<{\n readonly message: string;\n readonly resource?: string;\n readonly conflictingValue?: string;\n}> {\n static make(\n message: string,\n resource?: string,\n conflictingValue?: string,\n ): ConflictError {\n return new ConflictError({\n message,\n resource,\n conflictingValue,\n });\n }\n}\n\nexport class SiiAuthError extends Data.TaggedError(\"SiiAuthError\")<{\n readonly message: string;\n readonly cause?: unknown;\n}> {\n static make(message: string, cause?: unknown): SiiAuthError {\n return new SiiAuthError({\n message,\n cause,\n });\n }\n}\n\n// ============================================================================\n// UNION TYPE\n// ============================================================================\n\nexport type AppError =\n | NotFoundError\n | ValidationError\n | ForbiddenError\n | DbError\n | ConflictError\n | SiiAuthError;\n\n// ============================================================================\n// TYPE GUARDS\n// ============================================================================\n\nexport function isAppError(error: unknown): error is AppError {\n return (\n error instanceof NotFoundError ||\n error instanceof ValidationError ||\n error instanceof ForbiddenError ||\n error instanceof DbError ||\n error instanceof ConflictError ||\n error instanceof SiiAuthError\n );\n}\n\n// ============================================================================\n// SERIALIZATION\n// ============================================================================\n\nexport function serializeAppError(error: AppError): {\n _type: string;\n message: string;\n [key: string]: unknown;\n} {\n const result: Record<string, unknown> = {\n _type: error._tag,\n message: error.message,\n };\n\n switch (error._tag) {\n case \"NotFoundError\":\n if (error.entity) result.entity = error.entity;\n if (error.entityId) result.entityId = error.entityId;\n break;\n case \"ValidationError\":\n if (error.field) result.field = error.field;\n if (error.details) result.details = error.details;\n if (error.fieldErrors) result.fieldErrors = error.fieldErrors;\n break;\n case \"ForbiddenError\":\n if (error.requiredPermission)\n result.requiredPermission = error.requiredPermission;\n break;\n case \"DbError\":\n if (error.operation) result.operation = error.operation;\n break;\n case \"ConflictError\":\n if (error.resource) result.resource = error.resource;\n if (error.conflictingValue)\n result.conflictingValue = error.conflictingValue;\n break;\n case \"SiiAuthError\":\n break;\n default: {\n const _exhaustive: never = error;\n return result as any;\n }\n }\n\n return result as { _type: string; message: string; [key: string]: unknown };\n}\n","/**\n * Framework-agnostic HTTP response helpers using Web API Response.\n * No dependency on Next.js or any framework.\n */\n\nimport { Effect } from \"effect\";\nimport type { AppError } from \"./app-error.js\";\nimport { isAppError, serializeAppError } from \"./app-error.js\";\n\n// ============================================================================\n// STATUS CODE MAPPING\n// ============================================================================\n\nconst STATUS_MAP: Record<AppError[\"_tag\"], number> = {\n ValidationError: 400,\n ForbiddenError: 403,\n NotFoundError: 404,\n ConflictError: 409,\n SiiAuthError: 502,\n DbError: 500,\n};\n\n// ============================================================================\n// ERROR RESPONSES\n// ============================================================================\n\nexport function toErrorResponse(error: AppError): Response {\n const status = STATUS_MAP[error._tag] ?? 500;\n const body = serializeAppError(error);\n return Response.json({ error: body }, { status });\n}\n\n/**\n * Extracts an AppError from an unknown error, handling Effect's FiberFailure wrapping.\n */\nfunction extractAppError(error: unknown): AppError | null {\n if (isAppError(error)) return error;\n // Handle Effect's FiberFailure — access cause.error\n const cause = (error as any)?.cause;\n if (cause) {\n const inner = cause?.error;\n if (isAppError(inner)) return inner;\n }\n return null;\n}\n\nexport function toErrorResponseFromUnknown(error: unknown): Response {\n const appError = extractAppError(error);\n if (appError) return toErrorResponse(appError);\n console.error(\"[sii-api] Unhandled error:\", error);\n return Response.json(\n { error: { _type: \"InternalError\", message: \"Internal server error\" } },\n { status: 500 },\n );\n}\n\n// ============================================================================\n// EFFECT HANDLER\n// ============================================================================\n\n/**\n * Run an Effect at the handler boundary, converting errors to HTTP responses.\n */\nexport function handleEffect<T>(\n effect: Effect.Effect<T, AppError>,\n toResponse: (data: T) => Response = jsonResponse,\n): Promise<Response> {\n return Effect.runPromise(\n effect.pipe(\n Effect.map(toResponse),\n Effect.catchAll((err) => Effect.succeed(toErrorResponse(err))),\n ),\n );\n}\n\n// ============================================================================\n// SUCCESS RESPONSES\n// ============================================================================\n\nexport function jsonResponse<T>(data: T, status: number = 200): Response {\n return Response.json(data, { status });\n}\n\nexport function createdResponse<T>(data: T): Response {\n return Response.json(data, { status: 201 });\n}\n\nexport function noContentResponse(): Response {\n return new Response(null, { status: 204 });\n}\n","import { Effect } from \"effect\";\nimport { DbError, NotFoundError } from \"./app-error.js\";\n\n/**\n * Query a single row and fail with NotFoundError if not found.\n */\nexport function queryOneOrFail<T>(\n operation: string,\n entity: string,\n entityId: string,\n query: () => Promise<T | undefined>,\n): Effect.Effect<T, DbError | NotFoundError> {\n return Effect.tryPromise({\n try: query,\n catch: (e) => DbError.make(operation, e),\n }).pipe(\n Effect.flatMap((row) =>\n row\n ? Effect.succeed(row)\n : Effect.fail(NotFoundError.make(entity, entityId)),\n ),\n );\n}\n","/**\n * Converts between DB rows and engine Invoice type.\n */\n\nimport type { Invoice, IssueType } from \"@emisso/sii\";\nimport type { InvoiceRow, NewInvoiceRow } from \"../db/schema/index.js\";\n\n/**\n * Convert an engine Invoice to a DB row for upsert.\n */\nexport function invoiceToRow(\n tenantId: string,\n invoice: Invoice,\n issueType: IssueType,\n): Omit<NewInvoiceRow, \"id\" | \"createdAt\" | \"updatedAt\"> {\n return {\n tenantId,\n documentType: invoice.documentType,\n number: invoice.number,\n issuerRut: invoice.issuer.rut || null,\n issuerName: invoice.issuer.name || null,\n receiverRut: invoice.receiver.rut || null,\n receiverName: invoice.receiver.name || null,\n date: invoice.date || null,\n netAmount: String(invoice.netAmount),\n exemptAmount: String(invoice.exemptAmount),\n vatAmount: String(invoice.vatAmount),\n totalAmount: String(invoice.totalAmount),\n taxPeriodYear: invoice.taxPeriod.year,\n taxPeriodMonth: invoice.taxPeriod.month,\n issueType,\n confirmationStatus: invoice.confirmationStatus ?? null,\n raw: invoice.raw ?? null,\n };\n}\n\n/**\n * Convert a DB row back to an engine-compatible Invoice.\n */\nexport function rowToInvoice(row: InvoiceRow): Invoice {\n return {\n id: `${row.documentType}-${row.number}-${row.issuerRut || row.receiverRut || \"\"}`,\n number: row.number,\n issuer: {\n rut: row.issuerRut ?? \"\",\n name: row.issuerName ?? \"\",\n },\n receiver: {\n rut: row.receiverRut ?? \"\",\n name: row.receiverName ?? \"\",\n },\n date: row.date ?? \"\",\n netAmount: Number(row.netAmount ?? 0),\n exemptAmount: Number(row.exemptAmount ?? 0),\n vatAmount: Number(row.vatAmount ?? 0),\n totalAmount: Number(row.totalAmount ?? 0),\n currency: \"CLP\",\n taxPeriod: {\n year: row.taxPeriodYear,\n month: row.taxPeriodMonth,\n },\n documentType: row.documentType,\n confirmationStatus: row.confirmationStatus ?? \"REGISTRO\",\n raw: row.raw ?? {},\n };\n}\n","/**\n * Zod validation schemas for HTTP inputs.\n */\n\nimport { z } from \"zod\";\nimport { SiiEnvSchema, IssueTypeSchema, DteTypeSchema } from \"@emisso/sii\";\n\n// ── Credentials ──\n\nexport const SaveCredentialsSchema = z\n .object({\n env: SiiEnvSchema.default(\"production\"),\n certBase64: z.string().optional(),\n certPassword: z.string().optional(),\n portalRut: z.string().optional(),\n portalPassword: z.string().optional(),\n })\n .refine(\n (d) => (d.certBase64 || d.certPassword) || (d.portalRut || d.portalPassword),\n { message: \"At least one credential pair is required: certificate (certBase64 + certPassword) or portal (portalRut + portalPassword)\" },\n )\n .refine(\n (d) => (!d.certBase64 && !d.certPassword) || (d.certBase64 && d.certPassword),\n { message: \"certBase64 and certPassword must both be provided or both omitted\" },\n )\n .refine(\n (d) => (!d.portalRut && !d.portalPassword) || (d.portalRut && d.portalPassword),\n { message: \"portalRut and portalPassword must both be provided or both omitted\" },\n );\nexport type SaveCredentialsInput = z.infer<typeof SaveCredentialsSchema>;\n\n// ── Invoice sync ──\n\nexport const SyncInvoicesSchema = z.object({\n period: z.string().regex(/^\\d{4}-\\d{2}$/, \"Period must be YYYY-MM format\"),\n type: IssueTypeSchema.default(\"received\"),\n});\nexport type SyncInvoicesInput = z.infer<typeof SyncInvoicesSchema>;\n\n// ── Invoice list query ──\n\nexport const ListInvoicesQuerySchema = z.object({\n period: z.string().regex(/^\\d{4}-\\d{2}$/).optional(),\n type: IssueTypeSchema.optional(),\n documentType: DteTypeSchema.optional(),\n limit: z.coerce.number().int().positive().max(1000).default(100),\n offset: z.coerce.number().int().nonnegative().default(0),\n});\n\n// ── Sync status query ──\n\nexport const SyncStatusQuerySchema = z.object({\n period: z.string().regex(/^\\d{4}-\\d{2}$/).optional(),\n type: IssueTypeSchema.optional(),\n});\nexport type ListInvoicesQuery = z.infer<typeof ListInvoicesQuerySchema>;\n","import { Effect } from \"effect\";\nimport { and, eq } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport type { SiiEnv } from \"@emisso/sii\";\nimport { credentials, type Credential, type NewCredential } from \"../db/schema/index.js\";\nimport { DbError, NotFoundError } from \"../core/effect/app-error.js\";\nimport { queryOneOrFail } from \"../core/effect/repo-helpers.js\";\n\nexport function createCredentialRepo(db: PgDatabase<any>) {\n return {\n getByTenantAndEnv(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<Credential, DbError | NotFoundError> {\n return queryOneOrFail(\n \"credential.getByTenantAndEnv\",\n \"Credential\",\n `${tenantId}/${env}`,\n () =>\n db\n .select()\n .from(credentials)\n .where(\n and(\n eq(credentials.tenantId, tenantId),\n eq(credentials.env, env),\n ),\n )\n .then((rows) => rows[0]),\n );\n },\n\n upsert(\n tenantId: string,\n data: Omit<NewCredential, \"id\" | \"tenantId\" | \"createdAt\" | \"updatedAt\">,\n ): Effect.Effect<Credential, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .insert(credentials)\n .values({ ...data, tenantId })\n .onConflictDoUpdate({\n target: [credentials.tenantId, credentials.env],\n set: { ...data, updatedAt: new Date() },\n })\n .returning()\n .then((rows) => rows[0]!),\n catch: (e) => DbError.make(\"credential.upsert\", e),\n });\n },\n\n delete(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<boolean, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .delete(credentials)\n .where(\n and(\n eq(credentials.tenantId, tenantId),\n eq(credentials.env, env),\n ),\n )\n .returning()\n .then((rows) => rows.length > 0),\n catch: (e) => DbError.make(\"credential.delete\", e),\n });\n },\n };\n}\n\nexport type CredentialRepo = ReturnType<typeof createCredentialRepo>;\n","import { Effect } from \"effect\";\nimport { and, eq } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport { tokenCache, type TokenCacheEntry } from \"../db/schema/index.js\";\nimport { DbError } from \"../core/effect/app-error.js\";\n\nexport function createTokenCacheRepo(db: PgDatabase<any>) {\n return {\n get(\n credentialId: string,\n tokenType: \"soap\" | \"portal\",\n ): Effect.Effect<TokenCacheEntry | null, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .select()\n .from(tokenCache)\n .where(\n and(\n eq(tokenCache.credentialId, credentialId),\n eq(tokenCache.tokenType, tokenType),\n ),\n )\n .then((rows) => rows[0] ?? null),\n catch: (e) => DbError.make(\"tokenCache.get\", e),\n });\n },\n\n upsert(\n credentialId: string,\n tokenType: \"soap\" | \"portal\",\n tokenValue: string,\n expiresAt: Date,\n ): Effect.Effect<TokenCacheEntry, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .insert(tokenCache)\n .values({ credentialId, tokenType, tokenValue, expiresAt })\n .onConflictDoUpdate({\n target: [tokenCache.credentialId, tokenCache.tokenType],\n set: { tokenValue, expiresAt, createdAt: new Date() },\n })\n .returning()\n .then((rows) => rows[0]!),\n catch: (e) => DbError.make(\"tokenCache.upsert\", e),\n });\n },\n\n deleteByCredential(credentialId: string): Effect.Effect<void, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .delete(tokenCache)\n .where(eq(tokenCache.credentialId, credentialId))\n .then(() => undefined),\n catch: (e) => DbError.make(\"tokenCache.deleteByCredential\", e),\n });\n },\n };\n}\n\nexport type TokenCacheRepo = ReturnType<typeof createTokenCacheRepo>;\n","import { Effect } from \"effect\";\nimport { and, eq, sql } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport type { IssueType, DteType } from \"@emisso/sii\";\nimport { invoices, type InvoiceRow, type NewInvoiceRow } from \"../db/schema/index.js\";\nimport { DbError } from \"../core/effect/app-error.js\";\n\nexport function createInvoiceRepo(db: PgDatabase<any>) {\n return {\n list(\n tenantId: string,\n filters?: {\n periodYear?: number;\n periodMonth?: number;\n issueType?: IssueType;\n documentType?: DteType;\n limit?: number;\n offset?: number;\n },\n ): Effect.Effect<InvoiceRow[], DbError> {\n return Effect.tryPromise({\n try: () => {\n const conditions = [eq(invoices.tenantId, tenantId)];\n if (filters?.periodYear !== undefined) {\n conditions.push(eq(invoices.taxPeriodYear, filters.periodYear));\n }\n if (filters?.periodMonth !== undefined) {\n conditions.push(eq(invoices.taxPeriodMonth, filters.periodMonth));\n }\n if (filters?.issueType) {\n conditions.push(eq(invoices.issueType, filters.issueType));\n }\n if (filters?.documentType) {\n conditions.push(eq(invoices.documentType, filters.documentType));\n }\n return db\n .select()\n .from(invoices)\n .where(and(...conditions))\n .limit(filters?.limit ?? 100)\n .offset(filters?.offset ?? 0);\n },\n catch: (e) => DbError.make(\"invoice.list\", e),\n });\n },\n\n upsertMany(\n rows: Omit<NewInvoiceRow, \"id\" | \"createdAt\" | \"updatedAt\">[],\n ): Effect.Effect<number, DbError> {\n if (rows.length === 0) return Effect.succeed(0);\n return Effect.tryPromise({\n try: () =>\n db\n .insert(invoices)\n .values(rows)\n .onConflictDoUpdate({\n target: [\n invoices.tenantId,\n invoices.documentType,\n invoices.number,\n invoices.issuerRut,\n invoices.receiverRut,\n invoices.issueType,\n ],\n set: {\n issuerName: sql`excluded.issuer_name`,\n receiverName: sql`excluded.receiver_name`,\n date: sql`excluded.date`,\n netAmount: sql`excluded.net_amount`,\n exemptAmount: sql`excluded.exempt_amount`,\n vatAmount: sql`excluded.vat_amount`,\n totalAmount: sql`excluded.total_amount`,\n confirmationStatus: sql`excluded.confirmation_status`,\n raw: sql`excluded.raw`,\n updatedAt: new Date(),\n },\n })\n .returning({ id: invoices.id })\n .then((rows) => rows.length),\n catch: (e) => DbError.make(\"invoice.upsertMany\", e),\n });\n },\n\n count(\n tenantId: string,\n filters?: {\n periodYear?: number;\n periodMonth?: number;\n issueType?: IssueType;\n },\n ): Effect.Effect<number, DbError> {\n return Effect.tryPromise({\n try: () => {\n const conditions = [eq(invoices.tenantId, tenantId)];\n if (filters?.periodYear !== undefined) {\n conditions.push(eq(invoices.taxPeriodYear, filters.periodYear));\n }\n if (filters?.periodMonth !== undefined) {\n conditions.push(eq(invoices.taxPeriodMonth, filters.periodMonth));\n }\n if (filters?.issueType) {\n conditions.push(eq(invoices.issueType, filters.issueType));\n }\n return db\n .select({ count: sql<number>`count(*)::int` })\n .from(invoices)\n .where(and(...conditions))\n .then((rows) => rows[0]?.count ?? 0);\n },\n catch: (e) => DbError.make(\"invoice.count\", e),\n });\n },\n };\n}\n\nexport type InvoiceRepo = ReturnType<typeof createInvoiceRepo>;\n","import { Effect } from \"effect\";\nimport { and, eq, desc } from \"drizzle-orm\";\nimport type { PgDatabase } from \"drizzle-orm/pg-core\";\nimport type { IssueType } from \"@emisso/sii\";\nimport { syncJobs, type SyncJob, type NewSyncJob } from \"../db/schema/index.js\";\nimport { DbError, NotFoundError } from \"../core/effect/app-error.js\";\nimport { queryOneOrFail } from \"../core/effect/repo-helpers.js\";\n\nexport function createSyncJobRepo(db: PgDatabase<any>) {\n return {\n create(\n data: Omit<NewSyncJob, \"id\" | \"createdAt\">,\n ): Effect.Effect<SyncJob, DbError> {\n return Effect.tryPromise({\n try: () =>\n db\n .insert(syncJobs)\n .values(data)\n .returning()\n .then((rows) => rows[0]!),\n catch: (e) => DbError.make(\"syncJob.create\", e),\n });\n },\n\n getById(id: string): Effect.Effect<SyncJob, DbError | NotFoundError> {\n return queryOneOrFail(\n \"syncJob.getById\",\n \"SyncJob\",\n id,\n () =>\n db\n .select()\n .from(syncJobs)\n .where(eq(syncJobs.id, id))\n .then((rows) => rows[0]),\n );\n },\n\n listByTenant(\n tenantId: string,\n filters?: {\n periodYear?: number;\n periodMonth?: number;\n issueType?: IssueType;\n },\n ): Effect.Effect<SyncJob[], DbError> {\n return Effect.tryPromise({\n try: () => {\n const conditions = [eq(syncJobs.tenantId, tenantId)];\n if (filters?.periodYear !== undefined) {\n conditions.push(eq(syncJobs.periodYear, filters.periodYear));\n }\n if (filters?.periodMonth !== undefined) {\n conditions.push(eq(syncJobs.periodMonth, filters.periodMonth));\n }\n if (filters?.issueType) {\n conditions.push(eq(syncJobs.issueType, filters.issueType));\n }\n return db\n .select()\n .from(syncJobs)\n .where(and(...conditions))\n .orderBy(desc(syncJobs.createdAt))\n .limit(20);\n },\n catch: (e) => DbError.make(\"syncJob.listByTenant\", e),\n });\n },\n\n update(\n id: string,\n data: Partial<Pick<SyncJob, \"status\" | \"startedAt\" | \"completedAt\" | \"recordsFetched\" | \"errorMessage\">>,\n ): Effect.Effect<SyncJob, DbError | NotFoundError> {\n return queryOneOrFail(\n \"syncJob.update\",\n \"SyncJob\",\n id,\n () =>\n db\n .update(syncJobs)\n .set(data)\n .where(eq(syncJobs.id, id))\n .returning()\n .then((rows) => rows[0]),\n );\n },\n };\n}\n\nexport type SyncJobRepo = ReturnType<typeof createSyncJobRepo>;\n","import { Effect } from \"effect\";\nimport type { SiiEnv } from \"@emisso/sii\";\nimport type { CredentialRepo } from \"../repos/credential-repo.js\";\nimport type { TokenCacheRepo } from \"../repos/token-cache-repo.js\";\nimport type { Credential } from \"../db/schema/index.js\";\nimport type { SaveCredentialsInput } from \"../validation/schemas.js\";\nimport { NotFoundError, type AppError } from \"../core/effect/app-error.js\";\n\nexport function createCredentialService(deps: {\n credentialRepo: CredentialRepo;\n tokenCacheRepo: TokenCacheRepo;\n encrypt?: (plaintext: string) => string;\n decrypt?: (ciphertext: string) => string;\n}) {\n const { credentialRepo, tokenCacheRepo } = deps;\n const enc = (v: string | null | undefined) =>\n v && deps.encrypt ? deps.encrypt(v) : v;\n const dec = (v: string | null) =>\n v && deps.decrypt ? deps.decrypt(v) : v;\n\n return {\n save(\n tenantId: string,\n input: SaveCredentialsInput,\n ): Effect.Effect<Credential, AppError> {\n return credentialRepo.upsert(tenantId, {\n env: input.env,\n certBase64: enc(input.certBase64) ?? null,\n certPassword: enc(input.certPassword) ?? null,\n portalRut: input.portalRut ?? null,\n portalPassword: enc(input.portalPassword) ?? null,\n });\n },\n\n getStatus(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<{\n connected: boolean;\n env: string;\n hasCert: boolean;\n hasPortal: boolean;\n portalRut: string | null;\n }, AppError> {\n return credentialRepo.getByTenantAndEnv(tenantId, env).pipe(\n Effect.map((cred) => ({\n connected: true,\n env: cred.env,\n hasCert: !!cred.certBase64,\n hasPortal: !!cred.portalRut && !!cred.portalPassword,\n portalRut: cred.portalRut,\n })),\n Effect.catchTag(\"NotFoundError\", () =>\n Effect.succeed({\n connected: false,\n env,\n hasCert: false,\n hasPortal: false,\n portalRut: null,\n }),\n ),\n );\n },\n\n disconnect(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<void, AppError> {\n return Effect.gen(function* () {\n // Get credential to clean up token cache\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n\n // Token cache cascades on delete, but explicit cleanup is clearer\n yield* tokenCacheRepo.deleteByCredential(cred.id);\n yield* credentialRepo.delete(tenantId, env);\n });\n },\n };\n}\n\nexport type CredentialService = ReturnType<typeof createCredentialService>;\n","import { Effect } from \"effect\";\nimport {\n loadCertFromBase64,\n getSeed,\n signSeedFromCertData,\n getToken,\n portalLogin,\n type SiiToken,\n type PortalSession,\n type PortalLoginOptions,\n type SiiEnv,\n} from \"@emisso/sii\";\nimport type { CredentialRepo } from \"../repos/credential-repo.js\";\nimport type { TokenCacheRepo } from \"../repos/token-cache-repo.js\";\nimport { SiiAuthError, type AppError } from \"../core/effect/app-error.js\";\n\nfunction toMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Authenticate with SII SOAP using base64 certificate data.\n */\nasync function authenticateSoap(\n certBase64: string,\n certPassword: string,\n env: SiiEnv,\n): Promise<SiiToken> {\n const certData = loadCertFromBase64(certBase64, certPassword);\n // certPath and certPassword are required by SiiConfig but unused by getSeed/getToken,\n // which only need `env` to resolve the SOAP endpoint URL. We pass empty strings\n // because authentication is handled via the in-memory certData / signedSeed flow.\n const seed = await getSeed({ certPath: \"\", certPassword: \"\", env });\n const signedSeed = signSeedFromCertData(seed, certData);\n return getToken(signedSeed, { certPath: \"\", certPassword: \"\", env });\n}\n\nexport function createAuthService(deps: {\n credentialRepo: CredentialRepo;\n tokenCacheRepo: TokenCacheRepo;\n decrypt?: (ciphertext: string) => string;\n connectBrowser?: PortalLoginOptions[\"connectBrowser\"];\n}) {\n const { credentialRepo, tokenCacheRepo } = deps;\n const dec = (v: string) => (deps.decrypt ? deps.decrypt(v) : v);\n\n return {\n /**\n * Get a valid SOAP token, using cache if available.\n */\n getSoapToken(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<SiiToken, AppError> {\n return Effect.gen(function* () {\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n\n if (!cred.certBase64 || !cred.certPassword) {\n return yield* Effect.fail(\n SiiAuthError.make(\"No certificate configured for SOAP authentication\"),\n );\n }\n\n // Check cache\n const cached = yield* tokenCacheRepo.get(cred.id, \"soap\");\n if (cached && new Date(cached.expiresAt).getTime() > Date.now()) {\n return { token: cached.tokenValue, expiresAt: new Date(cached.expiresAt) };\n }\n\n // Authenticate with SII (decrypt credentials before use)\n const siiToken = yield* Effect.tryPromise({\n try: () => authenticateSoap(dec(cred.certBase64!), dec(cred.certPassword!), env),\n catch: (e) =>\n SiiAuthError.make(`SOAP authentication failed: ${toMessage(e)}`, e),\n });\n\n // Cache the token\n yield* tokenCacheRepo.upsert(\n cred.id,\n \"soap\",\n siiToken.token,\n siiToken.expiresAt,\n );\n\n return siiToken;\n });\n },\n\n /**\n * Get a portal session via fresh login.\n */\n getPortalSession(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<PortalSession, AppError> {\n return Effect.gen(function* () {\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n\n if (!cred.portalRut || !cred.portalPassword) {\n return yield* Effect.fail(\n SiiAuthError.make(\"No portal credentials configured\"),\n );\n }\n\n // Login to portal (decrypt credentials before use)\n const session = yield* Effect.tryPromise({\n try: () =>\n portalLogin(\n { rut: cred.portalRut!, claveTributaria: dec(cred.portalPassword!), env },\n { connectBrowser: deps.connectBrowser },\n ),\n catch: (e) =>\n SiiAuthError.make(`Portal login failed: ${toMessage(e)}`, e),\n });\n\n return session;\n });\n },\n\n /**\n * Test credentials by attempting authentication.\n * Runs SOAP and portal tests concurrently.\n */\n testConnection(\n tenantId: string,\n env: SiiEnv,\n ): Effect.Effect<{ soap: boolean; portal: boolean; errors: string[] }, AppError> {\n return Effect.gen(function* () {\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n const errors: string[] = [];\n\n // Build test effects\n const soapTest = cred.certBase64 && cred.certPassword\n ? Effect.tryPromise({\n try: () => authenticateSoap(dec(cred.certBase64!), dec(cred.certPassword!), env).then(() => true),\n catch: (e) => toMessage(e),\n }).pipe(Effect.catchAll((msg) => {\n errors.push(`SOAP: ${msg}`);\n return Effect.succeed(false);\n }))\n : Effect.sync(() => {\n errors.push(\"SOAP: No certificate configured\");\n return false;\n });\n\n const portalTest = cred.portalRut && cred.portalPassword\n ? Effect.tryPromise({\n try: () =>\n portalLogin(\n { rut: cred.portalRut!, claveTributaria: dec(cred.portalPassword!), env },\n { connectBrowser: deps.connectBrowser },\n ).then(() => true),\n catch: (e) => toMessage(e),\n }).pipe(Effect.catchAll((msg) => {\n errors.push(`Portal: ${msg}`);\n return Effect.succeed(false);\n }))\n : Effect.sync(() => {\n errors.push(\"Portal: No portal credentials configured\");\n return false;\n });\n\n // Run both tests concurrently\n const [soapOk, portalOk] = yield* Effect.all(\n [soapTest, portalTest],\n { concurrency: 2 },\n );\n\n return { soap: soapOk, portal: portalOk, errors };\n });\n },\n };\n}\n\nexport type AuthService = ReturnType<typeof createAuthService>;\n","import { Effect } from \"effect\";\nimport { listInvoices, type IssueType, type SiiEnv } from \"@emisso/sii\";\nimport type { InvoiceRepo } from \"../repos/invoice-repo.js\";\nimport type { SyncJobRepo } from \"../repos/sync-job-repo.js\";\nimport type { AuthService } from \"./auth-service.js\";\nimport type { CredentialRepo } from \"../repos/credential-repo.js\";\nimport type { SyncJob } from \"../db/schema/index.js\";\nimport { invoiceToRow } from \"../core/bridge.js\";\nimport { SiiAuthError, type AppError } from \"../core/effect/app-error.js\";\n\nexport function createInvoiceService(deps: {\n invoiceRepo: InvoiceRepo;\n syncJobRepo: SyncJobRepo;\n authService: AuthService;\n credentialRepo: CredentialRepo;\n}) {\n const { invoiceRepo, syncJobRepo, authService, credentialRepo } = deps;\n\n return {\n /**\n * Trigger an RCV invoice sync for a given period.\n * Creates a sync job, fetches from SII, upserts into DB.\n */\n sync(\n tenantId: string,\n env: SiiEnv,\n periodYear: number,\n periodMonth: number,\n issueType: IssueType,\n ): Effect.Effect<SyncJob, AppError> {\n return Effect.gen(function* () {\n // Create sync job\n const job = yield* syncJobRepo.create({\n tenantId,\n operation: \"rcv_sync\",\n periodYear,\n periodMonth,\n issueType,\n status: \"running\",\n startedAt: new Date(),\n });\n\n /** Mark job as failed and re-raise the error */\n const failJob = (err: AppError) =>\n syncJobRepo.update(job.id, {\n status: \"failed\",\n completedAt: new Date(),\n errorMessage: err.message,\n }).pipe(Effect.flatMap(() => Effect.fail(err)));\n\n // Get credential to find the RUT\n const cred = yield* credentialRepo.getByTenantAndEnv(tenantId, env);\n if (!cred.portalRut) {\n const err = SiiAuthError.make(\"No portal RUT configured for RCV sync\");\n return yield* failJob(err);\n }\n\n // Get portal session\n const session = yield* authService\n .getPortalSession(tenantId, env)\n .pipe(Effect.catchAll(failJob));\n\n // Fetch invoices from SII\n const siiInvoices = yield* Effect.tryPromise({\n try: () =>\n listInvoices(session, {\n rut: cred.portalRut!,\n issueType,\n period: { year: periodYear, month: periodMonth },\n }),\n catch: (e) =>\n SiiAuthError.make(\n `RCV fetch failed: ${e instanceof Error ? e.message : String(e)}`,\n e,\n ),\n }).pipe(Effect.catchAll(failJob));\n\n // Convert and upsert\n const rows = siiInvoices.map((inv) =>\n invoiceToRow(tenantId, inv, issueType),\n );\n const count = yield* invoiceRepo.upsertMany(rows);\n\n // Complete the job\n return yield* syncJobRepo.update(job.id, {\n status: \"completed\",\n completedAt: new Date(),\n recordsFetched: count,\n });\n });\n },\n };\n}\n\nexport type InvoiceService = ReturnType<typeof createInvoiceService>;\n","/**\n * Simple pattern-matching router for framework-agnostic handlers.\n * Supports `:param` patterns for URL parameters.\n */\n\nexport interface HandlerContext {\n tenantId: string;\n params: Record<string, string>;\n}\n\nexport type HandlerFn = (req: Request, ctx: HandlerContext) => Promise<Response>;\n\nexport interface Route {\n method: string;\n pattern: string;\n handler: HandlerFn;\n}\n\ninterface CompiledRoute {\n method: string;\n regex: RegExp;\n paramNames: string[];\n handler: HandlerFn;\n}\n\nfunction compilePattern(pattern: string): {\n regex: RegExp;\n paramNames: string[];\n} {\n const paramNames: string[] = [];\n const regexStr = pattern\n .split(\"/\")\n .map((segment) => {\n if (segment.startsWith(\":\")) {\n paramNames.push(segment.slice(1));\n return \"([^/]+)\";\n }\n return segment;\n })\n .join(\"/\");\n return { regex: new RegExp(`^${regexStr}$`), paramNames };\n}\n\nexport function createRouter(routes: Route[]) {\n const compiled: CompiledRoute[] = routes.map((r) => {\n const { regex, paramNames } = compilePattern(r.pattern);\n return { method: r.method, regex, paramNames, handler: r.handler };\n });\n\n return async (req: Request, tenantId: string): Promise<Response> => {\n const url = new URL(req.url);\n const method = req.method.toUpperCase();\n const path = url.pathname;\n\n for (const route of compiled) {\n if (route.method !== method) continue;\n const match = path.match(route.regex);\n if (!match) continue;\n\n const params: Record<string, string> = {};\n route.paramNames.forEach((name, i) => {\n params[name] = match[i + 1]!;\n });\n\n return route.handler(req, { tenantId, params });\n }\n\n return Response.json(\n { error: { _type: \"NotFoundError\", message: \"Route not found\" } },\n { status: 404 },\n );\n };\n}\n","import { Effect } from \"effect\";\nimport type { HandlerFn } from \"./router.js\";\nimport { resolveEnv } from \"./handler-utils.js\";\nimport type { CredentialService } from \"../services/credential-service.js\";\nimport type { AuthService } from \"../services/auth-service.js\";\nimport { SaveCredentialsSchema } from \"../validation/schemas.js\";\nimport { ValidationError } from \"../core/effect/app-error.js\";\nimport {\n noContentResponse,\n handleEffect,\n} from \"../core/effect/http-response.js\";\n\nexport function createAuthHandlers(deps: {\n credentialService: CredentialService;\n authService: AuthService;\n}) {\n const { credentialService, authService } = deps;\n\n const saveCredentials: HandlerFn = (req, ctx) =>\n handleEffect(\n Effect.gen(function* () {\n const body = yield* Effect.tryPromise({\n try: () => req.json(),\n catch: () => ValidationError.make(\"Invalid JSON body\"),\n });\n const parsed = SaveCredentialsSchema.safeParse(body);\n if (!parsed.success) {\n return yield* Effect.fail(\n ValidationError.fromZodErrors(\"Invalid credentials data\", parsed.error.issues),\n );\n }\n const result = yield* credentialService.save(ctx.tenantId, parsed.data);\n return {\n id: result.id,\n env: result.env,\n hasCert: !!result.certBase64,\n hasPortal: !!result.portalRut,\n portalRut: result.portalRut,\n createdAt: result.createdAt,\n updatedAt: result.updatedAt,\n };\n }),\n );\n\n const getStatus: HandlerFn = (req, ctx) => {\n const env = resolveEnv(req);\n return handleEffect(credentialService.getStatus(ctx.tenantId, env));\n };\n\n const testConnection: HandlerFn = (req, ctx) => {\n const env = resolveEnv(req);\n return handleEffect(authService.testConnection(ctx.tenantId, env));\n };\n\n const disconnect: HandlerFn = (req, ctx) => {\n const env = resolveEnv(req);\n return handleEffect(\n credentialService.disconnect(ctx.tenantId, env).pipe(Effect.map(() => null)),\n () => noContentResponse(),\n );\n };\n\n return {\n saveCredentials,\n getStatus,\n testConnection,\n disconnect,\n };\n}\n","import type { SiiEnv } from \"@emisso/sii\";\n\n/**\n * Resolve the SII environment from query params, defaulting to \"production\".\n */\nexport function resolveEnv(req: Request): SiiEnv {\n const url = new URL(req.url);\n const env = url.searchParams.get(\"env\");\n return env === \"certification\" ? \"certification\" : \"production\";\n}\n\n/**\n * Parse a \"YYYY-MM\" period string into year and month numbers.\n */\nexport function parsePeriod(period: string): { year: number; month: number } {\n const [y, m] = period.split(\"-\");\n return { year: parseInt(y!, 10), month: parseInt(m!, 10) };\n}\n","import { Effect } from \"effect\";\nimport type { HandlerFn } from \"./router.js\";\nimport { resolveEnv, parsePeriod } from \"./handler-utils.js\";\nimport type { InvoiceService } from \"../services/invoice-service.js\";\nimport type { InvoiceRepo } from \"../repos/invoice-repo.js\";\nimport type { SyncJobRepo } from \"../repos/sync-job-repo.js\";\nimport {\n SyncInvoicesSchema,\n ListInvoicesQuerySchema,\n SyncStatusQuerySchema,\n} from \"../validation/schemas.js\";\nimport { ValidationError } from \"../core/effect/app-error.js\";\nimport { rowToInvoice } from \"../core/bridge.js\";\nimport {\n createdResponse,\n handleEffect,\n} from \"../core/effect/http-response.js\";\n\nexport function createInvoiceHandlers(deps: {\n invoiceService: InvoiceService;\n invoiceRepo: InvoiceRepo;\n syncJobRepo: SyncJobRepo;\n}) {\n const { invoiceService, invoiceRepo, syncJobRepo } = deps;\n\n const listInvoices: HandlerFn = (req, ctx) =>\n handleEffect(\n Effect.gen(function* () {\n const url = new URL(req.url);\n const query = ListInvoicesQuerySchema.safeParse(\n Object.fromEntries(url.searchParams),\n );\n if (!query.success) {\n return yield* Effect.fail(\n ValidationError.fromZodErrors(\"Invalid query parameters\", query.error.issues),\n );\n }\n\n const { period, type, documentType, limit, offset } = query.data;\n const periodParsed = period ? parsePeriod(period) : undefined;\n\n const rows = yield* invoiceRepo.list(ctx.tenantId, {\n periodYear: periodParsed?.year,\n periodMonth: periodParsed?.month,\n issueType: type,\n documentType,\n limit,\n offset,\n });\n\n return { data: rows.map(rowToInvoice), count: rows.length };\n }),\n );\n\n const syncInvoices: HandlerFn = (req, ctx) =>\n handleEffect(\n Effect.gen(function* () {\n const body = yield* Effect.tryPromise({\n try: () => req.json(),\n catch: () => ValidationError.make(\"Invalid JSON body\"),\n });\n const parsed = SyncInvoicesSchema.safeParse(body);\n if (!parsed.success) {\n return yield* Effect.fail(\n ValidationError.fromZodErrors(\"Invalid sync parameters\", parsed.error.issues),\n );\n }\n const { year: periodYear, month: periodMonth } = parsePeriod(parsed.data.period);\n const env = resolveEnv(req);\n return yield* invoiceService.sync(ctx.tenantId, env, periodYear, periodMonth, parsed.data.type);\n }),\n createdResponse,\n );\n\n const getSyncStatus: HandlerFn = (req, ctx) =>\n handleEffect(\n Effect.gen(function* () {\n const url = new URL(req.url);\n const query = SyncStatusQuerySchema.safeParse(\n Object.fromEntries(url.searchParams),\n );\n if (!query.success) {\n return yield* Effect.fail(\n ValidationError.fromZodErrors(\"Invalid query parameters\", query.error.issues),\n );\n }\n const { period, type } = query.data;\n const periodParsed = period ? parsePeriod(period) : undefined;\n const jobs = yield* syncJobRepo.listByTenant(ctx.tenantId, {\n periodYear: periodParsed?.year,\n periodMonth: periodParsed?.month,\n issueType: type,\n });\n return { data: jobs };\n }),\n );\n\n return {\n listInvoices,\n syncInvoices,\n getSyncStatus,\n };\n}\n"],"mappings":"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","names":["import_pg_core","import_pg_core","import_pg_core","import_pg_core","import_effect","import_effect","import_effect","import_effect","import_drizzle_orm","import_effect","import_drizzle_orm","rows","import_effect","import_drizzle_orm","import_effect","import_effect","import_sii","import_effect","import_sii","import_effect","import_effect","listInvoices"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -6,6 +6,8 @@ import { Effect } from 'effect';
|
|
|
6
6
|
import { Invoice, IssueType, SiiEnv, DteType, PortalLoginOptions, SiiToken, PortalSession } from '@emisso/sii';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
|
|
9
|
+
declare const siiSchema: drizzle_orm_pg_core.PgSchema<"sii">;
|
|
10
|
+
|
|
9
11
|
declare const credentials: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
10
12
|
name: "credentials";
|
|
11
13
|
schema: "sii";
|
|
@@ -864,12 +866,6 @@ declare const syncJobs: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
864
866
|
type SyncJob = typeof syncJobs.$inferSelect;
|
|
865
867
|
type NewSyncJob = typeof syncJobs.$inferInsert;
|
|
866
868
|
|
|
867
|
-
/**
|
|
868
|
-
* @emisso/sii-api — Drizzle schema exports
|
|
869
|
-
* All tables live in the PostgreSQL `sii` schema.
|
|
870
|
-
*/
|
|
871
|
-
declare const siiSchema: drizzle_orm_pg_core.PgSchema<"sii">;
|
|
872
|
-
|
|
873
869
|
/**
|
|
874
870
|
* Application errors for Effect-based SII API logic.
|
|
875
871
|
* Uses Data.TaggedError which automatically sets `_tag` as the discriminator.
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ import { Effect } from 'effect';
|
|
|
6
6
|
import { Invoice, IssueType, SiiEnv, DteType, PortalLoginOptions, SiiToken, PortalSession } from '@emisso/sii';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
|
|
9
|
+
declare const siiSchema: drizzle_orm_pg_core.PgSchema<"sii">;
|
|
10
|
+
|
|
9
11
|
declare const credentials: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
10
12
|
name: "credentials";
|
|
11
13
|
schema: "sii";
|
|
@@ -864,12 +866,6 @@ declare const syncJobs: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
864
866
|
type SyncJob = typeof syncJobs.$inferSelect;
|
|
865
867
|
type NewSyncJob = typeof syncJobs.$inferInsert;
|
|
866
868
|
|
|
867
|
-
/**
|
|
868
|
-
* @emisso/sii-api — Drizzle schema exports
|
|
869
|
-
* All tables live in the PostgreSQL `sii` schema.
|
|
870
|
-
*/
|
|
871
|
-
declare const siiSchema: drizzle_orm_pg_core.PgSchema<"sii">;
|
|
872
|
-
|
|
873
869
|
/**
|
|
874
870
|
* Application errors for Effect-based SII API logic.
|
|
875
871
|
* Uses Data.TaggedError which automatically sets `_tag` as the discriminator.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
// src/db/schema/
|
|
1
|
+
// src/db/schema/sii-schema.ts
|
|
2
2
|
import { pgSchema } from "drizzle-orm/pg-core";
|
|
3
|
+
var siiSchema = pgSchema("sii");
|
|
3
4
|
|
|
4
5
|
// src/db/schema/credentials.ts
|
|
5
6
|
import {
|
|
@@ -126,9 +127,6 @@ var syncJobs = siiSchema.table("sync_jobs", {
|
|
|
126
127
|
createdAt: timestamp4("created_at").notNull().defaultNow()
|
|
127
128
|
});
|
|
128
129
|
|
|
129
|
-
// src/db/schema/index.ts
|
|
130
|
-
var siiSchema = pgSchema("sii");
|
|
131
|
-
|
|
132
130
|
// src/core/effect/app-error.ts
|
|
133
131
|
import { Data } from "effect";
|
|
134
132
|
var NotFoundError = class _NotFoundError extends Data.TaggedError("NotFoundError") {
|