@tailor-platform/sdk 2.36.0 → 2.37.0
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/CHANGELOG.md +72 -0
- package/dist/{application-DaJbleMi.mjs → application-83WVdH85.mjs} +1 -1
- package/dist/{application-BbORWCj-.mjs → application-Cida-j1g.mjs} +36 -36
- package/dist/application-Cida-j1g.mjs.map +1 -0
- package/dist/cli/commands/deploy/deploy.d.mts +6 -1
- package/dist/cli/commands/deploy/tailordb/migration-validation.d.mts +1 -0
- package/dist/cli/commands/executor/jobs.d.mts +3 -0
- package/dist/cli/commands/tailordb/migrate/bundler.d.mts +3 -0
- package/dist/cli/commands/tailordb/migrate/config.d.mts +4 -0
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +10 -0
- package/dist/cli/commands/tailordb/migrate/generate.d.mts +28 -2
- package/dist/cli/commands/tailordb/migrate/hints.d.mts +1 -0
- package/dist/cli/commands/tailordb/migrate/remote-state.d.mts +3 -0
- package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +3 -1
- package/dist/cli/commands/tailordb/migrate/snapshot-comparison.d.mts +4 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-files.d.mts +44 -6
- package/dist/cli/commands/tailordb/migrate/snapshot-local.d.mts +2 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-migrations.d.mts +2 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +8 -0
- package/dist/cli/commands/tailordb/migrate/types.d.mts +2 -0
- package/dist/cli/commands/workspace/create.d.mts +1 -1
- package/dist/cli/lib.d.mts +2 -2
- package/dist/cli/lib.mjs +1 -1
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.mjs +52 -51
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/shared/client.d.mts +26 -0
- package/dist/cli/shared/function-execution.d.mts +2 -0
- package/dist/cli/shared/prompt.d.mts +9 -4
- package/dist/completion/zsh-worker.zsh +21 -13
- package/dist/configure/config/index.d.mts +2 -0
- package/dist/configure/config/types.d.mts +2 -0
- package/dist/configure/index.mjs.map +1 -1
- package/dist/configure/services/tailordb/schema.d.mts +1 -0
- package/dist/configure/services/tailordb/types.d.mts +3 -0
- package/dist/crashreport-C2AcQNTe.mjs +1 -0
- package/dist/{crashreport-DGU6lwiX.mjs → crashreport-D_wf4GZh.mjs} +4 -4
- package/dist/{crashreport-DGU6lwiX.mjs.map → crashreport-D_wf4GZh.mjs.map} +1 -1
- package/dist/date-representation-Cr7W7Pn2.mjs.map +1 -1
- package/dist/{errors-BXmGBX-7.mjs → errors-Dmdnq0zi.mjs} +2 -2
- package/dist/errors-Dmdnq0zi.mjs.map +1 -0
- package/dist/{kysely-type-B0ri1-Xs.mjs → kysely-type-DVL90_oX.mjs} +6 -6
- package/dist/kysely-type-DVL90_oX.mjs.map +1 -0
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/builtin/seed/seed-type-processor.d.mts +4 -3
- package/dist/plugin/get-generated-table.d.mts +4 -0
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/plugin/types.d.mts +55 -3
- package/dist/plugin/with-context.d.mts +16 -0
- package/dist/register-ts-hook-Ht4zCseV.mjs +1115 -0
- package/dist/register-ts-hook-Ht4zCseV.mjs.map +1 -0
- package/dist/schema-BU1aIQ63.mjs.map +1 -1
- package/dist/{secret-file-BxZ-J_Nz.mjs → secret-file-DiuEcLFP.mjs} +2 -2
- package/dist/{secret-file-BxZ-J_Nz.mjs.map → secret-file-DiuEcLFP.mjs.map} +1 -1
- package/dist/service-CZ0EdD2-.mjs +10 -0
- package/dist/service-CZ0EdD2-.mjs.map +1 -0
- package/dist/service-DDrbdyd-.mjs +2 -0
- package/dist/{service-CaGmqg0r.mjs.map → service-DDrbdyd-.mjs.map} +1 -1
- package/dist/service-WhSyhaho.mjs +1 -0
- package/dist/service_pb-BMHhVot2.mjs +1 -0
- package/dist/service_pb-BxMSK0gg.mjs +2 -0
- package/dist/service_pb-BxMSK0gg.mjs.map +1 -0
- package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +3 -3
- package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +92 -0
- package/dist/tailor-proto/src/tailor/v1/notification_pb.d.mts +176 -0
- package/dist/tailor-proto/src/tailor/v1/notification_resource_pb.d.mts +172 -0
- package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +78 -0
- package/dist/types/app-config.generated.d.mts +1 -1
- package/dist/types/auth-connection.generated.d.mts +2 -2
- package/dist/types/auth.generated.d.mts +13 -13
- package/dist/types/executor.generated.d.mts +25 -25
- package/dist/types/field.generated.d.mts +2 -2
- package/dist/types/http-adapter.generated.d.mts +4 -4
- package/dist/types/idp.generated.d.mts +272 -272
- package/dist/types/resolver.generated.d.mts +10 -10
- package/dist/types/tailordb.generated.d.mts +84 -80
- package/dist/types/workflow.generated.d.mts +2 -2
- package/dist/vitest/date-representation.d.mts +2 -0
- package/dist/vitest/environment.d.mts +1 -0
- package/dist/vitest/environment.mjs.map +1 -1
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/migration-steps.d.mts +13 -2
- package/dist/vitest/mock-kysely.d.mts +12 -2
- package/dist/vitest/mocks/aigateway.d.mts +7 -1
- package/dist/vitest/mocks/authconnection.d.mts +7 -1
- package/dist/vitest/mocks/file.d.mts +8 -2
- package/dist/vitest/mocks/iconv.d.mts +7 -1
- package/dist/vitest/mocks/idp.d.mts +7 -1
- package/dist/vitest/mocks/logger.d.mts +7 -1
- package/dist/vitest/mocks/secretmanager.d.mts +7 -1
- package/dist/vitest/mocks/tailordb-pglite.d.mts +12 -2
- package/dist/vitest/mocks/tailordb.d.mts +22 -4
- package/dist/vitest/mocks/workflow.d.mts +2 -1
- package/dist/vitest/pglite-kysely.d.mts +18 -2
- package/dist/vitest/pglite-temporal.d.mts +5 -1
- package/dist/vitest/workflow-local.d.mts +7 -0
- package/dist/{workspace_resource_pb-C4CkoYww.mjs → workspace_resource_pb-7smKERdZ.mjs} +2 -2
- package/dist/workspace_resource_pb-7smKERdZ.mjs.map +1 -0
- package/docs/cli/application.md +51 -21
- package/docs/cli/executor.md +2 -0
- package/docs/cli/function.md +3 -1
- package/docs/cli/tailordb.md +30 -22
- package/docs/cli/workflow.md +2 -0
- package/docs/cli/workspace.md +19 -17
- package/docs/cli-reference.md +5 -4
- package/docs/configuration.md +2 -2
- package/docs/data-clone.md +1 -1
- package/docs/github-actions.md +104 -15
- package/docs/plugin/custom.md +4 -4
- package/docs/runtime.md +1 -1
- package/docs/services/auth.md +2 -0
- package/docs/services/idp.md +2 -0
- package/docs/services/tailordb/index.md +7 -2
- package/docs/services/tailordb/migration.md +71 -30
- package/docs/services/workflow.md +1 -1
- package/docs/testing.md +9 -9
- package/package.json +13 -13
- package/dist/application-BbORWCj-.mjs.map +0 -1
- package/dist/crashreport-WsYAWARW.mjs +0 -1
- package/dist/errors-BXmGBX-7.mjs.map +0 -1
- package/dist/kysely-type-B0ri1-Xs.mjs.map +0 -1
- package/dist/register-ts-hook-iAcG1dfz.mjs +0 -1057
- package/dist/register-ts-hook-iAcG1dfz.mjs.map +0 -1
- package/dist/service-CaGmqg0r.mjs +0 -2
- package/dist/service-DTrVVaDJ.mjs +0 -1
- package/dist/service-hIarp2Gl.mjs +0 -8
- package/dist/service-hIarp2Gl.mjs.map +0 -1
- package/dist/service_pb-6EkMfdOb.mjs +0 -2
- package/dist/service_pb-6EkMfdOb.mjs.map +0 -1
- package/dist/service_pb-CsJKokDl.mjs +0 -1
- package/dist/workspace_resource_pb-C4CkoYww.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kysely-type-DVL90_oX.mjs","names":["multiline","utf8","fieldType","name","hash","byte","value","suffix","tableName","memberName","kind","head","tag","body","base","field","pgType","label","CURRENT_TIME_EXPRESSIONS","currentTime","v","groups","format","conversion","fieldName","range","serial","SERIAL_CONVERSIONS","nextval","sequence","number","width","zeroPad","prefix","column","parts","hasDefault","filledOnCreate","key","here","path","child","CASTABLE_UNIQUE_TYPES","keys","member","indexed","table","reference","type","target","tables","targetField","check","_foreignKey","_type","_field","rest","byName","message","references","parentValue","DELETED_ROWS","source","condition","remaining","event","transition","tableIdentifier","options","t","sequences","ownerships","columns","constraintReferences","r","constraint","inline","indexes","index","names","created","ordered","deferred","pending","statements","constraints","group","statement","entries","namespaces","namespace","temporal","COLUMN_TYPE_ALIASES","a","b","usedUtilityTypes","allowedValues","fieldConfig","fields","fieldResults","config","result","aggregatedUtilityTypes","acc","fieldTypes","obj","hasOptionalFields","hasGeneratedFields","nested","baseTypeResult","isArray","isNullable","isColumnTypeBase","finalType","fieldLines","parsedField","namespaceData","globalUsedUtilityTypes","ns","utilityTypeImports","types","line","KyselyGeneratorID","DEFAULT_KYSELY_TYPES_DIST_PATH","ctx","pgliteSchemaPath","resolve","distPath","allNamespaceData","typeMetadataList","metadata","files","content"],"sources":["../src/utils/tailordb-ddl.ts","../src/plugin/builtin/kysely-type/pglite-schema.ts","../src/utils/field-column-type.ts","../src/plugin/builtin/kysely-type/type-processor.ts","../src/plugin/builtin/kysely-type/index.ts"],"sourcesContent":["/**\n * PostgreSQL DDL derived from TailorDB table definitions, for creating the\n * tables a PGlite-backed test needs. The columns match the flat shape the\n * Kysely type generators emit, not TailorDB's storage layout.\n */\n\n/** The field shape the DDL generator reads; parsed and snapshot field configs are both assignable. */\nexport interface DDLFieldConfig {\n type: string;\n required?: boolean;\n array?: boolean;\n unique?: boolean;\n serial?: { start: number; maxValue?: number; format?: string };\n scale?: number;\n default?: unknown;\n optionalOnCreate?: boolean;\n foreignKey?: boolean;\n foreignKeyType?: string;\n foreignKeyField?: string;\n hooks?: { create?: unknown; update?: unknown };\n fields?: Record<string, DDLFieldConfig>;\n}\n\n/** A table to emit DDL for. */\nexport interface DDLTableConfig {\n name: string;\n fields: Record<string, DDLFieldConfig>;\n indexes?: Record<string, { fields: string[]; unique?: boolean }>;\n}\n\nconst MAX_IDENTIFIER_BYTES = 63;\n// The platform rounds decimals to their scale (6 unless configured); numeric\n// needs a precision to carry a scale, and the maximum leaves it unconstrained.\nconst DECIMAL_PRECISION = 1000;\nconst DEFAULT_DECIMAL_SCALE = 6;\nconst utf8 = new TextEncoder();\n\n/**\n * Map a TailorDB field type to the PostgreSQL column type PGlite tests use for it.\n * @param fieldType - TailorDB field type name\n * @returns The PostgreSQL type name\n * @throws If the type is not a TailorDB field type\n */\nexport function mapFieldTypeToPostgresType(fieldType: string): string {\n switch (fieldType) {\n case \"uuid\":\n return \"uuid\";\n case \"string\":\n case \"enum\":\n return \"text\";\n case \"boolean\":\n case \"bool\":\n return \"boolean\";\n case \"integer\":\n return \"integer\";\n case \"float\":\n return \"double precision\";\n case \"decimal\":\n return \"numeric\";\n case \"date\":\n return \"date\";\n case \"datetime\":\n return \"timestamptz\";\n case \"time\":\n return \"time\";\n case \"nested\":\n return \"jsonb\";\n default:\n throw new Error(`Field type \"${fieldType}\" has no PostgreSQL column type.`);\n }\n}\n\nfunction identifier(name: string): string {\n return `\"${name.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction fnv1aHex(value: string): string {\n let hash = 0x811c9dc5;\n for (const byte of utf8.encode(value)) {\n hash = Math.imul(hash ^ byte, 0x01000193) >>> 0;\n }\n return hash.toString(16).padStart(8, \"0\");\n}\n\ntype DerivedNameKind = \"seq\" | \"idx\" | \"nested_idx\" | \"fk\";\n\nfunction derivedName(tableName: string, memberName: string, kind: DerivedNameKind): string {\n const suffix = `_${fnv1aHex(JSON.stringify([tableName, memberName, kind]))}_${kind}`;\n let head = `${tableName}_${memberName}`;\n while (utf8.encode(head + suffix).length > MAX_IDENTIFIER_BYTES) head = head.slice(0, -1);\n return head + suffix;\n}\n\nfunction derivedIdentifier(tableName: string, memberName: string, kind: DerivedNameKind): string {\n return identifier(derivedName(tableName, memberName, kind));\n}\n\nfunction dollarQuoted(body: string): string {\n let tag = \"$fk$\";\n while (body.includes(tag)) tag = `${tag.slice(0, -1)}_$`;\n return `${tag}\\n${body}\\n${tag}`;\n}\n\nfunction stringLiteral(value: string): string {\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nfunction columnType(field: DDLFieldConfig): string {\n const base =\n field.type === \"decimal\"\n ? `numeric(${DECIMAL_PRECISION}, ${field.scale ?? DEFAULT_DECIMAL_SCALE})`\n : mapFieldTypeToPostgresType(field.type);\n return field.array && field.type !== \"nested\" ? `${base}[]` : base;\n}\n\nfunction scalarLiteral(value: unknown, field: DDLFieldConfig, label: string): string {\n const pgType = mapFieldTypeToPostgresType(field.type);\n if (value instanceof Date) {\n if (Number.isNaN(value.getTime())) {\n throw new Error(`Default of field ${label} is an invalid Date.`);\n }\n return `${stringLiteral(value.toISOString())}::${pgType}`;\n }\n switch (typeof value) {\n case \"string\":\n return pgType === \"text\" ? stringLiteral(value) : `${stringLiteral(value)}::${pgType}`;\n case \"number\":\n if (!Number.isFinite(value)) {\n throw new Error(`Default of field ${label} is not a finite number.`);\n }\n return String(value);\n case \"boolean\":\n return value ? \"TRUE\" : \"FALSE\";\n default:\n throw new Error(`Default of field ${label} cannot be rendered as a SQL literal.`);\n }\n}\n\nconst CURRENT_TIME_EXPRESSIONS = new Map([\n [\"datetime\", \"now()\"],\n [\"date\", \"CURRENT_DATE\"],\n [\"time\", \"LOCALTIME\"],\n]);\n\nfunction defaultExpression(field: DDLFieldConfig, label: string): string {\n const value = field.default;\n const currentTime = CURRENT_TIME_EXPRESSIONS.get(field.type);\n if (value === \"now\" && currentTime !== undefined) {\n return currentTime;\n }\n if (field.array) {\n if (!Array.isArray(value)) {\n throw new Error(`Default of array field ${label} must be an array.`);\n }\n const pgType = columnType(field);\n if (value.length === 0) return `'{}'::${pgType}`;\n return `ARRAY[${value.map((v) => scalarLiteral(v, field, label)).join(\", \")}]::${pgType}`;\n }\n return scalarLiteral(value, field, label);\n}\n\ninterface SerialFormat {\n prefix: string;\n width: number;\n zeroPad: boolean;\n conversion: \"d\" | \"x\" | \"X\";\n suffix: string;\n}\n\n// printf-style with exactly one conversion specifier; octal has no Postgres\n// formatting function to stand in for it.\nfunction parseSerialFormat(format: string, label: string): SerialFormat {\n const match =\n /^(?<prefix>[^%]*)%(?<zero>0?)(?<width>\\d*)(?<conversion>[a-zA-Z])(?<suffix>[^%]*)$/.exec(\n format,\n );\n const groups = match?.groups;\n const conversion = groups?.conversion;\n if (!groups || (conversion !== \"d\" && conversion !== \"x\" && conversion !== \"X\")) {\n throw new Error(\n `Serial format \"${format}\" of field ${label} is not supported; use a single %d, %x, or %X specifier with an optional width (e.g. \"INV-%05d\").`,\n );\n }\n return {\n prefix: groups.prefix ?? \"\",\n zeroPad: groups.zero === \"0\",\n width: groups.width ? Number(groups.width) : 0,\n conversion,\n suffix: groups.suffix ?? \"\",\n };\n}\n\nfunction sequenceName(tableName: string, fieldName: string): string {\n return derivedIdentifier(tableName, fieldName, \"seq\");\n}\n\n// A sequence's minimum defaults to 1, which rejects a start of 0.\nfunction sequenceRange(serial: NonNullable<DDLFieldConfig[\"serial\"]>): string {\n const range = [`START WITH ${serial.start}`, `MINVALUE ${serial.start}`];\n if (serial.maxValue !== undefined) range.push(`MAXVALUE ${serial.maxValue}`);\n return range.join(\" \");\n}\n\nconst SERIAL_CONVERSIONS: Record<SerialFormat[\"conversion\"], (nextval: string) => string> = {\n d: (nextval) => nextval,\n x: (nextval) => `to_hex(${nextval})`,\n X: (nextval) => `upper(to_hex(${nextval}))`,\n};\n\nfunction serialStringDefault(sequence: string, format: string | undefined, label: string): string {\n const nextval = `nextval(${stringLiteral(sequence)})`;\n if (format === undefined) return `(${nextval}::text)`;\n const { prefix, width, zeroPad, conversion, suffix } = parseSerialFormat(format, label);\n const number = SERIAL_CONVERSIONS[conversion](nextval);\n let value = conversion === \"d\" ? `${number}::text` : number;\n if (width > 0) {\n value = `format('%${width}s', ${number})`;\n if (zeroPad) value = `translate(${value}, ' ', '0')`;\n }\n const parts = [\n ...(prefix ? [stringLiteral(prefix)] : []),\n value,\n ...(suffix ? [stringLiteral(suffix)] : []),\n ];\n return `(${parts.join(\" || \")})`;\n}\n\nfunction columnDefinition(tableName: string, fieldName: string, field: DDLFieldConfig): string {\n const column = identifier(fieldName);\n const label = `${identifier(tableName)}.${column}`;\n const parts = [column, columnType(field)];\n\n if (field.serial) {\n if (field.type === \"integer\") {\n parts.push(`GENERATED BY DEFAULT AS IDENTITY (${sequenceRange(field.serial)})`);\n if (field.unique) parts.push(\"UNIQUE\");\n return parts.join(\" \");\n }\n if (field.required) parts.push(\"NOT NULL\");\n if (field.unique) parts.push(\"UNIQUE\");\n parts.push(\n `DEFAULT ${serialStringDefault(sequenceName(tableName, fieldName), field.serial.format, label)}`,\n );\n return parts.join(\" \");\n }\n\n const hasDefault = field.default !== undefined;\n const filledOnCreate = field.hooks?.create !== undefined || field.optionalOnCreate === true;\n if (field.required && (hasDefault || !filledOnCreate)) parts.push(\"NOT NULL\");\n if (field.unique) parts.push(\"UNIQUE\");\n if (hasDefault) parts.push(`DEFAULT ${defaultExpression(field, label)}`);\n return parts.join(\" \");\n}\n\ninterface Reference {\n /** Column holding the reference */\n column: string;\n /** JSONPath from the column value to each referencing value; `$` for a scalar column */\n path: string;\n table: string;\n field: string;\n /** TailorDB type of the referencing value */\n type: string;\n}\n\nfunction jsonPathKey(key: string): string {\n return `\"${key.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll('\"', '\\\\\"')}\"`;\n}\n\nfunction referencesWithin(column: string, field: DDLFieldConfig, path: string): Reference[] {\n const here = field.array ? `${path}[*]` : path;\n if (field.type === \"nested\") {\n return Object.entries(field.fields ?? {}).flatMap(([key, child]) =>\n referencesWithin(column, child, `${here}.${jsonPathKey(key)}`),\n );\n }\n if (!field.foreignKey || field.foreignKeyType === undefined) return [];\n return [\n {\n column,\n path: here,\n table: field.foreignKeyType,\n field: field.foreignKeyField ?? \"id\",\n type: field.type,\n },\n ];\n}\n\n// The platform indexes a unique member of a nested object by the value at its\n// path, cast to the member's type. Members inside an array have no single value\n// to index, so they are left out.\nconst CASTABLE_UNIQUE_TYPES = new Set([\"integer\", \"float\", \"decimal\", \"boolean\", \"bool\", \"uuid\"]);\n\ninterface NestedUniqueMember {\n column: string;\n path: string[];\n field: DDLFieldConfig;\n}\n\nfunction nestedUniqueMembers(\n column: string,\n field: DDLFieldConfig,\n path: string[],\n): NestedUniqueMember[] {\n if (field.array) return [];\n if (field.type === \"nested\") {\n return Object.entries(field.fields ?? {}).flatMap(([key, child]) =>\n nestedUniqueMembers(column, child, [...path, key]),\n );\n }\n return field.unique && path.length > 0 ? [{ column, path, field }] : [];\n}\n\nfunction nestedUniqueIndex(tableName: string, member: NestedUniqueMember): string {\n const keys = member.path.map(stringLiteral).join(\", \");\n const value = `${identifier(member.column)} #>> ARRAY[${keys}]`;\n const indexed = CASTABLE_UNIQUE_TYPES.has(member.field.type)\n ? `CAST(${value} AS ${mapFieldTypeToPostgresType(member.field.type)})`\n : value;\n const name = derivedIdentifier(\n tableName,\n `${member.column}.${member.path.join(\".\")}`,\n \"nested_idx\",\n );\n return `CREATE UNIQUE INDEX IF NOT EXISTS ${name} ON ${identifier(tableName)} ((${indexed}))`;\n}\n\nfunction tableReferences(table: DDLTableConfig): Reference[] {\n return Object.entries(table.fields)\n .filter(([fieldName]) => fieldName !== \"id\")\n .flatMap(([fieldName, field]) => referencesWithin(fieldName, field, \"$\"));\n}\n\n// Postgres cannot reference from an array or jsonb column, so only a plain\n// column's reference becomes a FOREIGN KEY constraint.\nfunction isConstraintReference(reference: Reference): boolean {\n return reference.path === \"$\";\n}\n\nfunction referenceClause(reference: Reference): string {\n return `REFERENCES ${identifier(reference.table)} (${identifier(reference.field)})`;\n}\n\nfunction declaredType(type: string): string {\n return type === \"bool\" ? \"boolean\" : type;\n}\n\ntype ReferenceCheck = { pgType: string } | { problem: string };\n\nfunction checkReference(\n reference: Reference,\n tables: ReadonlyMap<string, DDLTableConfig>,\n): ReferenceCheck {\n const target = tables.get(reference.table);\n if (!target) return { problem: `references unknown table \"${reference.table}\".` };\n const targetField =\n reference.field === \"id\" ? { type: \"uuid\", unique: true } : target.fields[reference.field];\n if (!targetField) {\n return {\n problem: `references unknown field \"${reference.field}\" of table \"${reference.table}\".`,\n };\n }\n if (!targetField.unique || declaredType(targetField.type) !== declaredType(reference.type)) {\n return {\n problem: `references \"${reference.table}\".\"${reference.field}\", which must be unique and of the same type as the referencing field.`,\n };\n }\n return { pgType: mapFieldTypeToPostgresType(targetField.type) };\n}\n\nfunction referencedColumnType(\n reference: Reference,\n tables: ReadonlyMap<string, DDLTableConfig>,\n label: string,\n): string {\n const check = checkReference(reference, tables);\n if (\"problem\" in check) throw new Error(`Field ${label} ${check.problem}`);\n return check.pgType;\n}\n\n/**\n * The field without the relation it declares.\n * @param field - A field config\n * @returns The field with its foreign key settings removed\n */\nexport function withoutReference(field: DDLFieldConfig): DDLFieldConfig {\n const {\n foreignKey: _foreignKey,\n foreignKeyType: _type,\n foreignKeyField: _field,\n ...rest\n } = field;\n return rest;\n}\n\nfunction withoutUnresolvableReference(\n field: DDLFieldConfig,\n tables: ReadonlyMap<string, DDLTableConfig>,\n): DDLFieldConfig {\n if (field.fields) {\n return {\n ...field,\n fields: Object.fromEntries(\n Object.entries(field.fields).map(([name, child]) => [\n name,\n withoutUnresolvableReference(child, tables),\n ]),\n ),\n };\n }\n if (!field.foreignKey || field.foreignKeyType === undefined) return field;\n const reference = {\n column: \"\",\n path: \"$\",\n table: field.foreignKeyType,\n field: field.foreignKeyField ?? \"id\",\n type: field.type,\n };\n return \"problem\" in checkReference(reference, tables) ? withoutReference(field) : field;\n}\n\n/**\n * Remove the references the given tables cannot satisfy: a target table or\n * field that is missing, not unique, or of another type than the referencing\n * field. {@link generateSchemaDDL} rejects such references, so this lets a\n * schema that is only partly consistent still render, minus those references.\n * @param tables - Tables of one schema\n * @returns The tables, with unsatisfiable references removed from their fields\n */\nexport function dropUnresolvableReferences(tables: readonly DDLTableConfig[]): DDLTableConfig[] {\n const byName = new Map(tables.map((table) => [table.name, table]));\n return tables.map((table) => ({\n ...table,\n fields: Object.fromEntries(\n Object.entries(table.fields).map(([name, field]) => [\n name,\n withoutUnresolvableReference(field, byName),\n ]),\n ),\n }));\n}\n\nfunction referenceCheck(\n reference: Reference,\n tables: ReadonlyMap<string, DDLTableConfig>,\n label: string,\n): string {\n const pgType = referencedColumnType(reference, tables, label);\n const target = `${identifier(reference.table)}.${identifier(reference.field)}`;\n const message = `violates foreign key constraints: % not found in ${target.replaceAll(\"%\", \"%%\")}`;\n return [\n ` FOR v IN SELECT jsonb_path_query(to_jsonb(NEW.${identifier(reference.column)}), ${stringLiteral(reference.path)}) LOOP`,\n ` IF jsonb_typeof(fk_check.v) <> 'null' AND NOT EXISTS (SELECT 1 FROM ${identifier(reference.table)} AS parent WHERE parent.${identifier(reference.field)} = (fk_check.v #>> '{}')::${pgType}) THEN`,\n ` RAISE EXCEPTION ${stringLiteral(message)}, fk_check.v #>> '{}' USING ERRCODE = 'foreign_key_violation';`,\n \" END IF;\",\n \" END LOOP;\",\n ].join(\"\\n\");\n}\n\nfunction referenceTrigger(\n table: DDLTableConfig,\n references: readonly Reference[],\n tables: ReadonlyMap<string, DDLTableConfig>,\n): string[] {\n if (references.length === 0) return [];\n const name = derivedIdentifier(table.name, \"references\", \"fk\");\n const checks = references.map((reference) =>\n referenceCheck(reference, tables, `${table.name}.${reference.column}`),\n );\n const body = [\n \"<<fk_check>>\",\n \"DECLARE v jsonb;\",\n \"BEGIN\",\n ...checks,\n \" RETURN NULL;\",\n \"END\",\n ].join(\"\\n\");\n return [\n `CREATE OR REPLACE FUNCTION ${name}() RETURNS trigger LANGUAGE plpgsql AS ${dollarQuoted(body)}`,\n `CREATE OR REPLACE TRIGGER ${name} AFTER INSERT OR UPDATE ON ${identifier(table.name)} FOR EACH ROW EXECUTE FUNCTION ${name}()`,\n ];\n}\n\ninterface IncomingReference extends Reference {\n /** Table whose array or nested column holds the reference */\n child: string;\n pgType: string;\n}\n\nfunction incomingReferences(\n table: DDLTableConfig,\n tables: ReadonlyMap<string, DDLTableConfig>,\n): IncomingReference[] {\n return [...tables.values()].flatMap((child) =>\n tableReferences(child)\n .filter((reference) => !isConstraintReference(reference) && reference.table === table.name)\n .flatMap((reference) => {\n const check = checkReference(reference, tables);\n return \"pgType\" in check ? [{ ...reference, child: child.name, pgType: check.pgType }] : [];\n }),\n );\n}\n\nfunction holdsParent(reference: IncomingReference): string {\n const column = `child.${identifier(reference.column)}`;\n const parentValue = `OLD.${identifier(reference.field)}`;\n if (reference.path === \"$[*]\") return `${parentValue} = ANY(${column})`;\n return `EXISTS (SELECT 1 FROM jsonb_path_query(to_jsonb(${column}), ${stringLiteral(reference.path)}) AS held(v) WHERE CASE WHEN jsonb_typeof(held.v) = 'null' THEN false WHEN NOT pg_input_is_valid(held.v #>> '{}', ${stringLiteral(reference.pgType)}) THEN false ELSE (held.v #>> '{}')::${reference.pgType} = ${parentValue} END)`;\n}\n\nconst DELETED_ROWS = \"old_rows\";\n\nfunction holds(reference: IncomingReference, source: string): string {\n return `EXISTS (SELECT 1 FROM ${source} AS child WHERE ${holdsParent(reference)})`;\n}\n\nfunction refuseWhen(\n table: DDLTableConfig,\n reference: IncomingReference,\n condition: string,\n): string {\n const message = `update or delete on table \\`${table.name}\\` violates foreign key constraint: some record is still referenced from table \\`${reference.child}\\``;\n return [\n ` IF ${condition} THEN`,\n ` RAISE EXCEPTION ${stringLiteral(message.replaceAll(\"%\", \"%%\"))} USING ERRCODE = 'foreign_key_violation';`,\n \" END IF;\",\n ].join(\"\\n\");\n}\n\nfunction referencedDeleteCheck(table: DDLTableConfig, reference: IncomingReference): string {\n const remaining = holds(reference, identifier(reference.child));\n const condition =\n reference.child === table.name\n ? `${remaining} OR ${holds(reference, DELETED_ROWS)}`\n : remaining;\n return refuseWhen(table, reference, condition);\n}\n\nfunction referencedUpdateCheck(table: DDLTableConfig, reference: IncomingReference): string {\n const field = identifier(reference.field);\n return refuseWhen(\n table,\n reference,\n `NEW.${field} IS DISTINCT FROM OLD.${field} AND ${holds(reference, identifier(reference.child))}`,\n );\n}\n\nfunction referencedTrigger(\n table: DDLTableConfig,\n tables: ReadonlyMap<string, DDLTableConfig>,\n): string[] {\n const references = incomingReferences(table, tables);\n if (references.length === 0) return [];\n const selfReferencing = references.some((reference) => reference.child === table.name);\n const deletedRows = selfReferencing ? ` REFERENCING OLD TABLE AS ${DELETED_ROWS}` : \"\";\n return (\n [\n [\"referenced_delete\", \"DELETE\", deletedRows, referencedDeleteCheck],\n [\"referenced_update\", \"UPDATE\", \"\", referencedUpdateCheck],\n ] as const\n ).flatMap(([member, event, transition, check]) => {\n const name = derivedIdentifier(table.name, member, \"fk\");\n const body = [\n \"BEGIN\",\n ...references.map((reference) => check(table, reference)),\n \" RETURN NULL;\",\n \"END\",\n ].join(\"\\n\");\n return [\n `CREATE OR REPLACE FUNCTION ${name}() RETURNS trigger LANGUAGE plpgsql AS ${dollarQuoted(body)}`,\n `CREATE OR REPLACE TRIGGER ${name} AFTER ${event} ON ${identifier(table.name)}${transition} FOR EACH ROW EXECUTE FUNCTION ${name}()`,\n ];\n });\n}\n\n/** What {@link generateTableDDL} needs to know about the other tables of the schema. */\nexport interface TableDDLOptions {\n /** Every table of the schema, to resolve the types referenced columns point at */\n tables?: readonly DDLTableConfig[];\n /** Columns whose FOREIGN KEY is added after all tables exist, because the target is created later */\n deferredReferences?: ReadonlySet<string>;\n}\n\n/**\n * DDL statements that create one table: any sequences its string serial\n * fields draw from, the table, the sequences' ownership of their columns,\n * its unique indexes, then the triggers that enforce the references Postgres\n * cannot express as a FOREIGN KEY (inside array and nested columns): one\n * checking the references the table holds, one refusing to delete a row, and\n * one refusing to change the key of a row, that another table's array or\n * nested value still points at. Every statement\n * is `IF NOT EXISTS` or otherwise idempotent, so re-applying the script on a\n * database that already has the table is a no-op. Owning a sequence makes\n * `DROP TABLE` drop it and `TRUNCATE ... RESTART IDENTITY` reset it to the\n * configured start. Index names end in `_idx` so they cannot take the\n * `<table>_<column>_key` name Postgres gives a UNIQUE column, which\n * `IF NOT EXISTS` would otherwise silently skip.\n * @param table - Table name, fields, and indexes\n * @param options - The schema's other tables, and references to leave to later statements\n * @returns Statements in execution order, without trailing semicolons\n * @throws If a field type, default, or serial format cannot be expressed\n */\nexport function generateTableDDL(table: DDLTableConfig, options: TableDDLOptions = {}): string[] {\n const tableIdentifier = identifier(table.name);\n const tables = new Map((options.tables ?? [table]).map((t) => [t.name, t]));\n const sequences: string[] = [];\n const ownerships: string[] = [];\n const columns = [` \"id\" uuid PRIMARY KEY DEFAULT gen_random_uuid()`];\n const references = tableReferences(table);\n const constraintReferences = new Map(\n references.filter(isConstraintReference).map((r) => [r.column, r]),\n );\n\n for (const [fieldName, field] of Object.entries(table.fields)) {\n if (fieldName === \"id\") continue;\n if (field.serial && field.type !== \"integer\") {\n const sequence = sequenceName(table.name, fieldName);\n sequences.push(`CREATE SEQUENCE IF NOT EXISTS ${sequence} ${sequenceRange(field.serial)}`);\n ownerships.push(\n `ALTER SEQUENCE ${sequence} OWNED BY ${tableIdentifier}.${identifier(fieldName)}`,\n );\n }\n const constraint = constraintReferences.get(fieldName);\n const inline =\n constraint && !options.deferredReferences?.has(fieldName)\n ? ` ${referenceClause(constraint)}`\n : \"\";\n columns.push(` ${columnDefinition(table.name, fieldName, field)}${inline}`);\n }\n\n const indexes = [\n ...Object.entries(table.indexes ?? {})\n .filter(([, index]) => index.unique)\n .map(\n ([name, index]) =>\n `CREATE UNIQUE INDEX IF NOT EXISTS ${derivedIdentifier(table.name, name, \"idx\")} ON ${tableIdentifier} (${index.fields.map(identifier).join(\", \")})`,\n ),\n ...Object.entries(table.fields)\n .filter(([fieldName]) => fieldName !== \"id\")\n .flatMap(([fieldName, field]) => nestedUniqueMembers(fieldName, field, []))\n .map((member) => nestedUniqueIndex(table.name, member)),\n ];\n\n for (const reference of constraintReferences.values()) {\n referencedColumnType(reference, tables, `${table.name}.${reference.column}`);\n }\n\n return [\n ...sequences,\n `CREATE TABLE IF NOT EXISTS ${tableIdentifier} (\\n${columns.join(\",\\n\")}\\n)`,\n ...ownerships,\n ...indexes,\n ...referenceTrigger(\n table,\n references.filter((r) => !isConstraintReference(r)),\n tables,\n ),\n ...referencedTrigger(table, tables),\n ];\n}\n\nfunction addForeignKey(table: DDLTableConfig, reference: Reference): string {\n const name = derivedName(table.name, reference.column, \"fk\");\n const tableIdentifier = identifier(table.name);\n const body = [\n \"BEGIN\",\n `IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = ${stringLiteral(name)} AND conrelid = ${stringLiteral(tableIdentifier)}::regclass) THEN`,\n `ALTER TABLE ${tableIdentifier} ADD CONSTRAINT ${identifier(name)} FOREIGN KEY (${identifier(reference.column)}) ${referenceClause(reference)};`,\n \"END IF;\",\n \"END\",\n ].join(\"\\n\");\n return `DO ${dollarQuoted(body)}`;\n}\n\n// Tables come after the tables they reference. Where references form a cycle,\n// the first table of the cycle is created without the constraint that points\n// at a table not yet created, and the constraint is added once all tables exist.\nfunction planCreation(tables: readonly DDLTableConfig[]): {\n ordered: DDLTableConfig[];\n deferred: Map<DDLTableConfig, Reference[]>;\n} {\n const names = new Set(tables.map((table) => table.name));\n const created = new Set<string>();\n const remaining = [...tables];\n const ordered: DDLTableConfig[] = [];\n const deferred = new Map<DDLTableConfig, Reference[]>();\n const pendingOf = (table: DDLTableConfig) =>\n tableReferences(table)\n .filter(isConstraintReference)\n .filter((r) => names.has(r.table) && r.table !== table.name && !created.has(r.table));\n while (remaining.length > 0) {\n const index = remaining.findIndex((table) => pendingOf(table).length === 0);\n const [table] = remaining.splice(Math.max(index, 0), 1) as [DDLTableConfig];\n const pending = pendingOf(table);\n if (pending.length > 0) deferred.set(table, pending);\n created.add(table.name);\n ordered.push(table);\n }\n return { ordered, deferred };\n}\n\n/**\n * A single SQL script creating every given table, for `pglite.exec()`. Tables\n * are created after the tables they reference.\n * @param tables - Tables to create\n * @returns The script, empty when there are no tables\n * @throws If a field references a table or field that is not among the tables\n */\nexport function generateSchemaDDL(tables: readonly DDLTableConfig[]): string {\n const { ordered, deferred } = planCreation(tables);\n const statements = ordered.map((table) =>\n generateTableDDL(table, {\n tables,\n deferredReferences: new Set(deferred.get(table)?.map((r) => r.column)),\n }),\n );\n const constraints = ordered.flatMap((table) =>\n (deferred.get(table) ?? []).map((reference) => addForeignKey(table, reference)),\n );\n return [...statements, constraints]\n .filter((group) => group.length > 0)\n .map((group) => group.map((statement) => `${statement};`).join(\"\\n\"))\n .join(\"\\n\\n\");\n}\n\n/** One namespace's tables, as the schema module groups them. */\nexport interface PgliteSchemaNamespace {\n namespace: string;\n tables: readonly DDLTableConfig[];\n}\n\n/** Options for {@link generatePgliteSchemaModule}. */\nexport interface PgliteSchemaModuleOptions {\n /** Named in the generated header as the producer users must not edit around. */\n generatedBy: string;\n}\n\n// A template literal keeps line feeds but folds a carriage return into one.\nfunction templateLiteral(value: string): string {\n const escaped = value\n .replaceAll(\"\\\\\", \"\\\\\\\\\")\n .replaceAll(\"`\", \"\\\\`\")\n .replaceAll(\"${\", \"\\\\${\")\n .replaceAll(\"\\r\", \"\\\\r\");\n return `\\`${escaped}\\``;\n}\n\n/**\n * Render the module that exports each namespace's `CREATE TABLE` script for\n * `pglite.exec()`.\n * @param namespaces - Namespaces with the tables to create\n * @param options - Header wording\n * @returns TypeScript source of the schema module\n */\nexport function generatePgliteSchemaModule(\n namespaces: readonly PgliteSchemaNamespace[],\n options: PgliteSchemaModuleOptions,\n): string {\n const entries = namespaces.map(\n ({ namespace, tables }) =>\n ` ${JSON.stringify(namespace)}: ${templateLiteral(generateSchemaDDL(tables))},`,\n );\n return [\n \"/**\",\n \" * Auto-generated PGlite schema for TailorDB tables.\",\n \" * Create a namespace's tables in a test with `pglite.exec(pgliteSchema[namespace])`.\",\n \" *\",\n ` * DO NOT EDIT - This file is auto-generated by ${options.generatedBy}.`,\n \" */\",\n \"\",\n \"export const pgliteSchema = {\",\n ...entries,\n \"} as const;\",\n \"\",\n ].join(\"\\n\");\n}\n","import { generatePgliteSchemaModule, type DDLTableConfig } from \"#/utils/tailordb-ddl\";\nimport type { TailorDBType } from \"#/parser/service/tailordb/types\";\n\n/** Tables of one namespace, as the schema module groups them. */\nexport interface PGliteSchemaNamespace {\n namespace: string;\n tables: Record<string, TailorDBType>;\n}\n\n/**\n * Reduce parsed tables to what the DDL generator reads.\n * @param tables - Parsed TailorDB tables keyed by name\n * @returns DDL table configs in the same order\n */\nexport function toDDLTables(tables: Record<string, TailorDBType>): DDLTableConfig[] {\n return Object.values(tables).map((type) => ({\n name: type.name,\n fields: Object.fromEntries(\n Object.entries(type.fields).map(([fieldName, field]) => [fieldName, field.config]),\n ),\n indexes: type.indexes,\n }));\n}\n\n/**\n * Render the module that exports each namespace's `CREATE TABLE` script for\n * `pglite.exec()`.\n * @param namespaces - Namespaces with their parsed tables\n * @returns TypeScript source of the schema module\n */\nexport function generatePGliteSchemaModule(namespaces: readonly PGliteSchemaNamespace[]): string {\n return generatePgliteSchemaModule(\n namespaces.map(({ namespace, tables }) => ({ namespace, tables: toDDLTables(tables) })),\n { generatedBy: \"the kysely-type plugin\" },\n );\n}\n","/** The Kysely column type a TailorDB field maps to, before array/null modifiers. */\nexport type FieldColumnType =\n | \"string\"\n | \"number\"\n | \"boolean\"\n | \"Timestamp\"\n | \"TemporalDate\"\n | \"TemporalInstant\"\n | \"TemporalTime\";\n\n/**\n * Map a scalar TailorDB field type to the column type generated code uses for it.\n *\n * With `temporal: false` (the default), `date`/`datetime` resolve to `Timestamp` and\n * `time` to `string`, because that's what the function runtime hands back for them by\n * default. With `temporal: true`, `date`/`datetime`/`time` resolve to their\n * `Temporal.PlainDate`/`Temporal.Instant`/`Temporal.PlainTime` counterparts instead,\n * matching a `getDB` created with `createGetDB({ temporal: true })`.\n *\n * `enum` and `nested` carry their own shape, so each generator resolves them\n * before reaching here; passing either is a caller bug rather than a `string`\n * column.\n * @param fieldType - TailorDB scalar field type name\n * @param temporal - Whether to map date/datetime/time fields to their Temporal column\n * types instead of their `Date`/`string` defaults\n * @returns The column type for the field, defaulting to `string`\n * @throws If given `enum` or `nested`\n */\nexport function mapFieldTypeToColumnType(fieldType: string, temporal = false): FieldColumnType {\n switch (fieldType) {\n case \"uuid\":\n case \"string\":\n case \"decimal\":\n return \"string\";\n case \"integer\":\n case \"float\":\n return \"number\";\n case \"date\":\n return temporal ? \"TemporalDate\" : \"Timestamp\";\n case \"datetime\":\n return temporal ? \"TemporalInstant\" : \"Timestamp\";\n case \"time\":\n return temporal ? \"TemporalTime\" : \"string\";\n case \"bool\":\n case \"boolean\":\n return \"boolean\";\n case \"enum\":\n case \"nested\":\n throw new Error(\n `Field type \"${fieldType}\" has no scalar column type; resolve it before mapping.`,\n );\n default:\n return \"string\";\n }\n}\n\n/** The select and write types a `ColumnType`-shaped alias expands to. */\nexport type ColumnTypeAliasExpansion = {\n /** Type the alias reads back as. */\n readonly select: string;\n /** Type the alias accepts on insert and update. */\n readonly write: string;\n};\n\n/**\n * Column types whose alias expands to a `ColumnType`, mapped to that expansion.\n *\n * Kysely only unwraps a `ColumnType` at the top level of a table property, so an\n * array of one of these stays wrapped in `ArrayColumnType<...>` rather than taking\n * a `[]` suffix, which would nest the `ColumnType` out of Kysely's reach. Where a\n * generator has to spell out the slots itself, it reads the expansion from here\n * rather than inlining the alias, which would nest just the same.\n *\n * Both type generators track alias usage per alias to decide which declarations to\n * emit, so adding an entry here also means teaching them to report the new alias.\n */\nexport const COLUMN_TYPE_ALIASES: ReadonlyMap<string, ColumnTypeAliasExpansion> = new Map<\n FieldColumnType,\n ColumnTypeAliasExpansion\n>([\n [\"Timestamp\", { select: \"Date\", write: \"Date | string\" }],\n [\"TemporalDate\", { select: \"Temporal.PlainDate\", write: \"Temporal.PlainDate | string\" }],\n [\"TemporalInstant\", { select: \"Temporal.Instant\", write: \"Temporal.Instant | string\" }],\n [\"TemporalTime\", { select: \"Temporal.PlainTime\", write: \"Temporal.PlainTime | string\" }],\n]);\n","import { COLUMN_TYPE_ALIASES, mapFieldTypeToColumnType } from \"#/utils/field-column-type\";\nimport multiline from \"#/utils/multiline\";\nimport {\n type KyselyFieldConfig,\n type KyselyNamespaceMetadata,\n type KyselyTypeMetadata,\n type UsedUtilityTypes,\n} from \"./types\";\nimport type { TailorDBType } from \"#/parser/service/tailordb/types\";\n\ntype FieldTypeResult = {\n type: string;\n usedUtilityTypes: UsedUtilityTypes;\n};\n\nfunction emptyUsedUtilityTypes(): UsedUtilityTypes {\n return {\n Timestamp: false,\n TemporalDate: false,\n TemporalInstant: false,\n TemporalTime: false,\n Serial: false,\n ObjectColumnType: false,\n ArrayColumnType: false,\n };\n}\n\nfunction mergeUsedUtilityTypes(a: UsedUtilityTypes, b: UsedUtilityTypes): UsedUtilityTypes {\n return {\n Timestamp: a.Timestamp || b.Timestamp,\n TemporalDate: a.TemporalDate || b.TemporalDate,\n TemporalInstant: a.TemporalInstant || b.TemporalInstant,\n TemporalTime: a.TemporalTime || b.TemporalTime,\n Serial: a.Serial || b.Serial,\n ObjectColumnType: a.ObjectColumnType || b.ObjectColumnType,\n ArrayColumnType: a.ArrayColumnType || b.ArrayColumnType,\n };\n}\n\n/**\n * Whether a utility-type usage record uses any `ColumnType`-shaped alias.\n * @param usedUtilityTypes - Utility-type usage record to check\n * @returns Whether any `ColumnType`-shaped alias is used\n */\nfunction usesColumnTypeAlias(usedUtilityTypes: UsedUtilityTypes): boolean {\n return (\n usedUtilityTypes.Timestamp ||\n usedUtilityTypes.TemporalDate ||\n usedUtilityTypes.TemporalInstant ||\n usedUtilityTypes.TemporalTime\n );\n}\n\n/**\n * Get the enum type definition.\n * @param fieldConfig - The field configuration\n * @returns The enum type as a string union\n */\nfunction getEnumType(fieldConfig: KyselyFieldConfig): string {\n const allowedValues = fieldConfig.allowedValues;\n\n if (allowedValues && Array.isArray(allowedValues)) {\n return allowedValues\n .map((v: string | { value: string }) => {\n const value = typeof v === \"string\" ? v : v.value;\n return `\"${value}\"`;\n })\n .join(\" | \");\n }\n return \"string\";\n}\n\n/**\n * Get the nested object type definition.\n * @param fieldConfig - The field configuration\n * @param temporal - Whether date/datetime/time fields resolve to their Temporal column\n * types instead of their `Date`/`string` defaults\n * @returns The nested type with used utility types\n */\nfunction getNestedType(fieldConfig: KyselyFieldConfig, temporal: boolean): FieldTypeResult {\n const fields = fieldConfig.fields;\n if (!fields || typeof fields !== \"object\") {\n return {\n type: \"string\",\n usedUtilityTypes: emptyUsedUtilityTypes(),\n };\n }\n\n const fieldResults = Object.entries(fields).map(([fieldName, config]) => {\n const result = generateFieldType(config, temporal, true);\n const optional = config.required !== true ? \"?\" : \"\";\n return {\n fieldType: `${fieldName}${optional}: ${result.type}`,\n usedUtilityTypes: result.usedUtilityTypes,\n };\n });\n\n const aggregatedUtilityTypes = fieldResults.reduce(\n (acc, result) => mergeUsedUtilityTypes(acc, result.usedUtilityTypes),\n emptyUsedUtilityTypes(),\n );\n\n const fieldTypes = fieldResults.map((r) => r.fieldType);\n const obj = `{\\n ${fieldTypes.join(\";\\n \")}${fieldTypes.length > 0 ? \";\" : \"\"}\\n}`;\n\n const hasOptionalFields = Object.values(fields).some((config) => config.required !== true);\n const hasGeneratedFields = Object.values(fields).some(\n (config) =>\n config.hooks?.create || config.default !== undefined || config.optionalOnCreate === true,\n );\n if (usesColumnTypeAlias(aggregatedUtilityTypes) || hasOptionalFields || hasGeneratedFields) {\n return {\n type: `ObjectColumnType<${obj}>`,\n usedUtilityTypes: { ...aggregatedUtilityTypes, ObjectColumnType: true },\n };\n }\n return { type: obj, usedUtilityTypes: aggregatedUtilityTypes };\n}\n\n/**\n * Get the base Kysely type for a field (without array/null modifiers).\n * @param fieldConfig - The field configuration\n * @param temporal - Whether date/datetime/time fields resolve to their Temporal column\n * types instead of their `Date`/`string` defaults\n * @param nested - Whether the field is inside an object\n * @returns The base type with used utility types\n */\nfunction getBaseType(\n fieldConfig: KyselyFieldConfig,\n temporal: boolean,\n nested: boolean,\n): FieldTypeResult {\n const fieldType = fieldConfig.type;\n const usedUtilityTypes = emptyUsedUtilityTypes();\n\n if (fieldType === \"enum\") {\n return { type: getEnumType(fieldConfig), usedUtilityTypes };\n }\n if (fieldType === \"nested\") {\n return getNestedType(fieldConfig, temporal);\n }\n\n const type = mapFieldTypeToColumnType(fieldType, temporal && !(nested && fieldType === \"time\"));\n switch (type) {\n case \"Timestamp\":\n usedUtilityTypes.Timestamp = true;\n break;\n case \"TemporalDate\":\n usedUtilityTypes.TemporalDate = true;\n break;\n case \"TemporalInstant\":\n usedUtilityTypes.TemporalInstant = true;\n break;\n case \"TemporalTime\":\n usedUtilityTypes.TemporalTime = true;\n break;\n case \"string\":\n case \"number\":\n case \"boolean\":\n break;\n }\n\n return { type, usedUtilityTypes };\n}\n\n/**\n * Generate the complete field type including array and null modifiers.\n * @param fieldConfig - The field configuration\n * @param temporal - Whether date/datetime/time fields resolve to their Temporal column\n * types instead of their `Date`/`string` defaults\n * @param nested - Whether the field is inside an object\n * @returns The complete field type with used utility types\n */\nfunction generateFieldType(\n fieldConfig: KyselyFieldConfig,\n temporal: boolean,\n nested = false,\n): FieldTypeResult {\n const baseTypeResult = getBaseType(fieldConfig, temporal, nested);\n const usedUtilityTypes = { ...baseTypeResult.usedUtilityTypes };\n\n const isArray = fieldConfig.array === true;\n const isNullable = fieldConfig.required !== true;\n\n // A ColumnType-shaped alias and ObjectColumnType cannot be wrapped with [] for\n // arrays, because Kysely only resolves ColumnType at the top-level table\n // property. Use ArrayColumnType to keep the ColumnType at the top level.\n const isColumnTypeBase = COLUMN_TYPE_ALIASES.has(baseTypeResult.type);\n\n let finalType = baseTypeResult.type;\n if (isArray) {\n if (isColumnTypeBase || finalType.startsWith(\"ObjectColumnType<\")) {\n finalType = `ArrayColumnType<${baseTypeResult.type}>`;\n usedUtilityTypes.ArrayColumnType = true;\n } else {\n const needsParens = fieldConfig.type === \"enum\";\n finalType = needsParens ? `(${baseTypeResult.type})[]` : `${baseTypeResult.type}[]`;\n }\n }\n if (isNullable) {\n finalType = `${finalType} | null`;\n }\n\n if (fieldConfig.serial) {\n usedUtilityTypes.Serial = true;\n finalType = `Serial<${finalType}>`;\n }\n if (\n fieldConfig.hooks?.create ||\n fieldConfig.default !== undefined ||\n fieldConfig.optionalOnCreate === true\n ) {\n finalType = `Generated<${finalType}>`;\n }\n\n return { type: finalType, usedUtilityTypes };\n}\n\n/**\n * Generate the table interface.\n * @param name - Table name\n * @param fields - Field configurations keyed by field name\n * @param temporal - Whether date/datetime/time fields resolve to their Temporal column\n * types instead of their `Date`/`string` defaults\n * @returns The type definition and used utility types\n */\nfunction generateTableInterface(\n name: string,\n fields: Record<string, KyselyFieldConfig>,\n temporal: boolean,\n): {\n typeDef: string;\n usedUtilityTypes: UsedUtilityTypes;\n} {\n const fieldEntries = Object.entries(fields).filter(([fieldName]) => fieldName !== \"id\");\n\n const fieldResults = fieldEntries.map(([fieldName, fieldConfig]) => ({\n fieldName,\n ...generateFieldType(fieldConfig, temporal),\n }));\n\n const fieldLines = [\n \"id: Generated<string>;\",\n ...fieldResults.map((result) => `${result.fieldName}: ${result.type};`),\n ];\n\n const aggregatedUtilityTypes = fieldResults.reduce(\n (acc, result) => mergeUsedUtilityTypes(acc, result.usedUtilityTypes),\n emptyUsedUtilityTypes(),\n );\n\n const typeDef = multiline /* ts */ `\n ${name}: {\n ${fieldLines.join(\"\\n\")}\n }\n `;\n\n return { typeDef, usedUtilityTypes: aggregatedUtilityTypes };\n}\n\n/**\n * Generate KyselyTypeMetadata from field configurations.\n * @param name - Table name\n * @param fields - Field configurations keyed by field name\n * @param temporal - Whether date/datetime/time fields resolve to their Temporal column\n * types instead of their `Date`/`string` defaults. Defaults to `false`.\n * @returns Generated Kysely type metadata\n */\nexport function processKyselyFields(\n name: string,\n fields: Record<string, KyselyFieldConfig>,\n temporal = false,\n): KyselyTypeMetadata {\n const result = generateTableInterface(name, fields, temporal);\n\n return {\n name,\n typeDef: result.typeDef,\n usedUtilityTypes: result.usedUtilityTypes,\n };\n}\n\n/**\n * Convert a TailorDBType into KyselyTypeMetadata.\n * @param type - Parsed TailorDB table\n * @param temporal - Whether date/datetime/time fields resolve to their Temporal column\n * types instead of their `Date`/`string` defaults. Defaults to `false`.\n * @returns Generated Kysely type metadata\n */\nexport async function processKyselyType(\n type: TailorDBType,\n temporal = false,\n): Promise<KyselyTypeMetadata> {\n return processKyselyFields(\n type.name,\n Object.fromEntries(\n Object.entries(type.fields).map(([fieldName, parsedField]) => [\n fieldName,\n parsedField.config,\n ]),\n ),\n temporal,\n );\n}\n\n/**\n * Generate unified types file from multiple namespaces.\n * @param namespaceData - Namespace metadata\n * @param temporal - Whether `kyselyTypePlugin` was configured with `{ temporal: true }`;\n * passed to `createGetDB` so the generated `getDB` always reads back the Temporal values\n * the tables above are typed with. Defaults to `false`.\n * @returns Generated types file contents\n */\nexport function generateUnifiedKyselyTypes(\n namespaceData: KyselyNamespaceMetadata[],\n temporal = false,\n): string {\n if (namespaceData.length === 0) {\n return \"\";\n }\n\n // Aggregate used utility types from all namespaces\n const globalUsedUtilityTypes = namespaceData\n .flatMap((ns) => ns.types)\n .reduce(\n (acc, type) => mergeUsedUtilityTypes(acc, type.usedUtilityTypes),\n emptyUsedUtilityTypes(),\n );\n\n const utilityTypeImports: string[] = [\"type Generated\"];\n if (globalUsedUtilityTypes.Timestamp) {\n utilityTypeImports.push(\"type Timestamp\");\n }\n if (globalUsedUtilityTypes.TemporalDate) {\n utilityTypeImports.push(\"type TemporalDate\");\n }\n if (globalUsedUtilityTypes.TemporalInstant) {\n utilityTypeImports.push(\"type TemporalInstant\");\n }\n if (globalUsedUtilityTypes.TemporalTime) {\n utilityTypeImports.push(\"type TemporalTime\");\n }\n if (globalUsedUtilityTypes.ObjectColumnType) {\n utilityTypeImports.push(\"type ObjectColumnType\");\n }\n if (globalUsedUtilityTypes.ArrayColumnType) {\n utilityTypeImports.push(\"type ArrayColumnType\");\n }\n if (globalUsedUtilityTypes.Serial) {\n utilityTypeImports.push(\"type Serial\");\n }\n\n const importsSection = multiline /* ts */ `\n import {\n createGetDB,\n ${utilityTypeImports.join(\",\\n\")},\n type NamespaceDB,\n type NamespaceInsertable,\n type NamespaceSelectable,\n type NamespaceTable,\n type NamespaceTableName,\n type NamespaceTransaction,\n type NamespaceUpdateable,\n } from \"@tailor-platform/sdk/kysely\";\n `;\n\n // Generate Namespace interface with multiple namespaces\n const namespaceInterfaces = namespaceData\n .map(({ namespace, types }) => {\n const typeDefsWithIndent = types\n .map((type) => {\n return type.typeDef\n .split(\"\\n\")\n .map((line) => (line.trim() ? ` ${line}` : \"\"))\n .join(\"\\n\");\n })\n .join(\"\\n\\n\");\n\n return ` \"${namespace}\": {\\n${typeDefsWithIndent}\\n }`;\n })\n .join(\",\\n\");\n\n const namespaceInterface = `export interface Namespace {\\n${namespaceInterfaces}\\n}`;\n\n const getDBFunction = multiline /* ts */ `\n export const getDB = createGetDB<Namespace>(${temporal ? \"{ temporal: true }\" : \"\"});\n\n export type DB<N extends keyof Namespace = keyof Namespace> = NamespaceDB<Namespace, N>;\n `;\n\n const utilityTypeExports = multiline /* ts */ `\n export type Transaction<K extends keyof Namespace | DB = keyof Namespace> =\n NamespaceTransaction<Namespace, K>;\n\n type TableName = NamespaceTableName<Namespace>;\n export type Table<T extends TableName> = NamespaceTable<Namespace, T>;\n\n export type Insertable<T extends TableName> = NamespaceInsertable<Namespace, T>;\n export type Selectable<T extends TableName> = NamespaceSelectable<Namespace, T>;\n export type Updateable<T extends TableName> = NamespaceUpdateable<Namespace, T>;\n `;\n\n return (\n [importsSection, namespaceInterface, getDBFunction, utilityTypeExports].join(\"\\n\\n\") + \"\\n\"\n );\n}\n","import { resolve } from \"pathe\";\nimport { generatePGliteSchemaModule } from \"./pglite-schema\";\nimport { processKyselyType, generateUnifiedKyselyTypes } from \"./type-processor\";\nimport type { Plugin, GeneratorResult, TailorDBReadyContext } from \"#/plugin/types\";\nimport type { KyselyTypeMetadata, KyselyNamespaceMetadata } from \"./types\";\n\n/** Unique identifier for the Kysely type generator plugin. */\nexport const KyselyGeneratorID = \"@tailor-platform/kysely-type\";\n\ntype KyselyTypePluginOptions = {\n distPath: string;\n pgliteSchemaPath?: string;\n /**\n * When `true`, generated tables map date/datetime fields and top-level time fields to\n * `Temporal.PlainDate`/`Temporal.Instant`/`Temporal.PlainTime` columns instead of\n * their `Date`/`string` defaults, and the generated `getDB` reads them back as those\n * Temporal values. Nested time fields remain strings. Defaults to `false`.\n */\n temporal?: boolean;\n};\n\n// Register this plugin's config type under its own id, via the package's\n// real public specifier, so callers can resolve it type-safely from a\n// `Plugin[]` array (see plugin/get-plugin-config.ts's resolvePluginConfig)\n// without importing KyselyTypePluginOptions, which stays unexported.\ndeclare module \"@tailor-platform/sdk/plugin\" {\n interface PluginConfigRegistry {\n \"@tailor-platform/kysely-type\": KyselyTypePluginOptions;\n }\n}\n\n/** Conventional output path used when `kyselyTypePlugin` has no `distPath` configured. */\nexport const DEFAULT_KYSELY_TYPES_DIST_PATH = \"./generated/tailordb.ts\";\n\n/**\n * Plugin that generates Kysely type definitions for TailorDB tables.\n * @param options - Plugin options\n * @param options.distPath - Output file path for generated types\n * @param options.pgliteSchemaPath - Output file path for the PGlite `CREATE TABLE` script module; omit to skip it\n * @param options.temporal - When `true`, generated tables map date/datetime fields and\n * top-level time fields to their `Temporal.PlainDate`/`Temporal.Instant`/\n * `Temporal.PlainTime` counterparts instead of `Date`/`string`. Nested time fields\n * remain strings. Defaults to `false`.\n * @returns Plugin instance with onTailorDBReady hook\n */\nexport function kyselyTypePlugin(\n options: KyselyTypePluginOptions,\n): Plugin<unknown, KyselyTypePluginOptions> {\n return {\n id: KyselyGeneratorID,\n description: \"Generates Kysely type definitions for TailorDB tables\",\n pluginConfig: options,\n\n async onTailorDBReady(\n ctx: TailorDBReadyContext<KyselyTypePluginOptions>,\n ): Promise<GeneratorResult> {\n const { distPath, pgliteSchemaPath, temporal } = ctx.pluginConfig;\n if (pgliteSchemaPath && resolve(distPath) === resolve(pgliteSchemaPath)) {\n throw new Error(\"distPath and pgliteSchemaPath must resolve to different files.\");\n }\n\n const allNamespaceData: KyselyNamespaceMetadata[] = [];\n\n for (const ns of ctx.tailordb) {\n const typeMetadataList: KyselyTypeMetadata[] = [];\n\n for (const type of Object.values(ns.tables)) {\n const metadata = await processKyselyType(type, temporal);\n typeMetadataList.push(metadata);\n }\n\n if (typeMetadataList.length === 0) continue;\n\n allNamespaceData.push({\n namespace: ns.namespace,\n types: typeMetadataList,\n });\n }\n\n const files: GeneratorResult[\"files\"] = [];\n if (allNamespaceData.length > 0) {\n const content = generateUnifiedKyselyTypes(allNamespaceData, temporal);\n files.push({\n path: ctx.pluginConfig.distPath,\n content,\n });\n if (ctx.pluginConfig.pgliteSchemaPath) {\n files.push({\n path: ctx.pluginConfig.pgliteSchemaPath,\n content: generatePGliteSchemaModule(\n ctx.tailordb.filter((ns) => Object.keys(ns.tables).length > 0),\n ),\n });\n }\n }\n\n return { files };\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{t as DEFAULT_KYSELY_TYPES_DIST_PATH,n as KyselyGeneratorID,r as kyselyTypePlugin}from"../../../kysely-type-
|
|
1
|
+
export{t as DEFAULT_KYSELY_TYPES_DIST_PATH,n as KyselyGeneratorID,r as kyselyTypePlugin}from"../../../kysely-type-DVL90_oX.mjs";
|
|
@@ -17,8 +17,9 @@ export interface SeedNamespaceConfig {
|
|
|
17
17
|
omitFields?: Record<string, string[]>;
|
|
18
18
|
/**
|
|
19
19
|
* Self-referencing field names per table (a subset of the table's own
|
|
20
|
-
* fields, e.g. `parentId`).
|
|
21
|
-
*
|
|
20
|
+
* fields, e.g. `parentId`). A field inside a nested field is named by its
|
|
21
|
+
* dotted path, e.g. `links.parentID`. Lets the seed script order same-table
|
|
22
|
+
* inserts so a row is never inserted before the row it points to.
|
|
22
23
|
*/
|
|
23
24
|
selfRefFields?: Record<string, string[]>;
|
|
24
25
|
/**
|
|
@@ -27,7 +28,7 @@ export interface SeedNamespaceConfig {
|
|
|
27
28
|
* always target the row's `id` — `toward.key` (or a `keyOnly` relation's
|
|
28
29
|
* `foreignKeyField`) can point at another unique field — so the seed
|
|
29
30
|
* script needs this to resolve parent/child edges by the right value
|
|
30
|
-
* instead of assuming `id`.
|
|
31
|
+
* instead of assuming `id`. Keyed by the same names as `selfRefFields`.
|
|
31
32
|
*/
|
|
32
33
|
selfRefKeys?: Record<string, Record<string, string>>;
|
|
33
34
|
}
|
|
@@ -4,6 +4,8 @@ import { TailorAnyDBType } from "../configure/services/tailordb/types.mjs";
|
|
|
4
4
|
* For table-attached plugins, calls onTableLoaded() with the source table.
|
|
5
5
|
* For namespace plugins, calls onNamespaceLoaded() with auto-resolved namespace.
|
|
6
6
|
* Results are cached per config path, plugin, namespace, and pluginConfig to avoid redundant processing.
|
|
7
|
+
*
|
|
8
|
+
* **Beta:** This API may change in future releases.
|
|
7
9
|
* @param configPath - Path to tailor.config.ts (absolute or relative to cwd)
|
|
8
10
|
* @param pluginId - The plugin's unique identifier
|
|
9
11
|
* @param sourceTable - The source TailorDB table (null for namespace plugins)
|
|
@@ -18,6 +20,8 @@ export declare function getGeneratedTable(configPath: string, pluginId: string,
|
|
|
18
20
|
* The table exported from the source file is not changed; the returned table is a new object.
|
|
19
21
|
* Returns the source table itself when no plugin is attached to it, or when the config is
|
|
20
22
|
* not available (e.g. in a bundled executor on the platform server).
|
|
23
|
+
*
|
|
24
|
+
* **Beta:** This API may change in future releases.
|
|
21
25
|
* @template T - The source table's own type, which the returned table keeps
|
|
22
26
|
* @param configPath - Path to tailor.config.ts (absolute or relative to cwd)
|
|
23
27
|
* @param sourceTable - The TailorDB table as exported from its source file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["PluginManager","path","fs","factory","configCacheMap","OPTIONAL_HOOK_KEYS","value","candidate","key","resolvedPath","configPath","cached","configModule","pathToFileURL","config","configDir","plugins","pluginsExport","item","result","namespace","nsConfig","dbConfig","pattern","absolutePattern","matchedFiles","file","mod","exported","sourceTable","plugin","output","kind","processCache","namespaceProcessCache","pluginConfig","baseKey","cache","pluginEntry","pluginId","pluginCache","cacheKey","tableConfig","p","generatedTable","extendedTableCache","tables","pending","entry","extendedTable"],"sources":["../../src/plugin/with-context.ts","../../src/plugin/get-generated-table.ts"],"sourcesContent":["/**\n * Plugin executor context support for defining plugin executors in separate files.\n * This module provides utilities for creating type-safe plugin executors that receive\n * context (like table references and namespace) at runtime.\n */\n\nimport type { TailorEnv, TailorPrincipal } from \"#/runtime/types\";\n\n/**\n * Plugin executor factory function type.\n * Takes context and returns an executor configuration.\n * Returns unknown since the exact return type depends on createExecutor's generic params.\n */\nexport type PluginExecutorFactory<Ctx> = (ctx: Ctx) => unknown;\n\n// ============================================================================\n// Plugin Executor Args Types\n// ============================================================================\n\n/**\n * Base args for plugin executor function operations.\n * Provides typed access to runtime context without requiring specific record types.\n */\nexport interface PluginFunctionArgs {\n /** Workspace ID where the executor runs */\n workspaceId: string;\n /** Application namespace */\n appNamespace: string;\n /** Environment variables */\n env: TailorEnv;\n /** Principal that triggered the event, null for system events */\n actor: TailorPrincipal | null;\n /** Name of the TailorDB table */\n typeName: string;\n /** TailorDB connections by namespace */\n tailordb: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record creation.\n */\nexport interface PluginRecordCreatedArgs extends PluginFunctionArgs {\n /** The newly created record */\n newRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record update.\n */\nexport interface PluginRecordUpdatedArgs extends PluginFunctionArgs {\n /** The record after update */\n newRecord: Record<string, unknown>;\n /** The record before update */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record deletion.\n */\nexport interface PluginRecordDeletedArgs extends PluginFunctionArgs {\n /** The deleted record */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Database schema type for plugins.\n * Since plugins work with dynamic types, the schema uses Record types.\n */\nexport type PluginDBSchema = Record<string, Record<string, unknown>>;\n\n/**\n * Base record type for TailorDB records.\n * All records have an id field.\n */\nexport type PluginRecord = { id: string } & Record<string, unknown>;\n\n/**\n * Define a plugin executor that receives context at runtime.\n * This allows executor definitions to be in separate files while\n * still receiving dynamic values like typeName, generated types, and namespace.\n * @param factory - Function that takes context and returns executor configuration\n * @returns The same factory function (for type inference)\n * @example\n * ```typescript\n * // executors/on-create.ts\n * import { withPluginContext } from \"@tailor-platform/sdk/plugin\";\n * import { createExecutor, recordCreatedTrigger } from \"@tailor-platform/sdk\";\n * import { getDB } from \"@tailor-platform/function-kysely-tailordb\";\n *\n * interface MyContext {\n * sourceTable: TailorAnyDBType;\n * historyType: TailorAnyDBType;\n * namespace: string;\n * }\n *\n * export default withPluginContext<MyContext>((ctx) =>\n * createExecutor({\n * name: `${ctx.sourceTable.name.toLowerCase()}-on-create`,\n * trigger: recordCreatedTrigger({ type: ctx.sourceTable }),\n * operation: {\n * kind: \"function\",\n * body: async (args) => {\n * const db = getDB(ctx.namespace);\n * await db.insertInto(ctx.historyType.name).values({\n * recordId: args.newRecord.id,\n * // ...\n * }).execute();\n * },\n * },\n * })\n * );\n * ```\n */\nexport function withPluginContext<Ctx>(\n factory: PluginExecutorFactory<Ctx>,\n): PluginExecutorFactory<Ctx> {\n return factory;\n}\n","import * as fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport * as path from \"pathe\";\nimport { PluginManager } from \"./manager\";\nimport type { TailorAnyDBType } from \"#/configure/services/tailordb/types\";\nimport type { Plugin, PluginOutput, TablePluginOutput } from \"#/plugin/types\";\nimport type { TailorDBTypeRaw } from \"#/types/tailordb.generated\";\n\n// ========================================\n// Config loading and caching\n// ========================================\n\ninterface PluginEntry {\n plugin: Plugin;\n pluginConfig: unknown;\n}\n\ninterface ConfigCache {\n config: { db?: Record<string, unknown> };\n plugins: Map<string, PluginEntry>;\n configDir: string;\n}\n\n/** Cache: resolved config path -> loaded config data */\nconst configCacheMap = new Map<string, ConfigCache>();\n\nconst OPTIONAL_HOOK_KEYS = [\n \"onTableLoaded\",\n \"onNamespaceLoaded\",\n \"onTailorDBReady\",\n \"onResolverReady\",\n \"onExecutorReady\",\n \"onDeployed\",\n] as const;\n\n/**\n * Check if a value is a Plugin instance. Mirrors PluginConfigSchema's shape without\n * depending on zod, since this module must stay usable from a bundled executor.\n * @param value - Value to check\n * @returns True if value has the shape of Plugin\n */\nfunction isPlugin(value: unknown): value is Plugin {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n const candidate = value as Record<string, unknown>;\n if (typeof candidate.id !== \"string\" || typeof candidate.description !== \"string\") return false;\n if (candidate.importPath !== undefined && typeof candidate.importPath !== \"string\") return false;\n if (\n candidate.tableConfigRequired !== undefined &&\n typeof candidate.tableConfigRequired !== \"boolean\" &&\n typeof candidate.tableConfigRequired !== \"function\"\n )\n return false;\n for (const key of OPTIONAL_HOOK_KEYS) {\n if (candidate[key] !== undefined && typeof candidate[key] !== \"function\") return false;\n }\n const hasDefinitionTimeHooks = candidate.onTableLoaded || candidate.onNamespaceLoaded;\n if (hasDefinitionTimeHooks && !candidate.importPath) return false;\n return true;\n}\n\n/**\n * Load and cache config module from the given path.\n * Reads plugins from the config module's `plugins` export (definePlugins() format).\n * Returns null if the config file does not exist (e.g., in bundled executor on platform server).\n * @param configPath - Absolute or relative path to tailor.config.ts\n * @returns Cached config data with plugins map, or null if config file is not available\n */\nasync function loadAndCacheConfig(configPath: string): Promise<ConfigCache | null> {\n const resolvedPath = path.resolve(configPath);\n\n const cached = configCacheMap.get(resolvedPath);\n if (cached) return cached;\n\n // Config file may not exist in bundled environments (e.g., platform server)\n if (!fs.existsSync(resolvedPath)) {\n return null;\n }\n\n const configModule = await import(pathToFileURL(resolvedPath).href);\n if (!configModule?.default) {\n throw new Error(`Invalid config module at \"${resolvedPath}\": default export not found`);\n }\n\n const config = configModule.default as { db?: Record<string, unknown> };\n const configDir = path.dirname(resolvedPath);\n const plugins = new Map<string, PluginEntry>();\n\n if (Object.hasOwn(configModule, \"plugins\")) {\n const pluginsExport: unknown = configModule.plugins;\n if (!Array.isArray(pluginsExport)) {\n throw new Error(\n `Invalid \\`plugins\\` export in \"${resolvedPath}\": expected an array returned by definePlugins(), got ${typeof pluginsExport}`,\n );\n }\n for (const item of pluginsExport) {\n if (!isPlugin(item)) {\n throw new Error(\n `Invalid \\`plugins\\` export in \"${resolvedPath}\": every item must be a plugin created by definePlugins()`,\n );\n }\n if (plugins.has(item.id)) {\n throw new Error(\n `Duplicate plugin ID \"${item.id}\" detected in \"${resolvedPath}\". Each plugin must have a unique ID.`,\n );\n }\n plugins.set(item.id, { plugin: item, pluginConfig: item.pluginConfig });\n }\n }\n\n const result: ConfigCache = { config, plugins, configDir };\n configCacheMap.set(resolvedPath, result);\n return result;\n}\n\n// ========================================\n// Namespace resolution\n// ========================================\n\ninterface DbNamespaceConfig {\n files?: string[];\n external?: boolean;\n}\n\n/**\n * Resolve the namespace for a table-attached source table by checking config.db file patterns.\n * Uses ESM module cache identity: same file path yields same object references.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param configDir - Directory containing the config file\n * @param sourceTable - The TailorDB table to look up\n * @returns The namespace name\n */\nasync function resolveNamespaceForTable(\n config: { db?: Record<string, unknown> },\n configDir: string,\n sourceTable: TailorAnyDBType,\n): Promise<string> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n for (const [namespace, nsConfig] of Object.entries(config.db)) {\n const dbConfig = nsConfig as DbNamespaceConfig;\n // Skip external namespaces (no files to resolve)\n if (dbConfig.external || !dbConfig.files) continue;\n\n for (const pattern of dbConfig.files) {\n const absolutePattern = path.resolve(configDir, pattern);\n let matchedFiles: string[];\n try {\n matchedFiles = fs.globSync(absolutePattern);\n } catch {\n continue;\n }\n\n for (const file of matchedFiles) {\n const mod = await import(pathToFileURL(file).href);\n for (const exported of Object.values(mod)) {\n if (exported === sourceTable) {\n return namespace;\n }\n }\n }\n }\n }\n\n throw new Error(\n `Could not resolve namespace for table \"${sourceTable.name}\". ` +\n `Ensure the table file is included in a db namespace's files pattern.`,\n );\n}\n\n/**\n * Resolve the namespace for a namespace plugin by trying each namespace.\n * Calls onNamespaceLoaded() for each and returns the first whose output contains the requested kind.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - Plugin instance\n * @param kind - The generated table kind to look for\n * @param pluginConfig - Plugin-level configuration\n * @returns The namespace name\n */\nasync function resolveNamespaceForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<{ namespace: string; output: PluginOutput }> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const output = await plugin.onNamespaceLoaded({\n pluginConfig,\n namespace,\n });\n\n if (output.tables?.[kind]) {\n return { namespace, output };\n }\n }\n\n throw new Error(\n `Could not resolve namespace for plugin \"${plugin.id}\" with kind \"${kind}\". ` +\n `No namespace produced a table with that kind.`,\n );\n}\n\n// ========================================\n// Process caching\n// ========================================\n\n// Cache: plugin -> cacheKey -> TablePluginOutput\nconst processCache = new WeakMap<Plugin, Map<string, TablePluginOutput>>();\n\n// Cache for namespace plugins: plugin -> cacheKey -> PluginOutput\nconst namespaceProcessCache = new WeakMap<Plugin, Map<string, PluginOutput>>();\n\n/**\n * Generate a cache key that includes pluginConfig.\n * @param baseKey - Base key for the cache\n * @param pluginConfig - Plugin configuration to include in the key\n * @returns Cache key string\n */\nfunction getCacheKey(baseKey: string, pluginConfig: unknown): string {\n if (pluginConfig === undefined) {\n return baseKey;\n }\n try {\n return `${baseKey}:${JSON.stringify(pluginConfig)}`;\n } catch {\n throw new Error(\n `pluginConfig must be JSON-serializable for caching. Received non-serializable value.`,\n );\n }\n}\n\n// ========================================\n// Main API\n// ========================================\n\n/**\n * Get a generated table from a plugin by loading the config and resolving everything automatically.\n * For table-attached plugins, calls onTableLoaded() with the source table.\n * For namespace plugins, calls onNamespaceLoaded() with auto-resolved namespace.\n * Results are cached per config path, plugin, namespace, and pluginConfig to avoid redundant processing.\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param pluginId - The plugin's unique identifier\n * @param sourceTable - The source TailorDB table (null for namespace plugins)\n * @param kind - The generated table kind (e.g., \"request\", \"step\")\n * @returns The generated TailorDB table\n */\nexport async function getGeneratedTable(\n configPath: string,\n pluginId: string,\n sourceTable: TailorAnyDBType | null,\n kind: string,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n\n if (!cache) {\n // Config not available (e.g., running in bundled executor on platform server).\n // Return a placeholder. The actual table is resolved at generate/apply time.\n return { name: `__placeholder_${kind}__`, fields: {} } as TailorAnyDBType;\n }\n\n const { config, configDir, plugins } = cache;\n\n const pluginEntry = plugins.get(pluginId);\n if (!pluginEntry) {\n throw new Error(\n `Plugin \"${pluginId}\" not found in config at \"${configPath}\". ` +\n `Ensure the plugin is registered via definePlugins().`,\n );\n }\n\n const { plugin, pluginConfig } = pluginEntry;\n\n if (sourceTable === null) {\n return getGeneratedTableForNamespacePlugin(config, plugin, kind, pluginConfig);\n }\n\n const namespace = await resolveNamespaceForTable(config, configDir, sourceTable);\n return getGeneratedTableForTableAttachedPlugin(\n plugin,\n sourceTable,\n kind,\n pluginConfig,\n namespace,\n );\n}\n\n/**\n * Get a generated table from a table-attached plugin.\n * @param plugin - The plugin instance (must have onTableLoaded() method)\n * @param sourceTable - The source TailorDB table\n * @param kind - The generated table kind\n * @param pluginConfig - Plugin-level configuration\n * @param namespace - Resolved namespace\n * @returns The generated TailorDB table\n */\nasync function getGeneratedTableForTableAttachedPlugin(\n plugin: Plugin,\n sourceTable: TailorAnyDBType,\n kind: string,\n pluginConfig: unknown,\n namespace: string,\n): Promise<TailorAnyDBType> {\n if (!plugin.onTableLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have an onTableLoaded() method`);\n }\n\n // Check cache first\n let pluginCache = processCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n processCache.set(plugin, pluginCache);\n }\n\n const cacheKey = getCacheKey(`${sourceTable.name}:ns=${namespace}`, pluginConfig);\n let output = pluginCache.get(cacheKey);\n\n if (!output) {\n const tableConfig = sourceTable.plugins.find((p) => p.pluginId === plugin.id)?.config;\n output = await plugin.onTableLoaded({\n table: sourceTable,\n tableConfig: tableConfig ?? {},\n pluginConfig,\n namespace,\n });\n pluginCache.set(cacheKey, output);\n }\n\n const generatedTable = output.tables?.[kind];\n if (!generatedTable) {\n throw new Error(\n `Generated table not found: plugin=${plugin.id}, sourceTable=${sourceTable.name}, kind=${kind}`,\n );\n }\n\n return generatedTable as TailorAnyDBType;\n}\n\n/**\n * Get a generated table from a namespace plugin.\n * Auto-resolves the namespace by trying each one.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - The plugin instance (must have onNamespaceLoaded() method)\n * @param kind - The generated table kind\n * @param pluginConfig - Plugin-level configuration\n * @returns The generated TailorDB table\n */\nasync function getGeneratedTableForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<TailorAnyDBType> {\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n // Check cache first - try all namespaces\n let pluginCache = namespaceProcessCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n namespaceProcessCache.set(plugin, pluginCache);\n }\n\n // Try cached results first\n if (config.db) {\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n const cached = pluginCache.get(cacheKey);\n if (cached?.tables?.[kind]) {\n return cached.tables[kind] as TailorAnyDBType;\n }\n }\n }\n\n // Not in cache - resolve namespace and process\n const { namespace, output } = await resolveNamespaceForNamespacePlugin(\n config,\n plugin,\n kind,\n pluginConfig,\n );\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n pluginCache.set(cacheKey, output);\n\n const generatedTable = output.tables?.[kind];\n if (!generatedTable) {\n throw new Error(`Generated table not found: plugin=${plugin.id}, kind=${kind}`);\n }\n\n return generatedTable as TailorAnyDBType;\n}\n\n// Cache: resolved config path -> source table -> the table with plugin fields applied.\n// Holds the pending promise so concurrent callers share one plugin run.\nconst extendedTableCache = new Map<string, WeakMap<TailorAnyDBType, Promise<TailorAnyDBType>>>();\n\n/**\n * Get a table with the fields its attached plugins add to it, as `tailor generate` sees it.\n * The plugins attached with `.plugin()` run in order, each seeing the fields the ones before\n * it added, and the result is cached per config path and table.\n * The table exported from the source file is not changed; the returned table is a new object.\n * Returns the source table itself when no plugin is attached to it, or when the config is\n * not available (e.g. in a bundled executor on the platform server).\n * @template T - The source table's own type, which the returned table keeps\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param sourceTable - The TailorDB table as exported from its source file\n * @returns The table with every plugin-added field\n */\nexport async function getExtendedTable<T extends TailorAnyDBType>(\n configPath: string,\n sourceTable: T,\n): Promise<T> {\n if (sourceTable.plugins.length === 0) {\n return sourceTable;\n }\n const resolvedPath = path.resolve(configPath);\n let tables = extendedTableCache.get(resolvedPath);\n if (!tables) {\n tables = new WeakMap();\n extendedTableCache.set(resolvedPath, tables);\n }\n const cached = tables.get(sourceTable);\n if (cached) {\n return cached as Promise<T>;\n }\n const pending = applyPluginExtensions(resolvedPath, sourceTable);\n tables.set(sourceTable, pending);\n pending.catch(() => tables.delete(sourceTable));\n return pending as Promise<T>;\n}\n\nasync function applyPluginExtensions(\n configPath: string,\n sourceTable: TailorAnyDBType,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n if (!cache) {\n return sourceTable;\n }\n const { config, configDir, plugins } = cache;\n const namespace = await resolveNamespaceForTable(config, configDir, sourceTable);\n const manager = new PluginManager([...plugins.values()].map((entry) => entry.plugin));\n const { extendedTable } = await manager.processAttachmentsForTable({\n rawTable: sourceTable as unknown as TailorDBTypeRaw,\n attachments: [...sourceTable.plugins],\n namespace,\n });\n return (extendedTable as TailorAnyDBType | undefined) ?? sourceTable;\n}\n\n/**\n * Clear all internal caches. For testing only.\n */\nexport function _clearCacheForTesting(): void {\n configCacheMap.clear();\n extendedTableCache.clear();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["PluginManager","path","fs","factory","configCacheMap","OPTIONAL_HOOK_KEYS","value","candidate","key","resolvedPath","configPath","cached","configModule","pathToFileURL","config","configDir","plugins","pluginsExport","item","result","namespace","nsConfig","dbConfig","pattern","absolutePattern","matchedFiles","file","mod","exported","sourceTable","plugin","output","kind","processCache","namespaceProcessCache","pluginConfig","baseKey","cache","pluginEntry","pluginId","pluginCache","cacheKey","tableConfig","p","generatedTable","extendedTableCache","tables","pending","entry","extendedTable"],"sources":["../../src/plugin/with-context.ts","../../src/plugin/get-generated-table.ts"],"sourcesContent":["/**\n * Plugin executor context support for defining plugin executors in separate files.\n * This module provides utilities for creating type-safe plugin executors that receive\n * context (like table references and namespace) at runtime.\n */\n\nimport type { TailorEnv, TailorPrincipal } from \"#/runtime/types\";\n\n/**\n * Plugin executor factory function type.\n * Takes context and returns an executor configuration.\n * Returns unknown since the exact return type depends on createExecutor's generic params.\n *\n * **Beta:** This API may change in future releases.\n */\nexport type PluginExecutorFactory<Ctx> = (ctx: Ctx) => unknown;\n\n// ============================================================================\n// Plugin Executor Args Types\n// ============================================================================\n\n/**\n * Base args for plugin executor function operations.\n * Provides typed access to runtime context without requiring specific record types.\n *\n * **Beta:** This API may change in future releases.\n */\nexport interface PluginFunctionArgs {\n /** Workspace ID where the executor runs */\n workspaceId: string;\n /** Application namespace */\n appNamespace: string;\n /** Environment variables */\n env: TailorEnv;\n /** Principal that triggered the event, null for system events */\n actor: TailorPrincipal | null;\n /** Name of the TailorDB table */\n typeName: string;\n /** TailorDB connections by namespace */\n tailordb: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record creation.\n *\n * **Beta:** This API may change in future releases.\n */\nexport interface PluginRecordCreatedArgs extends PluginFunctionArgs {\n /** The newly created record */\n newRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record update.\n *\n * **Beta:** This API may change in future releases.\n */\nexport interface PluginRecordUpdatedArgs extends PluginFunctionArgs {\n /** The record after update */\n newRecord: Record<string, unknown>;\n /** The record before update */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Args for plugin executors triggered on record deletion.\n *\n * **Beta:** This API may change in future releases.\n */\nexport interface PluginRecordDeletedArgs extends PluginFunctionArgs {\n /** The deleted record */\n oldRecord: Record<string, unknown>;\n}\n\n/**\n * Database schema type for plugins.\n * Since plugins work with dynamic types, the schema uses Record types.\n *\n * **Beta:** This API may change in future releases.\n */\nexport type PluginDBSchema = Record<string, Record<string, unknown>>;\n\n/**\n * Base record type for TailorDB records.\n * All records have an id field.\n *\n * **Beta:** This API may change in future releases.\n */\nexport type PluginRecord = { id: string } & Record<string, unknown>;\n\n/**\n * Define a plugin executor that receives context at runtime.\n * This allows executor definitions to be in separate files while\n * still receiving dynamic values like typeName, generated types, and namespace.\n *\n * **Beta:** This API may change in future releases.\n * @param factory - Function that takes context and returns executor configuration\n * @returns The same factory function (for type inference)\n * @example\n * ```typescript\n * // executors/on-create.ts\n * import { withPluginContext } from \"@tailor-platform/sdk/plugin\";\n * import { createExecutor, recordCreatedTrigger } from \"@tailor-platform/sdk\";\n * import { getDB } from \"@tailor-platform/function-kysely-tailordb\";\n *\n * interface MyContext {\n * sourceTable: TailorAnyDBType;\n * historyType: TailorAnyDBType;\n * namespace: string;\n * }\n *\n * export default withPluginContext<MyContext>((ctx) =>\n * createExecutor({\n * name: `${ctx.sourceTable.name.toLowerCase()}-on-create`,\n * trigger: recordCreatedTrigger({ type: ctx.sourceTable }),\n * operation: {\n * kind: \"function\",\n * body: async (args) => {\n * const db = getDB(ctx.namespace);\n * await db.insertInto(ctx.historyType.name).values({\n * recordId: args.newRecord.id,\n * // ...\n * }).execute();\n * },\n * },\n * })\n * );\n * ```\n */\nexport function withPluginContext<Ctx>(\n factory: PluginExecutorFactory<Ctx>,\n): PluginExecutorFactory<Ctx> {\n return factory;\n}\n","import * as fs from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport * as path from \"pathe\";\nimport { PluginManager } from \"./manager\";\nimport type { TailorAnyDBType } from \"#/configure/services/tailordb/types\";\nimport type { Plugin, PluginOutput, TablePluginOutput } from \"#/plugin/types\";\nimport type { TailorDBTypeRaw } from \"#/types/tailordb.generated\";\n\n// ========================================\n// Config loading and caching\n// ========================================\n\ninterface PluginEntry {\n plugin: Plugin;\n pluginConfig: unknown;\n}\n\ninterface ConfigCache {\n config: { db?: Record<string, unknown> };\n plugins: Map<string, PluginEntry>;\n configDir: string;\n}\n\n/** Cache: resolved config path -> loaded config data */\nconst configCacheMap = new Map<string, ConfigCache>();\n\nconst OPTIONAL_HOOK_KEYS = [\n \"onTableLoaded\",\n \"onNamespaceLoaded\",\n \"onTailorDBReady\",\n \"onResolverReady\",\n \"onExecutorReady\",\n \"onDeployed\",\n] as const;\n\n/**\n * Check if a value is a Plugin instance. Mirrors PluginConfigSchema's shape without\n * depending on zod, since this module must stay usable from a bundled executor.\n * @param value - Value to check\n * @returns True if value has the shape of Plugin\n */\nfunction isPlugin(value: unknown): value is Plugin {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n const candidate = value as Record<string, unknown>;\n if (typeof candidate.id !== \"string\" || typeof candidate.description !== \"string\") return false;\n if (candidate.importPath !== undefined && typeof candidate.importPath !== \"string\") return false;\n if (\n candidate.tableConfigRequired !== undefined &&\n typeof candidate.tableConfigRequired !== \"boolean\" &&\n typeof candidate.tableConfigRequired !== \"function\"\n )\n return false;\n for (const key of OPTIONAL_HOOK_KEYS) {\n if (candidate[key] !== undefined && typeof candidate[key] !== \"function\") return false;\n }\n const hasDefinitionTimeHooks = candidate.onTableLoaded || candidate.onNamespaceLoaded;\n if (hasDefinitionTimeHooks && !candidate.importPath) return false;\n return true;\n}\n\n/**\n * Load and cache config module from the given path.\n * Reads plugins from the config module's `plugins` export (definePlugins() format).\n * Returns null if the config file does not exist (e.g., in bundled executor on platform server).\n * @param configPath - Absolute or relative path to tailor.config.ts\n * @returns Cached config data with plugins map, or null if config file is not available\n */\nasync function loadAndCacheConfig(configPath: string): Promise<ConfigCache | null> {\n const resolvedPath = path.resolve(configPath);\n\n const cached = configCacheMap.get(resolvedPath);\n if (cached) return cached;\n\n // Config file may not exist in bundled environments (e.g., platform server)\n if (!fs.existsSync(resolvedPath)) {\n return null;\n }\n\n const configModule = await import(pathToFileURL(resolvedPath).href);\n if (!configModule?.default) {\n throw new Error(`Invalid config module at \"${resolvedPath}\": default export not found`);\n }\n\n const config = configModule.default as { db?: Record<string, unknown> };\n const configDir = path.dirname(resolvedPath);\n const plugins = new Map<string, PluginEntry>();\n\n if (Object.hasOwn(configModule, \"plugins\")) {\n const pluginsExport: unknown = configModule.plugins;\n if (!Array.isArray(pluginsExport)) {\n throw new Error(\n `Invalid \\`plugins\\` export in \"${resolvedPath}\": expected an array returned by definePlugins(), got ${typeof pluginsExport}`,\n );\n }\n for (const item of pluginsExport) {\n if (!isPlugin(item)) {\n throw new Error(\n `Invalid \\`plugins\\` export in \"${resolvedPath}\": every item must be a plugin created by definePlugins()`,\n );\n }\n if (plugins.has(item.id)) {\n throw new Error(\n `Duplicate plugin ID \"${item.id}\" detected in \"${resolvedPath}\". Each plugin must have a unique ID.`,\n );\n }\n plugins.set(item.id, { plugin: item, pluginConfig: item.pluginConfig });\n }\n }\n\n const result: ConfigCache = { config, plugins, configDir };\n configCacheMap.set(resolvedPath, result);\n return result;\n}\n\n// ========================================\n// Namespace resolution\n// ========================================\n\ninterface DbNamespaceConfig {\n files?: string[];\n external?: boolean;\n}\n\n/**\n * Resolve the namespace for a table-attached source table by checking config.db file patterns.\n * Uses ESM module cache identity: same file path yields same object references.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param configDir - Directory containing the config file\n * @param sourceTable - The TailorDB table to look up\n * @returns The namespace name\n */\nasync function resolveNamespaceForTable(\n config: { db?: Record<string, unknown> },\n configDir: string,\n sourceTable: TailorAnyDBType,\n): Promise<string> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n for (const [namespace, nsConfig] of Object.entries(config.db)) {\n const dbConfig = nsConfig as DbNamespaceConfig;\n // Skip external namespaces (no files to resolve)\n if (dbConfig.external || !dbConfig.files) continue;\n\n for (const pattern of dbConfig.files) {\n const absolutePattern = path.resolve(configDir, pattern);\n let matchedFiles: string[];\n try {\n matchedFiles = fs.globSync(absolutePattern);\n } catch {\n continue;\n }\n\n for (const file of matchedFiles) {\n const mod = await import(pathToFileURL(file).href);\n for (const exported of Object.values(mod)) {\n if (exported === sourceTable) {\n return namespace;\n }\n }\n }\n }\n }\n\n throw new Error(\n `Could not resolve namespace for table \"${sourceTable.name}\". ` +\n `Ensure the table file is included in a db namespace's files pattern.`,\n );\n}\n\n/**\n * Resolve the namespace for a namespace plugin by trying each namespace.\n * Calls onNamespaceLoaded() for each and returns the first whose output contains the requested kind.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - Plugin instance\n * @param kind - The generated table kind to look for\n * @param pluginConfig - Plugin-level configuration\n * @returns The namespace name\n */\nasync function resolveNamespaceForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<{ namespace: string; output: PluginOutput }> {\n if (!config.db) {\n throw new Error(`No db configuration found in config`);\n }\n\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const output = await plugin.onNamespaceLoaded({\n pluginConfig,\n namespace,\n });\n\n if (output.tables?.[kind]) {\n return { namespace, output };\n }\n }\n\n throw new Error(\n `Could not resolve namespace for plugin \"${plugin.id}\" with kind \"${kind}\". ` +\n `No namespace produced a table with that kind.`,\n );\n}\n\n// ========================================\n// Process caching\n// ========================================\n\n// Cache: plugin -> cacheKey -> TablePluginOutput\nconst processCache = new WeakMap<Plugin, Map<string, TablePluginOutput>>();\n\n// Cache for namespace plugins: plugin -> cacheKey -> PluginOutput\nconst namespaceProcessCache = new WeakMap<Plugin, Map<string, PluginOutput>>();\n\n/**\n * Generate a cache key that includes pluginConfig.\n * @param baseKey - Base key for the cache\n * @param pluginConfig - Plugin configuration to include in the key\n * @returns Cache key string\n */\nfunction getCacheKey(baseKey: string, pluginConfig: unknown): string {\n if (pluginConfig === undefined) {\n return baseKey;\n }\n try {\n return `${baseKey}:${JSON.stringify(pluginConfig)}`;\n } catch {\n throw new Error(\n `pluginConfig must be JSON-serializable for caching. Received non-serializable value.`,\n );\n }\n}\n\n// ========================================\n// Main API\n// ========================================\n\n/**\n * Get a generated table from a plugin by loading the config and resolving everything automatically.\n * For table-attached plugins, calls onTableLoaded() with the source table.\n * For namespace plugins, calls onNamespaceLoaded() with auto-resolved namespace.\n * Results are cached per config path, plugin, namespace, and pluginConfig to avoid redundant processing.\n *\n * **Beta:** This API may change in future releases.\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param pluginId - The plugin's unique identifier\n * @param sourceTable - The source TailorDB table (null for namespace plugins)\n * @param kind - The generated table kind (e.g., \"request\", \"step\")\n * @returns The generated TailorDB table\n */\nexport async function getGeneratedTable(\n configPath: string,\n pluginId: string,\n sourceTable: TailorAnyDBType | null,\n kind: string,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n\n if (!cache) {\n // Config not available (e.g., running in bundled executor on platform server).\n // Return a placeholder. The actual table is resolved at generate/apply time.\n return { name: `__placeholder_${kind}__`, fields: {} } as TailorAnyDBType;\n }\n\n const { config, configDir, plugins } = cache;\n\n const pluginEntry = plugins.get(pluginId);\n if (!pluginEntry) {\n throw new Error(\n `Plugin \"${pluginId}\" not found in config at \"${configPath}\". ` +\n `Ensure the plugin is registered via definePlugins().`,\n );\n }\n\n const { plugin, pluginConfig } = pluginEntry;\n\n if (sourceTable === null) {\n return getGeneratedTableForNamespacePlugin(config, plugin, kind, pluginConfig);\n }\n\n const namespace = await resolveNamespaceForTable(config, configDir, sourceTable);\n return getGeneratedTableForTableAttachedPlugin(\n plugin,\n sourceTable,\n kind,\n pluginConfig,\n namespace,\n );\n}\n\n/**\n * Get a generated table from a table-attached plugin.\n * @param plugin - The plugin instance (must have onTableLoaded() method)\n * @param sourceTable - The source TailorDB table\n * @param kind - The generated table kind\n * @param pluginConfig - Plugin-level configuration\n * @param namespace - Resolved namespace\n * @returns The generated TailorDB table\n */\nasync function getGeneratedTableForTableAttachedPlugin(\n plugin: Plugin,\n sourceTable: TailorAnyDBType,\n kind: string,\n pluginConfig: unknown,\n namespace: string,\n): Promise<TailorAnyDBType> {\n if (!plugin.onTableLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have an onTableLoaded() method`);\n }\n\n // Check cache first\n let pluginCache = processCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n processCache.set(plugin, pluginCache);\n }\n\n const cacheKey = getCacheKey(`${sourceTable.name}:ns=${namespace}`, pluginConfig);\n let output = pluginCache.get(cacheKey);\n\n if (!output) {\n const tableConfig = sourceTable.plugins.find((p) => p.pluginId === plugin.id)?.config;\n output = await plugin.onTableLoaded({\n table: sourceTable,\n tableConfig: tableConfig ?? {},\n pluginConfig,\n namespace,\n });\n pluginCache.set(cacheKey, output);\n }\n\n const generatedTable = output.tables?.[kind];\n if (!generatedTable) {\n throw new Error(\n `Generated table not found: plugin=${plugin.id}, sourceTable=${sourceTable.name}, kind=${kind}`,\n );\n }\n\n return generatedTable as TailorAnyDBType;\n}\n\n/**\n * Get a generated table from a namespace plugin.\n * Auto-resolves the namespace by trying each one.\n * @param config - App config with db namespace definitions\n * @param config.db - DB namespace definitions\n * @param plugin - The plugin instance (must have onNamespaceLoaded() method)\n * @param kind - The generated table kind\n * @param pluginConfig - Plugin-level configuration\n * @returns The generated TailorDB table\n */\nasync function getGeneratedTableForNamespacePlugin(\n config: { db?: Record<string, unknown> },\n plugin: Plugin,\n kind: string,\n pluginConfig: unknown,\n): Promise<TailorAnyDBType> {\n if (!plugin.onNamespaceLoaded) {\n throw new Error(`Plugin \"${plugin.id}\" does not have a onNamespaceLoaded() method`);\n }\n\n // Check cache first - try all namespaces\n let pluginCache = namespaceProcessCache.get(plugin);\n if (!pluginCache) {\n pluginCache = new Map();\n namespaceProcessCache.set(plugin, pluginCache);\n }\n\n // Try cached results first\n if (config.db) {\n for (const namespace of Object.keys(config.db)) {\n const dbConfig = config.db[namespace] as DbNamespaceConfig;\n if (dbConfig.external) continue;\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n const cached = pluginCache.get(cacheKey);\n if (cached?.tables?.[kind]) {\n return cached.tables[kind] as TailorAnyDBType;\n }\n }\n }\n\n // Not in cache - resolve namespace and process\n const { namespace, output } = await resolveNamespaceForNamespacePlugin(\n config,\n plugin,\n kind,\n pluginConfig,\n );\n\n const cacheKey = getCacheKey(`namespace:ns=${namespace}`, pluginConfig);\n pluginCache.set(cacheKey, output);\n\n const generatedTable = output.tables?.[kind];\n if (!generatedTable) {\n throw new Error(`Generated table not found: plugin=${plugin.id}, kind=${kind}`);\n }\n\n return generatedTable as TailorAnyDBType;\n}\n\n// Cache: resolved config path -> source table -> the table with plugin fields applied.\n// Holds the pending promise so concurrent callers share one plugin run.\nconst extendedTableCache = new Map<string, WeakMap<TailorAnyDBType, Promise<TailorAnyDBType>>>();\n\n/**\n * Get a table with the fields its attached plugins add to it, as `tailor generate` sees it.\n * The plugins attached with `.plugin()` run in order, each seeing the fields the ones before\n * it added, and the result is cached per config path and table.\n * The table exported from the source file is not changed; the returned table is a new object.\n * Returns the source table itself when no plugin is attached to it, or when the config is\n * not available (e.g. in a bundled executor on the platform server).\n *\n * **Beta:** This API may change in future releases.\n * @template T - The source table's own type, which the returned table keeps\n * @param configPath - Path to tailor.config.ts (absolute or relative to cwd)\n * @param sourceTable - The TailorDB table as exported from its source file\n * @returns The table with every plugin-added field\n */\nexport async function getExtendedTable<T extends TailorAnyDBType>(\n configPath: string,\n sourceTable: T,\n): Promise<T> {\n if (sourceTable.plugins.length === 0) {\n return sourceTable;\n }\n const resolvedPath = path.resolve(configPath);\n let tables = extendedTableCache.get(resolvedPath);\n if (!tables) {\n tables = new WeakMap();\n extendedTableCache.set(resolvedPath, tables);\n }\n const cached = tables.get(sourceTable);\n if (cached) {\n return cached as Promise<T>;\n }\n const pending = applyPluginExtensions(resolvedPath, sourceTable);\n tables.set(sourceTable, pending);\n pending.catch(() => tables.delete(sourceTable));\n return pending as Promise<T>;\n}\n\nasync function applyPluginExtensions(\n configPath: string,\n sourceTable: TailorAnyDBType,\n): Promise<TailorAnyDBType> {\n const cache = await loadAndCacheConfig(configPath);\n if (!cache) {\n return sourceTable;\n }\n const { config, configDir, plugins } = cache;\n const namespace = await resolveNamespaceForTable(config, configDir, sourceTable);\n const manager = new PluginManager([...plugins.values()].map((entry) => entry.plugin));\n const { extendedTable } = await manager.processAttachmentsForTable({\n rawTable: sourceTable as unknown as TailorDBTypeRaw,\n attachments: [...sourceTable.plugins],\n namespace,\n });\n return (extendedTable as TailorAnyDBType | undefined) ?? sourceTable;\n}\n\n/**\n * Clear all internal caches. For testing only.\n */\nexport function _clearCacheForTesting(): void {\n configCacheMap.clear();\n extendedTableCache.clear();\n}\n"],"mappings":"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"}
|
package/dist/plugin/types.d.mts
CHANGED
|
@@ -10,10 +10,11 @@ interface GeneratedFile {
|
|
|
10
10
|
path: string;
|
|
11
11
|
content: string;
|
|
12
12
|
skipIfExists?: boolean;
|
|
13
|
-
executable?: boolean;
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
15
|
* Result returned by generation-time hooks.
|
|
16
|
+
*
|
|
17
|
+
* **Beta:** This API may change in future releases.
|
|
17
18
|
*/
|
|
18
19
|
export interface GeneratorResult {
|
|
19
20
|
files: GeneratedFile[];
|
|
@@ -37,6 +38,8 @@ export interface GeneratorAuthInput {
|
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
40
|
* Namespace-level TailorDB data available to generation-time hooks.
|
|
41
|
+
*
|
|
42
|
+
* **Beta:** This API may change in future releases.
|
|
40
43
|
*/
|
|
41
44
|
export interface TailorDBNamespaceData {
|
|
42
45
|
/** Namespace name */
|
|
@@ -50,6 +53,8 @@ export interface TailorDBNamespaceData {
|
|
|
50
53
|
}
|
|
51
54
|
/**
|
|
52
55
|
* Namespace-level resolver data available to generation-time hooks.
|
|
56
|
+
*
|
|
57
|
+
* **Beta:** This API may change in future releases.
|
|
53
58
|
*/
|
|
54
59
|
export interface ResolverNamespaceData {
|
|
55
60
|
/** Namespace name */
|
|
@@ -59,6 +64,8 @@ export interface ResolverNamespaceData {
|
|
|
59
64
|
}
|
|
60
65
|
/**
|
|
61
66
|
* Context passed to plugin's onTailorDBReady hook.
|
|
67
|
+
*
|
|
68
|
+
* **Beta:** This API may change in future releases.
|
|
62
69
|
* @template PluginConfig - Plugin-level configuration type
|
|
63
70
|
*/
|
|
64
71
|
export interface TailorDBReadyContext<PluginConfig = unknown> {
|
|
@@ -75,6 +82,8 @@ export interface TailorDBReadyContext<PluginConfig = unknown> {
|
|
|
75
82
|
}
|
|
76
83
|
/**
|
|
77
84
|
* Context passed to plugin's onResolverReady hook.
|
|
85
|
+
*
|
|
86
|
+
* **Beta:** This API may change in future releases.
|
|
78
87
|
* @template PluginConfig - Plugin-level configuration type
|
|
79
88
|
*/
|
|
80
89
|
export interface ResolverReadyContext<PluginConfig = unknown> {
|
|
@@ -93,6 +102,8 @@ export interface ResolverReadyContext<PluginConfig = unknown> {
|
|
|
93
102
|
}
|
|
94
103
|
/**
|
|
95
104
|
* Context passed to plugin's onExecutorReady hook.
|
|
105
|
+
*
|
|
106
|
+
* **Beta:** This API may change in future releases.
|
|
96
107
|
* @template PluginConfig - Plugin-level configuration type
|
|
97
108
|
*/
|
|
98
109
|
export interface ExecutorReadyContext<PluginConfig = unknown> {
|
|
@@ -116,6 +127,8 @@ export type TableConfigRequired<PluginConfig = unknown> = boolean | ((pluginConf
|
|
|
116
127
|
/**
|
|
117
128
|
* Interface for plugin configuration mapping.
|
|
118
129
|
* Extend this interface via declaration merging to add typed plugin configs.
|
|
130
|
+
*
|
|
131
|
+
* **Beta:** This API may change in future releases.
|
|
119
132
|
*/
|
|
120
133
|
export interface PluginConfigs<Fields extends string = string> {}
|
|
121
134
|
/**
|
|
@@ -125,16 +138,22 @@ export interface PluginConfigs<Fields extends string = string> {}
|
|
|
125
138
|
* by the same `id` used in {@link PluginConfigs}. The value must be a
|
|
126
139
|
* `Record<string, TailorAnyDBField>` of the fields to add — it is merged
|
|
127
140
|
* into the table's existing fields, not a replacement for them.
|
|
141
|
+
*
|
|
142
|
+
* **Beta:** This API may change in future releases.
|
|
128
143
|
*/
|
|
129
144
|
export interface PluginFieldExtensions<Fields extends string = string, Config = unknown> {}
|
|
130
145
|
/**
|
|
131
146
|
* Registry mapping a plugin's `id` literal to its plugin-level config type.
|
|
132
147
|
* Extend via declaration merging, keyed by the `id` string, from the
|
|
133
148
|
* owning plugin's own module.
|
|
149
|
+
*
|
|
150
|
+
* **Beta:** This API may change in future releases.
|
|
134
151
|
*/
|
|
135
152
|
export interface PluginConfigRegistry {}
|
|
136
153
|
/**
|
|
137
154
|
* Context passed to plugin's process method
|
|
155
|
+
*
|
|
156
|
+
* **Beta:** This API may change in future releases.
|
|
138
157
|
*/
|
|
139
158
|
export interface PluginTableProcessContext<TableConfig = unknown, PluginConfig = unknown> {
|
|
140
159
|
table: TailorAnyDBType;
|
|
@@ -144,6 +163,8 @@ export interface PluginTableProcessContext<TableConfig = unknown, PluginConfig =
|
|
|
144
163
|
}
|
|
145
164
|
/**
|
|
146
165
|
* Context passed to plugin's onNamespaceLoaded hook.
|
|
166
|
+
*
|
|
167
|
+
* **Beta:** This API may change in future releases.
|
|
147
168
|
*/
|
|
148
169
|
export interface PluginNamespaceProcessContext<PluginConfig = unknown> {
|
|
149
170
|
pluginConfig: PluginConfig;
|
|
@@ -151,13 +172,17 @@ export interface PluginNamespaceProcessContext<PluginConfig = unknown> {
|
|
|
151
172
|
}
|
|
152
173
|
/**
|
|
153
174
|
* Interface representing a TailorDB table for plugin output.
|
|
175
|
+
*
|
|
176
|
+
* **Beta:** This API may change in future releases.
|
|
154
177
|
*/
|
|
155
178
|
export interface TailorDBTableForPlugin {
|
|
156
179
|
readonly name: string;
|
|
157
180
|
readonly fields: Record<string, unknown>;
|
|
158
181
|
}
|
|
182
|
+
/** **Beta:** This API may change in future releases. */
|
|
159
183
|
export type PluginGeneratedTable = TailorDBTableForPlugin;
|
|
160
184
|
type PluginGeneratedTables = Record<string, PluginGeneratedTable>;
|
|
185
|
+
/** **Beta:** This API may change in future releases. */
|
|
161
186
|
export interface PluginGeneratedResolver {
|
|
162
187
|
name: string;
|
|
163
188
|
operation: "query" | "mutation";
|
|
@@ -205,16 +230,19 @@ interface PluginWorkflowOperationConfig {
|
|
|
205
230
|
}
|
|
206
231
|
export type PluginOperationConfig = PluginFunctionOperationConfig | PluginGraphQLOperationConfig | PluginWebhookOperationConfig | PluginWorkflowOperationConfig;
|
|
207
232
|
type PluginExecutorContextValue = TailorAnyDBType | string | number | boolean | null | undefined;
|
|
233
|
+
/** **Beta:** This API may change in future releases. */
|
|
208
234
|
export interface PluginExecutorContextBase {
|
|
209
235
|
sourceTable: TailorAnyDBType | null;
|
|
210
236
|
namespace: string;
|
|
211
237
|
}
|
|
238
|
+
/** **Beta:** This API may change in future releases. */
|
|
212
239
|
export type PluginExecutorContext = PluginExecutorContextBase & {
|
|
213
240
|
[key: string]: PluginExecutorContextValue;
|
|
214
241
|
};
|
|
215
242
|
interface PluginExecutorModule {
|
|
216
243
|
default: unknown;
|
|
217
244
|
}
|
|
245
|
+
/** **Beta:** This API may change in future releases. */
|
|
218
246
|
export interface PluginGeneratedExecutorWithFile<Ctx = PluginExecutorContext> {
|
|
219
247
|
name: string;
|
|
220
248
|
resolve: () => Promise<PluginExecutorModule>;
|
|
@@ -226,21 +254,27 @@ export interface PluginGeneratedExecutorLegacy {
|
|
|
226
254
|
trigger: PluginTriggerConfig;
|
|
227
255
|
operation: PluginOperationConfig;
|
|
228
256
|
}
|
|
257
|
+
/** **Beta:** This API may change in future releases. */
|
|
229
258
|
export type PluginGeneratedExecutor = PluginGeneratedExecutorWithFile | PluginGeneratedExecutorLegacy;
|
|
230
259
|
interface PluginExtends<FieldExtension extends Record<string, TailorAnyDBField>> {
|
|
231
260
|
fields?: FieldExtension;
|
|
232
261
|
}
|
|
262
|
+
/** **Beta:** This API may change in future releases. */
|
|
233
263
|
export interface PluginOutput {
|
|
234
264
|
tables?: PluginGeneratedTables;
|
|
235
265
|
resolvers?: PluginGeneratedResolver[];
|
|
236
266
|
executors?: PluginGeneratedExecutor[];
|
|
237
267
|
}
|
|
268
|
+
/** **Beta:** This API may change in future releases. */
|
|
238
269
|
export interface TablePluginOutput<FieldExtension extends Record<string, TailorAnyDBField> = Record<string, TailorAnyDBField>> extends PluginOutput {
|
|
239
270
|
extends?: PluginExtends<FieldExtension>;
|
|
240
271
|
}
|
|
272
|
+
/** **Beta:** This API may change in future releases. */
|
|
241
273
|
export type NamespacePluginOutput = PluginOutput;
|
|
242
274
|
/**
|
|
243
275
|
* Plugin interface that all plugins must implement.
|
|
276
|
+
*
|
|
277
|
+
* **Beta:** This API may change in future releases.
|
|
244
278
|
* @template TableConfig - Type for per-table configuration passed via .plugin() method
|
|
245
279
|
* @template PluginConfig - Type for plugin-level configuration passed via definePlugins()
|
|
246
280
|
* @template FieldExtension - Type of the fields injected into the attached table via `extends.fields`. Should match the corresponding {@link PluginFieldExtensions} entry.
|
|
@@ -259,23 +293,31 @@ export interface Plugin<TableConfig = unknown, PluginConfig = unknown, FieldExte
|
|
|
259
293
|
/** Runs after a successful deploy, including deploys with no resource changes. */
|
|
260
294
|
onDeployed?(context: DeployedContext<PluginConfig>): void | DeployedHookResult | Promise<void | DeployedHookResult>;
|
|
261
295
|
}
|
|
296
|
+
/** **Beta:** This API may change in future releases. */
|
|
262
297
|
export interface PublishStaticWebsiteResult {
|
|
263
298
|
url: string;
|
|
264
299
|
skippedFiles: string[];
|
|
265
300
|
}
|
|
301
|
+
/** **Beta:** This API may change in future releases. */
|
|
266
302
|
export interface DeployedStaticWebsite {
|
|
267
303
|
name: string;
|
|
268
304
|
url: string;
|
|
269
305
|
}
|
|
270
|
-
/**
|
|
306
|
+
/**
|
|
307
|
+
* A static website declared in the config that registers the plugin, which the plugin can publish to.
|
|
308
|
+
*
|
|
309
|
+
* **Beta:** This API may change in future releases.
|
|
310
|
+
*/
|
|
271
311
|
export interface PublishableStaticWebsite extends DeployedStaticWebsite {
|
|
272
312
|
/** Uploads the directory at the absolute path `dir` and publishes it to this website. */
|
|
273
313
|
publish(dir: string): Promise<PublishStaticWebsiteResult>;
|
|
274
314
|
}
|
|
315
|
+
/** **Beta:** This API may change in future releases. */
|
|
275
316
|
export interface DeployedOAuth2Client {
|
|
276
317
|
name: string;
|
|
277
318
|
clientId: string;
|
|
278
319
|
}
|
|
320
|
+
/** **Beta:** This API may change in future releases. */
|
|
279
321
|
export interface DeployedApplication<StaticWebsite extends DeployedStaticWebsite = DeployedStaticWebsite> {
|
|
280
322
|
/** SDK-managed application ID from defineConfig(); undefined when the config has none. */
|
|
281
323
|
id?: string;
|
|
@@ -295,11 +337,13 @@ export interface DeployedApplication<StaticWebsite extends DeployedStaticWebsite
|
|
|
295
337
|
oauth2Clients: DeployedOAuth2Client[];
|
|
296
338
|
};
|
|
297
339
|
}
|
|
340
|
+
/** **Beta:** This API may change in future releases. */
|
|
298
341
|
export interface PluginLogger {
|
|
299
342
|
info(message: string): void;
|
|
300
343
|
warn(message: string): void;
|
|
301
344
|
success(message: string): void;
|
|
302
345
|
}
|
|
346
|
+
/** **Beta:** This API may change in future releases. */
|
|
303
347
|
export interface PluginExecOptions {
|
|
304
348
|
/** Directory to run the command in. */
|
|
305
349
|
workingDir: string;
|
|
@@ -311,13 +355,18 @@ export interface PluginExecOptions {
|
|
|
311
355
|
*/
|
|
312
356
|
output?: "stream" | "capture" | "ignore";
|
|
313
357
|
}
|
|
358
|
+
/** **Beta:** This API may change in future releases. */
|
|
314
359
|
export interface PluginExecResult {
|
|
315
360
|
/** Captured stdout. Empty unless `output` is `"capture"`. */
|
|
316
361
|
stdout: string;
|
|
317
362
|
/** Captured stderr. Empty unless `output` is `"capture"`. */
|
|
318
363
|
stderr: string;
|
|
319
364
|
}
|
|
320
|
-
/**
|
|
365
|
+
/**
|
|
366
|
+
* Values available after all applications in this deploy run have been applied.
|
|
367
|
+
*
|
|
368
|
+
* **Beta:** This API may change in future releases.
|
|
369
|
+
*/
|
|
321
370
|
export interface DeployedContext<PluginConfig = unknown> {
|
|
322
371
|
workspaceId: string;
|
|
323
372
|
/** Application whose config registers this plugin. Only its static websites can be published. */
|
|
@@ -346,10 +395,13 @@ type OutputObject = object & {
|
|
|
346
395
|
/**
|
|
347
396
|
* A value a plugin hook can return in `outputs`. Interface-typed objects are accepted;
|
|
348
397
|
* a `Date` or class instance nested inside one is rejected when the deploy runs.
|
|
398
|
+
*
|
|
399
|
+
* **Beta:** This API may change in future releases.
|
|
349
400
|
*/
|
|
350
401
|
export type PluginOutputValue = string | number | boolean | null | readonly PluginOutputValue[] | {
|
|
351
402
|
[key: string]: PluginOutputValue;
|
|
352
403
|
} | OutputObject;
|
|
404
|
+
/** **Beta:** This API may change in future releases. */
|
|
353
405
|
export interface DeployedHookResult {
|
|
354
406
|
/** Values included in deploy's JSON result. Interface-typed values are accepted, but a `Date` or class instance nested inside one fails the deploy instead of the type check. */
|
|
355
407
|
outputs?: Record<string, PluginOutputValue>;
|