@tailor-platform/sdk 2.5.0 → 2.7.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.
Files changed (104) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/bin/tailor.mjs +3 -2
  3. package/dist/application-D5lh2-_W.mjs +194 -0
  4. package/dist/application-D5lh2-_W.mjs.map +1 -0
  5. package/dist/application-o09L68wE.mjs +1 -0
  6. package/dist/cli/commands/api/index.d.mts +1 -1
  7. package/dist/cli/commands/deploy/config-id-injector.d.mts +16 -0
  8. package/dist/cli/commands/executor/trigger.d.mts +1 -1
  9. package/dist/cli/commands/workflow/start.d.mts +1 -1
  10. package/dist/cli/commands/workspace/create.d.mts +1 -1
  11. package/dist/cli/commands/workspace/list.d.mts +1 -1
  12. package/dist/cli/lib.d.mts +10 -1
  13. package/dist/cli/lib.mjs +1 -1
  14. package/dist/cli/lib.mjs.map +1 -1
  15. package/dist/cli/main.d.mts +2 -0
  16. package/dist/cli/main.mjs +42 -1137
  17. package/dist/cli/main.mjs.map +1 -1
  18. package/dist/cli/shared/args.d.mts +71 -1
  19. package/dist/cli/shared/beta.d.mts +8 -0
  20. package/dist/cli/shared/client.d.mts +11 -1
  21. package/dist/cli/shared/command.d.mts +11 -0
  22. package/dist/cli/shared/config.d.mts +13 -0
  23. package/dist/cli/shared/context.d.mts +1 -1
  24. package/dist/cli/shared/logger.d.mts +64 -0
  25. package/dist/cli/shared/prompt.d.mts +53 -0
  26. package/dist/cli/shared/script-executor.d.mts +2 -2
  27. package/dist/cli/shared/workspace-name.d.mts +10 -1
  28. package/dist/completion/zsh-worker.zsh +10 -206
  29. package/dist/configure/index.mjs +1 -1
  30. package/dist/configure/index.mjs.map +1 -1
  31. package/dist/configure/services/tailordb/schema.d.mts +18 -0
  32. package/dist/configure/services/tailordb/types.d.mts +1 -1
  33. package/dist/{crashreport-B-_HTKLr.mjs → crashreport-BN28xp5B.mjs} +2 -2
  34. package/dist/{crashreport-B-_HTKLr.mjs.map → crashreport-BN28xp5B.mjs.map} +1 -1
  35. package/dist/crashreport-By23O2k-.mjs +1 -0
  36. package/dist/errors-BlX4gUw5.mjs +4 -0
  37. package/dist/errors-BlX4gUw5.mjs.map +1 -0
  38. package/dist/es-builtins-BHCXINQp.mjs +2 -0
  39. package/dist/es-builtins-BHCXINQp.mjs.map +1 -0
  40. package/dist/field-column-type-QMtF6lUp.mjs +2 -0
  41. package/dist/field-column-type-QMtF6lUp.mjs.map +1 -0
  42. package/dist/{kysely-type-BTi3BMtL.mjs → kysely-type-CmvAz1Xj.mjs} +4 -4
  43. package/dist/kysely-type-CmvAz1Xj.mjs.map +1 -0
  44. package/dist/{logger-BcGy-u7G.mjs → logger-CCjs1DuH.mjs} +4 -4
  45. package/dist/logger-CCjs1DuH.mjs.map +1 -0
  46. package/dist/node-builtins-TQHhwNzG.mjs +2 -0
  47. package/dist/node-builtins-TQHhwNzG.mjs.map +1 -0
  48. package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
  49. package/dist/register-ts-hook-CL3Z3VP0.mjs +642 -0
  50. package/dist/register-ts-hook-CL3Z3VP0.mjs.map +1 -0
  51. package/dist/schema-AYG4OhXY.mjs +2 -0
  52. package/dist/{schema-Ze_dI5VX.mjs.map → schema-AYG4OhXY.mjs.map} +1 -1
  53. package/dist/service-COC9whur.mjs +1 -0
  54. package/dist/{service-DlgaUO4V.mjs → service-CqbQXFDp.mjs} +2 -2
  55. package/dist/{service-DlgaUO4V.mjs.map → service-CqbQXFDp.mjs.map} +1 -1
  56. package/dist/{service-BVe9u2Rt.mjs → service-DDon86tM.mjs} +4 -4
  57. package/dist/service-DDon86tM.mjs.map +1 -0
  58. package/dist/service_pb-BNxUPfP3.mjs +2 -0
  59. package/dist/service_pb-BNxUPfP3.mjs.map +1 -0
  60. package/dist/service_pb-D-xFu9Ub.mjs +1 -0
  61. package/dist/shared/src/color.d.mts +5 -0
  62. package/dist/tailor-proto/src/tailor/v1/application_pb.d.mts +12 -0
  63. package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +18 -1
  64. package/dist/tailor-proto/src/tailor/v1/metadata_pb.d.mts +130 -1
  65. package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +43 -4
  66. package/dist/tailor-proto/src/tailor/v1/workflow_pb.d.mts +9 -0
  67. package/dist/tailor-proto/src/tailor/v1/workspace_pb.d.mts +1 -1
  68. package/dist/vitest/environment.mjs +1 -1
  69. package/dist/vitest/environment.mjs.map +1 -1
  70. package/dist/vitest/index.mjs +1 -1
  71. package/dist/wait-point-registry-B-ESkTZX.mjs +2 -0
  72. package/dist/wait-point-registry-B-ESkTZX.mjs.map +1 -0
  73. package/dist/workspace_resource_pb-B7S-zx4Z.mjs +2 -0
  74. package/dist/workspace_resource_pb-B7S-zx4Z.mjs.map +1 -0
  75. package/docs/cli-reference.md +0 -16
  76. package/docs/github-actions.md +16 -3
  77. package/docs/migration/v2.md +5 -1
  78. package/docs/migration/v3.md +39 -0
  79. package/docs/services/tailordb-migration.md +12 -0
  80. package/docs/services/tailordb.md +11 -9
  81. package/package.json +13 -14
  82. package/dist/application-DFOUovmN.mjs +0 -1
  83. package/dist/application-D_4vg1KR.mjs +0 -192
  84. package/dist/application-D_4vg1KR.mjs.map +0 -1
  85. package/dist/crashreport-BmsRIdpy.mjs +0 -1
  86. package/dist/errors-DSEXKRVD.mjs +0 -2
  87. package/dist/errors-DSEXKRVD.mjs.map +0 -1
  88. package/dist/kysely-type-BTi3BMtL.mjs.map +0 -1
  89. package/dist/logger-BcGy-u7G.mjs.map +0 -1
  90. package/dist/node-builtins-oBl7EbyV.mjs +0 -2
  91. package/dist/node-builtins-oBl7EbyV.mjs.map +0 -1
  92. package/dist/register-ts-hook-Drnaproy.mjs +0 -640
  93. package/dist/register-ts-hook-Drnaproy.mjs.map +0 -1
  94. package/dist/schema-Ze_dI5VX.mjs +0 -2
  95. package/dist/service-BVe9u2Rt.mjs.map +0 -1
  96. package/dist/service-CpZELSBa.mjs +0 -1
  97. package/dist/service_pb-DGKCLuAs.mjs +0 -2
  98. package/dist/service_pb-DGKCLuAs.mjs.map +0 -1
  99. package/dist/service_pb-_aeFE-Nv.mjs +0 -1
  100. package/dist/wait-point-registry-BrkwfyjS.mjs +0 -2
  101. package/dist/wait-point-registry-BrkwfyjS.mjs.map +0 -1
  102. package/dist/workspace_resource_pb--GeYQPXu.mjs +0 -2
  103. package/dist/workspace_resource_pb--GeYQPXu.mjs.map +0 -1
  104. package/docs/cli/setup.md +0 -210
package/dist/cli/main.mjs CHANGED
@@ -1,1203 +1,107 @@
1
1
  #!/usr/bin/env node
2
- import{r as e}from"../schema-Ze_dI5VX.mjs";import{Bt as t,E as n,Et as r,G as i,Nt as a}from"../workspace_resource_pb--GeYQPXu.mjs";import{t as o}from"../assert-WeXvmG4j.mjs";import{n as s,r as c}from"../logger-BcGy-u7G.mjs";import{$ as l,$n as u,$t as d,An as f,Ar as p,At as m,B as h,Br as g,Bt as _,C as v,Cn as y,Cr as b,Ct as x,Dn as S,Dr as C,Dt as w,E as T,En as E,Er as D,Fn as O,Fr as ee,Gn as te,Gr as k,Hn as ne,Hr as re,Ht as ie,I as ae,In as A,Ir as oe,Jn as se,Jr as ce,Jt as le,K as ue,Kn as de,Kr as fe,L as pe,Lr as me,Lt as he,M as ge,Mn as _e,Mr as j,N as ve,Nn as ye,Nr as be,Nt as xe,O as Se,On as Ce,Or as we,P as Te,Pn as Ee,Pr as M,Qn as De,Qr as N,Qt as Oe,R as ke,Rr as Ae,Sn as je,Sr as Me,St as Ne,Tn as Pe,Tr as Fe,Tt as Ie,U as Le,Un as Re,Ur as ze,W as P,Wr as F,Wt as Be,X as Ve,Xr as He,Yn as Ue,Yr as We,Z as Ge,Zn as Ke,Zr as qe,Zt as Je,_n as Ye,_r as Xe,_t as Ze,a as Qe,an as $e,ar as et,at as tt,bn as nt,br as I,bt as rt,c as it,cn as at,cr as L,dn as ot,dr as st,dt as ct,en as lt,er as ut,f as dt,fn as ft,fr as pt,g as mt,gn as ht,gr as gt,gt as _t,hn as vt,hr as yt,ir as bt,j as xt,jn as St,jr as Ct,jt as wt,kn as Tt,kr as Et,lr as Dt,lt as Ot,m as kt,mn as At,mr as jt,nn as Mt,nr as Nt,o as Pt,on as Ft,or as It,pn as Lt,pr as R,pt as Rt,q as zt,qr as Bt,qt as Vt,r as Ht,rn as Ut,rr as Wt,rt as Gt,sn as Kt,sr as qt,st as Jt,t as Yt,tr as Xt,tt as Zt,u as Qt,un as $t,ur as en,v as tn,vn as nn,vr as z,w as rn,wn as an,wr as on,wt as sn,x as cn,xn as ln,xr as B,xt as un,yr as dn,yt as fn,z as pn,zr as V}from"../register-ts-hook-Drnaproy.mjs";import{A as mn,C as hn,D as gn,E as _n,G as vn,H as yn,I as bn,J as xn,K as Sn,L as Cn,O as wn,R as Tn,T as En,U as Dn,V as On,X as kn,Y as H,_ as An,a as jn,d as Mn,f as Nn,k as Pn,m as Fn,o as In,q as Ln,u as Rn,v as zn,w as Bn,z as Vn}from"../application-D_4vg1KR.mjs";import{h as Hn,i as Un,r as Wn}from"../service-BVe9u2Rt.mjs";import{t as U}from"../multiline-EyzjEwn9.mjs";import{t as Gn}from"../package-json-C690ceex.mjs";import{t as Kn}from"../user-agent-vdHYF3QL.mjs";import{a as qn,i as Jn,n as Yn,o as Xn,r as Zn,t as Qn}from"../errors-DSEXKRVD.mjs";import{t as $n}from"../service_pb-DGKCLuAs.mjs";import{a as er,i as tr,o as nr,r as rr,t as ir}from"../crashreport-B-_HTKLr.mjs";import{a as ar,i as or,n as sr}from"../kysely-type-BTi3BMtL.mjs";import*as W from"pathe";import{dirname as cr,resolve as lr}from"pathe";import{resolvePackageJSON as ur}from"pkg-types";import{arg as G,defineCommand as K,extractFields as dr,runCommand as q,runMain as fr,toCamelCase as pr}from"politty";import{withCompletionCommand as mr}from"politty/completion";import{withSkillCommand as hr}from"politty/skill";import{z as J}from"zod";import{ScalarType as Y,create as gr}from"@bufbuild/protobuf";import*as X from"node:fs";import{accessSync as _r,constants as vr,readdirSync as yr}from"node:fs";import{timestampDate as br}from"@bufbuild/protobuf/wkt";import{pathToFileURL as xr}from"node:url";import{generateCodeVerifier as Sr}from"@badgateway/oauth2-client";import{Code as Z,ConnectError as Q}from"@connectrpc/connect";import*as Cr from"node:crypto";import{createHash as wr,randomBytes as Tr}from"node:crypto";import*as Er from"node:http";import Dr from"open";import*as Or from"rolldown";import{parseSync as kr}from"oxc-parser";import*as Ar from"node:os";import*as $ from"node:fs/promises";import{TraceMap as jr,generatedPositionFor as Mr,originalPositionFor as Nr}from"@jridgewell/trace-mapping";import{spawn as Pr,spawnSync as Fr}from"node:child_process";const Ir=$n.methods.filter(e=>e.methodKind===`unary`);function listMethodNames(){return Ir.map(e=>e.name).toSorted()}function listMethodChoices(){return Ir.flatMap(e=>[e.name,`${$n.typeName}/${e.name}`]).toSorted()}function getMethodDescriptor(e){return Ir.find(t=>t.name===e)}function extractMethodName(e){return e.includes(`/`)?e.split(`/`).pop()??e:e}function nestedMessage(e){if(e.fieldKind===`message`||e.fieldKind===`list`&&e.listKind===`message`||e.fieldKind===`map`&&e.mapKind===`message`)return e.message}function isWellKnownType(e){return e.typeName.startsWith(`google.protobuf.`)}const Lr=new Set([`google.protobuf.Struct`,`google.protobuf.Value`,`google.protobuf.ListValue`,`google.protobuf.NullValue`,`google.protobuf.Any`,`google.protobuf.Empty`]);function isUnrepresentableWellKnownType(e){return Lr.has(e.typeName)}function enumerateAllFieldCompletions(e){let t=getMethodDescriptor(e);if(!t)return[];let n=[],r=new Set;function walk(e,t){r.add(e);for(let i of e.fields){if(i.fieldKind===`list`||i.fieldKind===`map`)continue;let e=t+i.localName;if(i.fieldKind===`message`){if(isUnrepresentableWellKnownType(i.message))continue;if(!isWellKnownType(i.message)){let t=i.message;n.push({value:`${e}.`,description:`${e} (message)`}),r.has(t)||walk(t,`${e}.`);continue}}if(n.push({value:`${e}=`,description:`Set ${e}`}),i.fieldKind===`enum`)for(let t of i.enum.values)n.push({value:`${e}=${t.name}`,description:t.name});else i.fieldKind===`scalar`&&i.scalar===Y.BOOL&&(n.push({value:`${e}=true`,description:`true`}),n.push({value:`${e}=false`,description:`false`}))}r.delete(e)}return walk(t.input,``),n}function resolveLeafField(e,t){let n=e;for(let e=0;e<t.length;e++){let r=n.fields.find(n=>n.localName===t[e]);if(!r)return;if(e===t.length-1)return r.fieldKind===`message`&&isUnrepresentableWellKnownType(r.message)?void 0:r;if(r.fieldKind!==`message`||isWellKnownType(r.message))return;n=r.message}}const Rr={[Y.DOUBLE]:`double`,[Y.FLOAT]:`float`,[Y.INT64]:`int64`,[Y.UINT64]:`uint64`,[Y.INT32]:`int32`,[Y.FIXED64]:`fixed64`,[Y.FIXED32]:`fixed32`,[Y.BOOL]:`bool`,[Y.STRING]:`string`,[Y.BYTES]:`bytes`,[Y.UINT32]:`uint32`,[Y.SFIXED32]:`sfixed32`,[Y.SFIXED64]:`sfixed64`,[Y.SINT32]:`sint32`,[Y.SINT64]:`sint64`};function shortName(e){let t=e.lastIndexOf(`.`);return t<0?e:e.slice(t+1)}function scalarLabel(e){return Rr[e]??`scalar(${e})`}function enumLabel(e){return`enum ${shortName(e.typeName)}`}function enumOf(e){if(e.fieldKind===`enum`||e.fieldKind===`list`&&e.listKind===`enum`)return e.enum}function describeFieldType(e){switch(e.fieldKind){case`scalar`:return scalarLabel(e.scalar);case`enum`:return enumLabel(e.enum);case`message`:return shortName(e.message.typeName);case`list`:{let t;return t=e.listKind===`scalar`?scalarLabel(e.scalar):e.listKind===`enum`?enumLabel(e.enum):shortName(e.message.typeName),`repeated ${t}`}case`map`:{let t=scalarLabel(e.mapKey),n;return n=e.mapKind===`scalar`?scalarLabel(e.scalar):e.mapKind===`enum`?enumLabel(e.enum):shortName(e.message.typeName),`map<${t}, ${n}>`}default:return`<unknown>`}}function fieldToJson(e,t){let n={name:e.localName,protoName:e.name,type:describeFieldType(e),fieldKind:e.fieldKind,repeated:e.fieldKind===`list`};e.oneof&&(n.oneof=e.oneof.name);let r=enumOf(e);r&&(n.enumValues=r.values.map(e=>e.name));let i=nestedMessage(e);return i&&!t.has(i)?(t.add(i),n.message={typeName:i.typeName,fields:i.fields.map(e=>fieldToJson(e,t))},t.delete(i)):i&&(n.message={typeName:i.typeName,fields:[],recursive:!0}),n}function renderInspectJson(e){let t=new Set([e.input]);return{method:e.name,input:{typeName:e.input.typeName,fields:e.input.fields.map(e=>fieldToJson(e,t))},output:{typeName:e.output.typeName}}}function renderFieldText(e,t,n){let r=[],i=e.oneof?` (oneof ${e.oneof.name})`:``;r.push(`${t}${e.localName}: ${describeFieldType(e)}${i}`);let a=enumOf(e);if(a){let e=a.values.map(e=>e.name).join(`, `);r.push(`${t} values: ${e}`)}let o=nestedMessage(e);if(o&&!n.has(o)){n.add(o);for(let e of o.fields)r.push(...renderFieldText(e,`${t} `,n));n.delete(o)}else o&&r.push(`${t} …(recursive ${o.typeName})`);return r}function renderInspectText(e){let t=[];t.push(`${e.name}`),t.push(` request: ${e.input.typeName}`);let n=new Set([e.input]);for(let r of e.input.fields)t.push(...renderFieldText(r,` `,n));return t.push(` response: ${e.output.typeName}`),t.join(`
3
- `)}const zr=g({name:`inspect`,description:`Print the input message tree of an OperatorService endpoint.`,notes:"Combine with the global `--json` flag for a machine-readable descriptor. Recursive type references and `oneof` membership are annotated. Use `tailor api list` to discover endpoint names.",examples:[{cmd:`GetApplication`,desc:`Show fields of GetApplicationRequest.`},{cmd:`CreateExecutorExecutor`,desc:"Inspect a deeply nested input with `(oneof config)` annotations."}],args:J.strictObject({endpoint:G(J.string(),{positional:!0,description:`API endpoint to inspect (e.g., 'GetApplication' or 'tailor.v1.OperatorService/GetApplication').`,completion:{custom:{choices:listMethodNames()}}})}),run:e=>{let t=extractMethodName(e.endpoint),n=getMethodDescriptor(t);if(!n)throw Qn({message:`unknown method: ${t}`,suggestion:"Run `tailor api list` to see available methods.",command:`api inspect`});s.jsonMode?s.out(renderInspectJson(n)):s.out(renderInspectText(n))}}),Br=g({name:`list`,description:`List all invocable OperatorService methods.`,notes:`Only single-request (non-streaming) methods are listed, because the CLI issues a single JSON request and reads one JSON response.`,args:J.strictObject({}),run:()=>{let e=listMethodNames();if(s.jsonMode)s.out(e);else for(let t of e)s.out(t)}});function resolveNamespaceName(e,t){if(/Auth|Tenant|UserProfile/.test(e))return t.auth?.name;if(/IdP/.test(e))return t.idp?.length===1?o(t.idp[0],`idp config missing`).name:void 0;if(/TailorDB/.test(e)){let e=Object.keys(t.db??{});return e.length===1?e[0]:void 0}if(/Pipeline/.test(e)){let e=Object.keys(t.resolver??{});return e.length===1?e[0]:void 0}}function parseBodyAsObject(e){let t;try{t=JSON.parse(e)}catch{return}if(!(typeof t!=`object`||!t||Array.isArray(t)))return t}function setNestedPath(e,t,n){let r=e;for(let e=0;e<t.length-1;e++){let n=o(t[e],`path segment missing`),i=r[n];(typeof i!=`object`||!i||Array.isArray(i))&&(r[n]={}),r=r[n]}r[o(t[t.length-1],`path last segment missing`)]=n}function coerceFieldValue(e,t){if(e&&e.fieldKind===`scalar`&&e.scalar===Y.BOOL){if(t===`true`)return!0;if(t===`false`)return!1;throw Error(`Invalid value for bool field: '${t}'. Expected 'true' or 'false'.`)}return t}function normalizeBodyFieldKeys(e,t){let n=new Map;for(let e of t)n.set(e.name,e.localName),n.set(e.jsonName,e.localName);let r=!1;for(let t of Object.keys(e)){let i=n.get(t);!i||i===t||(Object.hasOwn(e,i)||(e[i]=e[t]),delete e[t],r=!0)}return r}const Vr=new Set([`__proto__`,`constructor`,`prototype`]),Hr=J.string().transform((e,t)=>{let n=e.indexOf(`=`);if(n<0)return t.addIssue({code:J.ZodIssueCode.custom,message:`Invalid field format: '${e}'. Expected format: 'key=value' or 'a.b.c=value'`}),J.NEVER;let r=e.slice(0,n);if(r.length===0)return t.addIssue({code:J.ZodIssueCode.custom,message:`Field key cannot be empty`}),J.NEVER;let i=r.split(`.`);if(i.some(e=>e.length===0))return t.addIssue({code:J.ZodIssueCode.custom,message:`Invalid field key: '${r}'. Dotted segments cannot be empty`}),J.NEVER;let a=i.find(e=>Vr.has(e));return a?(t.addIssue({code:J.ZodIssueCode.custom,message:`Invalid field key: '${r}'. Segment '${a}' is not allowed.`}),J.NEVER):{path:i,value:e.slice(n+1)}}),Ur=g({name:`api`,description:`Call Tailor Platform API endpoints directly.`,notes:"Use `tailor api list` to enumerate invocable methods and `tailor api inspect <endpoint>` to print an endpoint's input message tree (combine with `--json` for machine-readable output).\n\nThe request body is inferred from the target endpoint's request schema, and commonly required fields are auto-injected so they can be omitted from `--body`:\n\n- `workspaceId` — resolved from `-w` / `TAILOR_PLATFORM_WORKSPACE_ID` / the selected profile.\n- `namespaceName` — resolved from `tailor.config.ts` based on the endpoint's service:\n - Auth / Tenant / UserProfile endpoints use `auth.name`.\n - IdP / TailorDB / Pipeline endpoints use the sole configured namespace when exactly one is defined.\n\nValues already present in `--body` are never overridden. If a value cannot be resolved (e.g. no config found), injection is silently skipped and the server-side validation error takes precedence.\n\nUse `--field key=value` (repeatable) to set request body fields without writing JSON. Dotted keys (e.g. `application.name=foo`) build nested objects. `--field` overrides matching fields in `--body` and tab-completes from the endpoint's request schema.",examples:[{cmd:`GetApplication -b '{"applicationName":"app-1"}'`,desc:`Call an endpoint; workspaceId is auto-injected.`},{cmd:`GetApplication -f applicationName=app-1`,desc:`Same as above, using --field instead of --body.`},{cmd:`list`,desc:`List all invocable OperatorService methods.`},{cmd:`inspect GetApplication`,desc:`Show the input message tree for an endpoint.`}],subCommands:{list:Br,inspect:zr},args:J.strictObject({...N,...ze,body:G(J.string().default(`{}`),{alias:`b`,description:`Request body as JSON.`}),field:G(Hr.array().optional(),{alias:`f`,description:"Set a body field as `key=value` (repeatable; dotted keys nest). Overrides --body.",completion:{custom:{expand:{dependsOn:[`endpoint`],enumerate:({endpoint:e})=>enumerateAllFieldCompletions(extractMethodName(e??``))}}}}),endpoint:G(J.string(),{positional:!0,description:`API endpoint to call (e.g., 'GetApplication' or 'tailor.v1.OperatorService/GetApplication').`,completion:{custom:{choices:listMethodChoices()}}})}),run:async e=>{await I({profile:e.profile});let t=extractMethodName(e.endpoint),n=getMethodDescriptor(t),r=parseBodyAsObject(e.body),i=!1;if(e.field&&e.field.length>0){if(!r)throw Error(`--field requires --body to be a JSON object (or omitted).`);for(let t of e.field){let e=n?resolveLeafField(n.input,t.path):void 0;setNestedPath(r,t.path,coerceFieldValue(e,t.value))}i=!0}if(r&&n){normalizeBodyFieldKeys(r,n.input.fields)&&(i=!0);let a=n.input.fields.map(e=>e.localName);if(a.includes(`workspaceId`)&&!Object.hasOwn(r,`workspaceId`))try{r.workspaceId=await j({workspaceId:e[`workspace-id`],profile:e.profile}),i=!0}catch{}if(a.includes(`namespaceName`)&&!Object.hasOwn(r,`namespaceName`))try{let{config:n}=await B(e.config),a=resolveNamespaceName(t,n);a&&(r.namespaceName=a,i=!0)}catch{}}let a=await dn({profile:e.profile,endpoint:e.endpoint,body:i&&r?JSON.stringify(r):e.body});s.out(JSON.stringify(a.data,null,2))}}),Wr=g({name:`token`,description:`Print a valid Tailor Platform access token to stdout, refreshing it first if expired.`,args:J.strictObject({profile:N.profile}),run:async({profile:e})=>{let t=await D({profile:e});s.out(t)}}),Gr=K({name:`auth`,description:`Authentication helpers for scripts and plugins.`,subCommands:{token:Wr}}),Kr={name:G(J.string(),{alias:`n`,description:`Auth connection name`})};async function fetchOIDCDiscovery(e){let t=e.replace(/\/$/,``)+`/.well-known/openid-configuration`,n=await fetch(t).catch(e=>{throw Error(`Failed to fetch OIDC discovery from ${t}: ${qn(e).message}`,{cause:e})});if(!n.ok)throw Error(`Failed to fetch OIDC discovery from ${t}: ${n.status}`);return n.json()}function randomState$1(){return Cr.randomBytes(32).toString(`base64url`)}const qr=g({name:`authorize`,description:`Authorize an auth connection via OAuth2 flow.`,args:J.strictObject({...N,...Kr,scopes:J.string().optional().default(`openid,profile,email`).describe(`OAuth2 scopes to request (comma-separated)`),port:J.coerce.number().optional().default(8080).describe(`Local callback server port`),"no-browser":J.boolean().optional().default(!1).describe(`Don't open browser automatically`)}),run:async e=>{await I({profile:e.profile});let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile}),i=(await Tn(async(e,t)=>{let{connections:i,nextPageToken:a}=await n.listAuthConnections({workspaceId:r,pageToken:e,pageSize:t});return[i,a]})).find(t=>t.name===e.name);if(!i)throw Error(`Auth connection "${e.name}" not found.`);if(i.config.case!==`oauth2`)throw Error(`Auth connection "${e.name}" is not an OAuth2 connection.`);let a=i.config.value,o=`http://localhost:${e.port}/callback`,c=randomState$1(),l;l=a.authUrl?a.authUrl:(await fetchOIDCDiscovery(a.providerUrl)).authorization_endpoint;let u=new URL(l);u.searchParams.set(`client_id`,a.clientId),u.searchParams.set(`redirect_uri`,o),u.searchParams.set(`response_type`,`code`),u.searchParams.set(`scope`,e.scopes.replace(/,/g,` `)),u.searchParams.set(`state`,c),u.searchParams.set(`access_type`,`offline`),await new Promise((t,i)=>{let handleCallback=async(s,l)=>{if(!s.url?.startsWith(`/callback`)){l.writeHead(404),l.end(`Not found`);return}try{let i=new URL(s.url,`http://localhost:${e.port}`),u=i.searchParams.get(`code`),d=i.searchParams.get(`state`),f=i.searchParams.get(`error`);if(f)throw Error(`Authorization failed: ${f}`);if(d!==c)throw Error(`State mismatch — possible CSRF attack.`);if(!u)throw Error(`No authorization code received.`);await n.exchangeAuthConnectionAuthorizationCode({workspaceId:r,connectionName:e.name,authorizationCode:u,redirectUri:o}),l.writeHead(200,{"Content-Type":`text/html`}),l.end(`<html><body><h1>Authorization successful</h1><p>You can close this window.</p></body></html>`),a.close(),t()}catch(e){l.writeHead(400,{"Content-Type":`text/plain`}),l.end(`Authorization failed: ${e instanceof Error?e.message:`Unknown error`}`),a.close(),i(qn(e))}},a=Er.createServer((e,t)=>void handleCallback(e,t)),l=setTimeout(()=>{a.close(),i(Error(`Authorization timeout exceeded (5 minutes).`))},3e5);a.on(`close`,()=>{clearTimeout(l)}),a.on(`error`,t=>{clearTimeout(l);let n=t.code,r=n===`EADDRINUSE`||n===`EACCES`?`Try a different port with --port, or authorize via the Console instead:`:`Authorize via the Console instead:`;s.warn(`Could not start the local callback server on port ${e.port}${n?` (${n})`:``}.\n${r}\n tailor authconnection open`),i(t)});let announceAuthorizeUrl=async()=>{let t=u.toString();if(s.info(e[`no-browser`]?`Open this URL in your browser to authorize:\n\n${t}\n`:`Opening browser for authorization:\n\n${t}\n`),s.info(`If this flow doesn't complete, you can authorize via the Console instead:
4
- tailor authconnection open`),!e[`no-browser`])try{await Dr(t)}catch{s.warn(`Failed to open browser automatically. Please open the URL above manually.`)}};a.listen(e.port,()=>void announceAuthorizeUrl())}),s.success(`Auth connection "${e.name}" authorized successfully.`)}}),Jr=g({name:`delete`,description:`Delete an auth connection entirely.`,args:J.strictObject({...N,...Kr,...F}),run:async e=>{await I({profile:e.profile});let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile});if(!e.yes&&await z.text({message:`Enter the connection name to confirm deletion ("${e.name}"):`})!==e.name){s.info(`Auth connection deletion cancelled.`);return}try{await n.deleteAuthConnection({workspaceId:r,connectionName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Auth connection "${e.name}" not found.`,{cause:t}):t}s.success(`Auth connection "${e.name}" deleted.`)}});function connectionInfo(e){let t=e.config.case===`oauth2`?e.config.value:void 0;return{name:e.name,type:e.config.case??`unknown`,providerUrl:t?.providerUrl??``,issuerUrl:t?.issuerUrl??``,clientId:t?.clientId??``,authUrl:t?.authUrl??``,tokenUrl:t?.tokenUrl??``,createdAt:e.createdAt?br(e.createdAt):null}}const Yr=g({name:`list`,description:`List all auth connections.`,args:J.strictObject({...N,...We()}),run:async e=>{let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile});try{let t=qe(e.order),i=await On(async(e,i)=>{let{connections:a,nextPageToken:o}=await n.listAuthConnections({workspaceId:r,pageToken:e,pageSize:i,pageDirection:t});return[a,o]},{limit:e.limit});s.out(i.map(connectionInfo))}catch(e){if(e instanceof Q&&e.code===Z.NotFound){s.out([]);return}throw e}}}),Xr=g({name:`open`,description:`Open the auth connections page in the Tailor Platform Console.`,args:J.strictObject({...N}),run:async e=>{let t=await j({workspaceId:e[`workspace-id`],profile:e.profile}),n=`/workspaces/${t}/settings/connections`,r=await we({profile:e.profile,...e[`workspace-id`]===void 0?{}:{allowMissingProfile:!0}}),i=new URL(n,r).toString(),a=s.jsonMode;s.info(`Opening auth connections page in Tailor Platform Console...`);let o=!0;try{await Dr(i)}catch{o=!1}if(a){s.out({consoleUrl:i,workspaceId:t,opened:o});return}o?(s.out(`Console URL: ${i}`),s.out(`Workspace ID: ${t}`)):s.warn(`Failed to open browser automatically. Please open this URL manually:\n${i}`)}}),Zr=g({name:`revoke`,description:`Revoke an auth connection's tokens (keeps the connection; use 'delete' to remove it).`,notes:"Revoke invalidates the connection's active session and tokens but keeps the connection and its stored credentials, so it can be re-authorized later. Use `delete` to remove the connection entirely.",args:J.strictObject({...N,...Kr,...F}),run:async e=>{await I({profile:e.profile});let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile});if(!e.yes&&await z.text({message:`Enter the connection name to confirm revocation ("${e.name}"):`})!==e.name){s.info(`Auth connection revocation cancelled.`);return}try{await n.revokeAuthConnection({workspaceId:r,connectionName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Auth connection "${e.name}" not found.`,{cause:t}):t}s.success(`Auth connection "${e.name}" revoked.`)}}),Qr=K({name:`authconnection`,description:`Manage auth connections.`,subCommands:{authorize:qr,list:Yr,open:Xr,revoke:Zr,delete:Jr},async run(){await q(Yr,[])}});function orderAndLimitCrashReports(e,t){let n=e.filter(e=>e.endsWith(tr)).toSorted(),r=t.order===`asc`?n:n.toReversed();return t.limit&&t.limit>0?r.slice(0,t.limit):r}function formatCrashReportFiles(e,t){return e.map(e=>({file:e,path:W.join(t,e)}))}const $r=g({name:`list`,description:`List local crash report files.`,args:J.strictObject({...We()}),run:async e=>{let t=nr(),n=s.jsonMode;if(!t.localDir){s.info(`Crash report directory not available.`),n&&s.out([]);return}let r;try{r=X.readdirSync(t.localDir)}catch{s.info(`No crash reports found.`),n&&s.out([]);return}let i=orderAndLimitCrashReports(r,{order:e.order,limit:e.limit});if(i.length===0){s.info(`No crash reports found.`),n&&s.out([]);return}if(n){s.out(formatCrashReportFiles(i,t.localDir));return}s.info(`${i.length} crash report(s) in ${t.localDir}:`);for(let e of i)s.log(` ${e}`)}}),ei=g({name:`send`,description:`Submit a crash report to help improve the SDK.`,args:J.strictObject({file:G(J.string(),{description:`Path to the crash report file`,required:!0,completion:{type:`file`,extensions:[`log`]}})}),run:async e=>{let t;try{t=X.readFileSync(e.file,`utf-8`)}catch{s.error(`Crash report file not found: ${e.file}`),process.exit(1)}let n=parseCrashLogFile(t);n||(s.error(`Failed to parse crash report file. The file may be corrupted.`),process.exit(1));let r=await Kn();s.info(`Sending crash report...`),await rr(n,r)?s.success(`Crash report submitted successfully. Thank you!`):(s.error(`Failed to submit crash report. The server may be unavailable.`),process.exit(1))}});function parseCrashLogFile(e){try{let t=e.replace(/\r\n/g,`
5
- `),n=`\n${er}\n`,r=t.lastIndexOf(n);if(r===-1)return;let i=t.slice(r+n.length).split(`
6
- `)[0];return i?JSON.parse(i):void 0}catch{return}}const ti=K({name:`crashreport`,description:`Manage crash reports.`,subCommands:{list:$r,send:ei},async run(){await q($r,[])}}),ni=g({name:`deploy`,description:`Deploy your application by applying the Tailor configuration.`,args:J.strictObject({...N,...Bt,...F,"create-workspace":G(J.boolean().optional(),{description:`Create a workspace when the account has none`}),"workspace-name":G(J.string().optional(),{description:`Name for a workspace created during deploy`}),"workspace-region":G(J.string().optional(),{description:`Region for a workspace created during deploy`}),"organization-id":G(J.string().optional(),{description:`Organization ID for a workspace created during deploy`,env:`TAILOR_PLATFORM_ORGANIZATION_ID`}),"folder-id":G(J.string().optional(),{description:`Folder ID for a workspace created during deploy`,env:`TAILOR_PLATFORM_FOLDER_ID`}),"dry-run":G(J.boolean().optional(),{alias:`d`,description:`Run the command without making any changes`}),"no-schema-check":G(J.boolean().optional(),{description:`Skip schema diff check against migration snapshots`}),"no-validate":G(J.boolean().optional(),{description:`Skip client-side validation against platform resource constraints`}),"no-cache":G(J.boolean().optional(),{description:`Disable bundle caching for this run`}),"clean-cache":G(J.boolean().optional(),{description:`Clean the bundle cache before building`})}),run:async e=>{await I({profile:e.profile});let{initTelemetry:t}=await import(`../telemetry-DXHP3VVi.mjs`);await t(),await Je({workspaceId:e[`workspace-id`],profile:e.profile,configPath:e.config,dryRun:e[`dry-run`],yes:e.yes,createWorkspace:e[`create-workspace`],workspaceName:e[`workspace-name`],workspaceRegion:e[`workspace-region`],organizationId:e[`organization-id`],folderId:e[`folder-id`],noSchemaCheck:e[`no-schema-check`],noValidate:e[`no-validate`],noCache:e[`no-cache`],cleanCache:e[`clean-cache`]},{envFile:e[`env-file`],envFileIfExists:e[`env-file-if-exists`],verbose:e.verbose,json:e.json})}}),ri=K({name:`executor`,description:`Manage executors`,subCommands:{trigger:wt,jobs:he,list:xe,get:le,webhook:m},async run(){await q(xe,[])}});function scriptNameToRegistryName(e,t){if(t===i.JOB)return`workflow--${e}`;let n=/^([^.]+)\.(.+)\.body\.js$/.exec(e);if(n){let[,e,t]=n;return`resolver--${e}--${t}`}let r=/^(.+)\.operation\.js$/.exec(e);if(r){let[,e]=r;return`executor--${e}`}let a=/^([^.]+)\.([^.]+)\.hook\.js$/.exec(e);if(a){let[,e,t]=a;return`auth-hook--${e}--${t}`}return t===i.UNSPECIFIED&&!e.includes(`.`)?`workflow--${e}`:null}async function downloadFunctionScript(e){let{client:t,workspaceId:n,name:r,contentHash:i}=e;try{let e=[];for await(let a of t.downloadFunctionRegistryScript({workspaceId:n,name:r,contentHash:i}))a.payload.case===`chunk`&&e.push(a.payload.value);return e.length===0?null:{code:Buffer.concat(e).toString(`utf-8`)}}catch(t){return s.debug(`Failed to download function script "${e.name}": ${t}`),null}}const ii=/^\s+at\s+(?:(.+?)\s+\()?(file:\/\/\/.+?):(\d+):(\d+)\)?$/;function parseStackTrace(e){let t=e.split(`
2
+ import{r as e}from"../schema-AYG4OhXY.mjs";import{E as t,Ft as n,Ht as r,Ot as i,q as a}from"../workspace_resource_pb-B7S-zx4Z.mjs";import{t as o}from"../assert-WeXvmG4j.mjs";import{n as s,r as c}from"../logger-CCjs1DuH.mjs";import{$ as l,$n as u,$r as d,$t as f,An as p,Ar as m,B as h,Br as g,C as _,Cn as v,Cr as y,Ct as b,Dn as x,Dr as S,Dt as C,E as w,En as T,Er as E,Fn as ee,Fr as te,Ft as ne,Gn as re,Hn as ie,Hr as ae,Ht as oe,I as se,In as D,Ir as ce,Jn as le,Jr as ue,K as de,Kn as fe,Kr as O,Kt as pe,L as me,Lr as he,M as ge,Mn as _e,Mr as k,Mt as ve,N as ye,Nn as be,Nr as A,Nt as xe,O as Se,On as Ce,Or as we,P as Te,Pn as Ee,Pr as j,Qn as De,Qr as Oe,R as ke,Rr as Ae,Sn as je,Sr as Me,St as Ne,Tn as Pe,Tr as Fe,Tt as Ie,Un as Le,Ur as Re,V as ze,W as Be,Wr as M,Wt as Ve,X as He,Xr as Ue,Xt as We,Yn as Ge,Yr as Ke,Yt as qe,Z as Je,Zn as Ye,Zr as Xe,_n as Ze,_r as Qe,_t as $e,a as et,an as tt,ar as nt,at as rt,bn as it,br as N,bt as at,c as ot,cr as P,dr as st,dt as ct,en as lt,er as ut,f as dt,fn as ft,fr as pt,g as mt,gn as ht,gr as gt,gt as _t,hn as vt,hr as yt,in as bt,ir as xt,j as St,jn as Ct,jr as wt,kn as Tt,kr as Et,kt as Dt,lr as Ot,lt as kt,m as At,mn as jt,mr as Mt,nn as Nt,nr as Pt,o as Ft,or as It,pn as Lt,pr as F,pt as Rt,q as zt,r as Bt,rr as Vt,rt as Ht,sn as Ut,sr as I,st as Wt,t as Gt,tn as Kt,tr as qt,tt as Jt,u as Yt,un as Xt,ur as Zt,v as Qt,vn as $t,vr as L,w as en,wn as tn,wr as nn,wt as rn,x as an,xn as on,xr as R,xt as sn,yn as cn,yr as ln,yt as un,z as dn,zr as z,zt as fn}from"../register-ts-hook-CL3Z3VP0.mjs";import{A as pn,B as mn,D as hn,E as gn,G as _n,J as vn,M as yn,O as bn,Q as xn,R as Sn,T as Cn,U as B,V as wn,W as Tn,X as En,Y as Dn,Z as V,_ as On,a as kn,d as An,f as jn,j as Mn,k as Nn,m as Pn,o as Fn,q as In,u as Ln,v as Rn,z as zn}from"../application-D5lh2-_W.mjs";import{h as Bn,i as Vn,r as Hn}from"../service-DDon86tM.mjs";import{t as H}from"../multiline-EyzjEwn9.mjs";import{t as Un}from"../package-json-C690ceex.mjs";import{t as Wn}from"../user-agent-vdHYF3QL.mjs";import{a as Gn,i as Kn,n as qn,o as Jn,r as Yn,t as Xn}from"../errors-BlX4gUw5.mjs";import{t as Zn}from"../service_pb-BNxUPfP3.mjs";import{a as Qn,i as $n,o as er,r as tr,t as nr}from"../crashreport-BN28xp5B.mjs";import{a as rr,i as ir,n as ar}from"../kysely-type-CmvAz1Xj.mjs";import*as U from"pathe";import{dirname as or,resolve as sr}from"pathe";import{resolvePackageJSON as cr}from"pkg-types";import{arg as W,defineCommand as G,extractFields as lr,runCommand as K,runMain as ur,toCamelCase as dr}from"politty";import{withCompletionCommand as fr}from"politty/completion";import{withSkillCommand as pr}from"politty/skill";import{z as q}from"zod";import{ScalarType as J,create as mr}from"@bufbuild/protobuf";import*as Y from"node:fs";import{accessSync as hr,constants as gr,readdirSync as _r}from"node:fs";import{timestampDate as X}from"@bufbuild/protobuf/wkt";import{pathToFileURL as vr}from"node:url";import{generateCodeVerifier as yr}from"@badgateway/oauth2-client";import{Code as Z,ConnectError as Q}from"@connectrpc/connect";import*as br from"node:crypto";import{randomBytes as xr}from"node:crypto";import*as Sr from"node:http";import Cr from"open";import*as wr from"rolldown";import{parseSync as Tr}from"oxc-parser";import*as Er from"node:os";import*as $ from"node:fs/promises";import{TraceMap as Dr,generatedPositionFor as Or,originalPositionFor as kr}from"@jridgewell/trace-mapping";import{spawn as Ar,spawnSync as jr}from"node:child_process";const Mr=Zn.methods.filter(e=>e.methodKind===`unary`);function listMethodNames(){return Mr.map(e=>e.name).toSorted()}function listMethodChoices(){return Mr.flatMap(e=>[e.name,`${Zn.typeName}/${e.name}`]).toSorted()}function getMethodDescriptor(e){return Mr.find(t=>t.name===e)}function extractMethodName(e){return e.includes(`/`)?e.split(`/`).pop()??e:e}function nestedMessage(e){if(e.fieldKind===`message`||e.fieldKind===`list`&&e.listKind===`message`||e.fieldKind===`map`&&e.mapKind===`message`)return e.message}function isWellKnownType(e){return e.typeName.startsWith(`google.protobuf.`)}const Nr=new Set([`google.protobuf.Struct`,`google.protobuf.Value`,`google.protobuf.ListValue`,`google.protobuf.NullValue`,`google.protobuf.Any`,`google.protobuf.Empty`]);function isUnrepresentableWellKnownType(e){return Nr.has(e.typeName)}function enumerateAllFieldCompletions(e){let t=getMethodDescriptor(e);if(!t)return[];let n=[],r=new Set;function walk(e,t){r.add(e);for(let i of e.fields){if(i.fieldKind===`list`||i.fieldKind===`map`)continue;let e=t+i.localName;if(i.fieldKind===`message`){if(isUnrepresentableWellKnownType(i.message))continue;if(!isWellKnownType(i.message)){let t=i.message;n.push({value:`${e}.`,description:`${e} (message)`}),r.has(t)||walk(t,`${e}.`);continue}}if(n.push({value:`${e}=`,description:`Set ${e}`}),i.fieldKind===`enum`)for(let t of i.enum.values)n.push({value:`${e}=${t.name}`,description:t.name});else i.fieldKind===`scalar`&&i.scalar===J.BOOL&&(n.push({value:`${e}=true`,description:`true`}),n.push({value:`${e}=false`,description:`false`}))}r.delete(e)}return walk(t.input,``),n}function resolveLeafField(e,t){let n=e;for(let e=0;e<t.length;e++){let r=n.fields.find(n=>n.localName===t[e]);if(!r)return;if(e===t.length-1)return r.fieldKind===`message`&&isUnrepresentableWellKnownType(r.message)?void 0:r;if(r.fieldKind!==`message`||isWellKnownType(r.message))return;n=r.message}}const Pr={[J.DOUBLE]:`double`,[J.FLOAT]:`float`,[J.INT64]:`int64`,[J.UINT64]:`uint64`,[J.INT32]:`int32`,[J.FIXED64]:`fixed64`,[J.FIXED32]:`fixed32`,[J.BOOL]:`bool`,[J.STRING]:`string`,[J.BYTES]:`bytes`,[J.UINT32]:`uint32`,[J.SFIXED32]:`sfixed32`,[J.SFIXED64]:`sfixed64`,[J.SINT32]:`sint32`,[J.SINT64]:`sint64`};function shortName(e){let t=e.lastIndexOf(`.`);return t<0?e:e.slice(t+1)}function scalarLabel(e){return Pr[e]??`scalar(${e})`}function enumLabel(e){return`enum ${shortName(e.typeName)}`}function enumOf(e){if(e.fieldKind===`enum`||e.fieldKind===`list`&&e.listKind===`enum`)return e.enum}function describeFieldType(e){switch(e.fieldKind){case`scalar`:return scalarLabel(e.scalar);case`enum`:return enumLabel(e.enum);case`message`:return shortName(e.message.typeName);case`list`:{let t;return t=e.listKind===`scalar`?scalarLabel(e.scalar):e.listKind===`enum`?enumLabel(e.enum):shortName(e.message.typeName),`repeated ${t}`}case`map`:{let t=scalarLabel(e.mapKey),n;return n=e.mapKind===`scalar`?scalarLabel(e.scalar):e.mapKind===`enum`?enumLabel(e.enum):shortName(e.message.typeName),`map<${t}, ${n}>`}default:return`<unknown>`}}function fieldToJson(e,t){let n={name:e.localName,protoName:e.name,type:describeFieldType(e),fieldKind:e.fieldKind,repeated:e.fieldKind===`list`};e.oneof&&(n.oneof=e.oneof.name);let r=enumOf(e);r&&(n.enumValues=r.values.map(e=>e.name));let i=nestedMessage(e);return i&&!t.has(i)?(t.add(i),n.message={typeName:i.typeName,fields:i.fields.map(e=>fieldToJson(e,t))},t.delete(i)):i&&(n.message={typeName:i.typeName,fields:[],recursive:!0}),n}function renderInspectJson(e){let t=new Set([e.input]);return{method:e.name,input:{typeName:e.input.typeName,fields:e.input.fields.map(e=>fieldToJson(e,t))},output:{typeName:e.output.typeName}}}function renderFieldText(e,t,n){let r=[],i=e.oneof?` (oneof ${e.oneof.name})`:``;r.push(`${t}${e.localName}: ${describeFieldType(e)}${i}`);let a=enumOf(e);if(a){let e=a.values.map(e=>e.name).join(`, `);r.push(`${t} values: ${e}`)}let o=nestedMessage(e);if(o&&!n.has(o)){n.add(o);for(let e of o.fields)r.push(...renderFieldText(e,`${t} `,n));n.delete(o)}else o&&r.push(`${t} …(recursive ${o.typeName})`);return r}function renderInspectText(e){let t=[];t.push(`${e.name}`),t.push(` request: ${e.input.typeName}`);let n=new Set([e.input]);for(let r of e.input.fields)t.push(...renderFieldText(r,` `,n));return t.push(` response: ${e.output.typeName}`),t.join(`
3
+ `)}const Fr=g({name:`inspect`,description:`Print the input message tree of an OperatorService endpoint.`,notes:"Combine with the global `--json` flag for a machine-readable descriptor. Recursive type references and `oneof` membership are annotated. Use `tailor api list` to discover endpoint names.",examples:[{cmd:`GetApplication`,desc:`Show fields of GetApplicationRequest.`},{cmd:`CreateExecutorExecutor`,desc:"Inspect a deeply nested input with `(oneof config)` annotations."}],args:q.strictObject({endpoint:W(q.string(),{positional:!0,description:`API endpoint to inspect (e.g., 'GetApplication' or 'tailor.v1.OperatorService/GetApplication').`,completion:{custom:{choices:listMethodNames()}}})}),run:e=>{let t=extractMethodName(e.endpoint),n=getMethodDescriptor(t);if(!n)throw Xn({message:`unknown method: ${t}`,suggestion:"Run `tailor api list` to see available methods.",command:`api inspect`});s.jsonMode?s.out(renderInspectJson(n)):s.out(renderInspectText(n))}}),Ir=g({name:`list`,description:`List all invocable OperatorService methods.`,notes:`Only single-request (non-streaming) methods are listed, because the CLI issues a single JSON request and reads one JSON response.`,args:q.strictObject({}),run:()=>{let e=listMethodNames();if(s.jsonMode)s.out(e);else for(let t of e)s.out(t)}});function resolveNamespaceName(e,t){if(/Auth|Tenant|UserProfile/.test(e))return t.auth?.name;if(/IdP/.test(e))return t.idp?.length===1?o(t.idp[0],`idp config missing`).name:void 0;if(/TailorDB/.test(e)){let e=Object.keys(t.db??{});return e.length===1?e[0]:void 0}if(/Pipeline/.test(e)){let e=Object.keys(t.resolver??{});return e.length===1?e[0]:void 0}}function parseBodyAsObject(e){let t;try{t=JSON.parse(e)}catch{return}if(!(typeof t!=`object`||!t||Array.isArray(t)))return t}function setNestedPath(e,t,n){let r=e;for(let e=0;e<t.length-1;e++){let n=o(t[e],`path segment missing`),i=r[n];(typeof i!=`object`||!i||Array.isArray(i))&&(r[n]={}),r=r[n]}r[o(t[t.length-1],`path last segment missing`)]=n}function coerceFieldValue(e,t){if(e&&e.fieldKind===`scalar`&&e.scalar===J.BOOL){if(t===`true`)return!0;if(t===`false`)return!1;throw Error(`Invalid value for bool field: '${t}'. Expected 'true' or 'false'.`)}return t}function normalizeBodyFieldKeys(e,t){let n=new Map;for(let e of t)n.set(e.name,e.localName),n.set(e.jsonName,e.localName);let r=!1;for(let t of Object.keys(e)){let i=n.get(t);!i||i===t||(Object.hasOwn(e,i)||(e[i]=e[t]),delete e[t],r=!0)}return r}const Lr=new Set([`__proto__`,`constructor`,`prototype`]),Rr=q.string().transform((e,t)=>{let n=e.indexOf(`=`);if(n<0)return t.addIssue({code:q.ZodIssueCode.custom,message:`Invalid field format: '${e}'. Expected format: 'key=value' or 'a.b.c=value'`}),q.NEVER;let r=e.slice(0,n);if(r.length===0)return t.addIssue({code:q.ZodIssueCode.custom,message:`Field key cannot be empty`}),q.NEVER;let i=r.split(`.`);if(i.some(e=>e.length===0))return t.addIssue({code:q.ZodIssueCode.custom,message:`Invalid field key: '${r}'. Dotted segments cannot be empty`}),q.NEVER;let a=i.find(e=>Lr.has(e));return a?(t.addIssue({code:q.ZodIssueCode.custom,message:`Invalid field key: '${r}'. Segment '${a}' is not allowed.`}),q.NEVER):{path:i,value:e.slice(n+1)}}),zr=g({name:`api`,description:`Call Tailor Platform API endpoints directly.`,notes:"Use `tailor api list` to enumerate invocable methods and `tailor api inspect <endpoint>` to print an endpoint's input message tree (combine with `--json` for machine-readable output).\n\nThe request body is inferred from the target endpoint's request schema, and commonly required fields are auto-injected so they can be omitted from `--body`:\n\n- `workspaceId` — resolved from `-w` / `TAILOR_PLATFORM_WORKSPACE_ID` / the selected profile.\n- `namespaceName` — resolved from `tailor.config.ts` based on the endpoint's service:\n - Auth / Tenant / UserProfile endpoints use `auth.name`.\n - IdP / TailorDB / Pipeline endpoints use the sole configured namespace when exactly one is defined.\n\nValues already present in `--body` are never overridden. If a value cannot be resolved (e.g. no config found), injection is silently skipped and the server-side validation error takes precedence.\n\nUse `--field key=value` (repeatable) to set request body fields without writing JSON. Dotted keys (e.g. `application.name=foo`) build nested objects. `--field` overrides matching fields in `--body` and tab-completes from the endpoint's request schema.",examples:[{cmd:`GetApplication -b '{"applicationName":"app-1"}'`,desc:`Call an endpoint; workspaceId is auto-injected.`},{cmd:`GetApplication -f applicationName=app-1`,desc:`Same as above, using --field instead of --body.`},{cmd:`list`,desc:`List all invocable OperatorService methods.`},{cmd:`inspect GetApplication`,desc:`Show the input message tree for an endpoint.`}],subCommands:{list:Ir,inspect:Fr},args:q.strictObject({...d,...Re,body:W(q.string().default(`{}`),{alias:`b`,description:`Request body as JSON.`}),field:W(Rr.array().optional(),{alias:`f`,description:"Set a body field as `key=value` (repeatable; dotted keys nest). Overrides --body.",completion:{custom:{expand:{dependsOn:[`endpoint`],enumerate:({endpoint:e})=>enumerateAllFieldCompletions(extractMethodName(e??``))}}}}),endpoint:W(q.string(),{positional:!0,description:`API endpoint to call (e.g., 'GetApplication' or 'tailor.v1.OperatorService/GetApplication').`,completion:{custom:{choices:listMethodChoices()}}})}),run:async e=>{await N({profile:e.profile});let t=extractMethodName(e.endpoint),n=getMethodDescriptor(t),r=parseBodyAsObject(e.body),i=!1;if(e.field&&e.field.length>0){if(!r)throw Error(`--field requires --body to be a JSON object (or omitted).`);for(let t of e.field){let e=n?resolveLeafField(n.input,t.path):void 0;setNestedPath(r,t.path,coerceFieldValue(e,t.value))}i=!0}if(r&&n){normalizeBodyFieldKeys(r,n.input.fields)&&(i=!0);let a=n.input.fields.map(e=>e.localName);if(a.includes(`workspaceId`)&&!Object.hasOwn(r,`workspaceId`))try{r.workspaceId=await k({workspaceId:e[`workspace-id`],profile:e.profile}),i=!0}catch{}if(a.includes(`namespaceName`)&&!Object.hasOwn(r,`namespaceName`))try{let{config:n}=await R(e.config),a=resolveNamespaceName(t,n);a&&(r.namespaceName=a,i=!0)}catch{}}let a=await ln({profile:e.profile,endpoint:e.endpoint,body:i&&r?JSON.stringify(r):e.body});s.out(JSON.stringify(a.data,null,2))}}),Br=g({name:`token`,description:`Print a valid Tailor Platform access token to stdout, refreshing it first if expired.`,args:q.strictObject({profile:d.profile}),run:async({profile:e})=>{let t=await E({profile:e});s.out(t)}}),Vr=G({name:`auth`,description:`Authentication helpers for scripts and plugins.`,subCommands:{token:Br}}),Hr={name:W(q.string(),{alias:`n`,description:`Auth connection name`})};async function fetchOIDCDiscovery(e){let t=e.replace(/\/$/,``)+`/.well-known/openid-configuration`,n=await fetch(t).catch(e=>{throw Error(`Failed to fetch OIDC discovery from ${t}: ${Gn(e).message}`,{cause:e})});if(!n.ok)throw Error(`Failed to fetch OIDC discovery from ${t}: ${n.status}`);return n.json()}function randomState$1(){return br.randomBytes(32).toString(`base64url`)}const Ur=g({name:`authorize`,description:`Authorize an auth connection via OAuth2 flow.`,args:q.strictObject({...d,...Hr,scopes:q.string().optional().default(`openid,profile,email`).describe(`OAuth2 scopes to request (comma-separated)`),port:q.coerce.number().optional().default(8080).describe(`Local callback server port`),"no-browser":q.boolean().optional().default(!1).describe(`Don't open browser automatically`)}),run:async e=>{await N({profile:e.profile});let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile}),i=(await mn(async(e,t)=>{let{connections:i,nextPageToken:a}=await n.listAuthConnections({workspaceId:r,pageToken:e,pageSize:t});return[i,a]})).find(t=>t.name===e.name);if(!i)throw Error(`Auth connection "${e.name}" not found.`);if(i.config.case!==`oauth2`)throw Error(`Auth connection "${e.name}" is not an OAuth2 connection.`);let a=i.config.value,o=`http://localhost:${e.port}/callback`,c=randomState$1(),l;l=a.authUrl?a.authUrl:(await fetchOIDCDiscovery(a.providerUrl)).authorization_endpoint;let u=new URL(l);u.searchParams.set(`client_id`,a.clientId),u.searchParams.set(`redirect_uri`,o),u.searchParams.set(`response_type`,`code`),u.searchParams.set(`scope`,e.scopes.replace(/,/g,` `)),u.searchParams.set(`state`,c),u.searchParams.set(`access_type`,`offline`),await new Promise((t,i)=>{let handleCallback=async(s,l)=>{if(!s.url?.startsWith(`/callback`)){l.writeHead(404),l.end(`Not found`);return}try{let i=new URL(s.url,`http://localhost:${e.port}`),u=i.searchParams.get(`code`),d=i.searchParams.get(`state`),f=i.searchParams.get(`error`);if(f)throw Error(`Authorization failed: ${f}`);if(d!==c)throw Error(`State mismatch — possible CSRF attack.`);if(!u)throw Error(`No authorization code received.`);await n.exchangeAuthConnectionAuthorizationCode({workspaceId:r,connectionName:e.name,authorizationCode:u,redirectUri:o}),l.writeHead(200,{"Content-Type":`text/html`}),l.end(`<html><body><h1>Authorization successful</h1><p>You can close this window.</p></body></html>`),a.close(),t()}catch(e){l.writeHead(400,{"Content-Type":`text/plain`}),l.end(`Authorization failed: ${e instanceof Error?e.message:`Unknown error`}`),a.close(),i(Gn(e))}},a=Sr.createServer((e,t)=>void handleCallback(e,t)),l=setTimeout(()=>{a.close(),i(Error(`Authorization timeout exceeded (5 minutes).`))},3e5);a.on(`close`,()=>{clearTimeout(l)}),a.on(`error`,t=>{clearTimeout(l);let n=t.code,r=n===`EADDRINUSE`||n===`EACCES`?`Try a different port with --port, or authorize via the Console instead:`:`Authorize via the Console instead:`;s.warn(`Could not start the local callback server on port ${e.port}${n?` (${n})`:``}.\n${r}\n tailor authconnection open`),i(t)});let announceAuthorizeUrl=async()=>{let t=u.toString();if(s.info(e[`no-browser`]?`Open this URL in your browser to authorize:\n\n${t}\n`:`Opening browser for authorization:\n\n${t}\n`),s.info(`If this flow doesn't complete, you can authorize via the Console instead:
4
+ tailor authconnection open`),!e[`no-browser`])try{await Cr(t)}catch{s.warn(`Failed to open browser automatically. Please open the URL above manually.`)}};a.listen(e.port,()=>void announceAuthorizeUrl())}),s.success(`Auth connection "${e.name}" authorized successfully.`)}}),Wr=g({name:`delete`,description:`Delete an auth connection entirely.`,args:q.strictObject({...d,...Hr,...M}),run:async e=>{await N({profile:e.profile});let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile});if(!e.yes&&await L.text({message:`Enter the connection name to confirm deletion ("${e.name}"):`})!==e.name){s.info(`Auth connection deletion cancelled.`);return}try{await n.deleteAuthConnection({workspaceId:r,connectionName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Auth connection "${e.name}" not found.`,{cause:t}):t}s.success(`Auth connection "${e.name}" deleted.`)}});function connectionInfo(e){let t=e.config.case===`oauth2`?e.config.value:void 0;return{name:e.name,type:e.config.case??`unknown`,providerUrl:t?.providerUrl??``,issuerUrl:t?.issuerUrl??``,clientId:t?.clientId??``,authUrl:t?.authUrl??``,tokenUrl:t?.tokenUrl??``,createdAt:e.createdAt?X(e.createdAt):null}}const Gr=g({name:`list`,description:`List all auth connections.`,args:q.strictObject({...d,...Ue()}),run:async e=>{let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile});try{let t=Oe(e.order),i=await B(async(e,i)=>{let{connections:a,nextPageToken:o}=await n.listAuthConnections({workspaceId:r,pageToken:e,pageSize:i,pageDirection:t});return[a,o]},{limit:e.limit});s.out(i.map(connectionInfo))}catch(e){if(e instanceof Q&&e.code===Z.NotFound){s.out([]);return}throw e}}}),Kr=g({name:`open`,description:`Open the auth connections page in the Tailor Platform Console.`,args:q.strictObject({...d}),run:async e=>{let t=await k({workspaceId:e[`workspace-id`],profile:e.profile}),n=`/workspaces/${t}/settings/connections`,r=await we({profile:e.profile,...e[`workspace-id`]===void 0?{}:{allowMissingProfile:!0}}),i=new URL(n,r).toString(),a=s.jsonMode;s.info(`Opening auth connections page in Tailor Platform Console...`);let o=!0;try{await Cr(i)}catch{o=!1}if(a){s.out({consoleUrl:i,workspaceId:t,opened:o});return}o?(s.out(`Console URL: ${i}`),s.out(`Workspace ID: ${t}`)):s.warn(`Failed to open browser automatically. Please open this URL manually:\n${i}`)}}),qr=g({name:`revoke`,description:`Revoke an auth connection's tokens (keeps the connection; use 'delete' to remove it).`,notes:"Revoke invalidates the connection's active session and tokens but keeps the connection and its stored credentials, so it can be re-authorized later. Use `delete` to remove the connection entirely.",args:q.strictObject({...d,...Hr,...M}),run:async e=>{await N({profile:e.profile});let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile});if(!e.yes&&await L.text({message:`Enter the connection name to confirm revocation ("${e.name}"):`})!==e.name){s.info(`Auth connection revocation cancelled.`);return}try{await n.revokeAuthConnection({workspaceId:r,connectionName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Auth connection "${e.name}" not found.`,{cause:t}):t}s.success(`Auth connection "${e.name}" revoked.`)}}),Jr=G({name:`authconnection`,description:`Manage auth connections.`,subCommands:{authorize:Ur,list:Gr,open:Kr,revoke:qr,delete:Wr},async run(){await K(Gr,[])}});function orderAndLimitCrashReports(e,t){let n=e.filter(e=>e.endsWith($n)).toSorted(),r=t.order===`asc`?n:n.toReversed();return t.limit&&t.limit>0?r.slice(0,t.limit):r}function formatCrashReportFiles(e,t){return e.map(e=>({file:e,path:U.join(t,e)}))}const Yr=g({name:`list`,description:`List local crash report files.`,args:q.strictObject({...Ue()}),run:async e=>{let t=er(),n=s.jsonMode;if(!t.localDir){s.info(`Crash report directory not available.`),n&&s.out([]);return}let r;try{r=Y.readdirSync(t.localDir)}catch{s.info(`No crash reports found.`),n&&s.out([]);return}let i=orderAndLimitCrashReports(r,{order:e.order,limit:e.limit});if(i.length===0){s.info(`No crash reports found.`),n&&s.out([]);return}if(n){s.out(formatCrashReportFiles(i,t.localDir));return}s.info(`${i.length} crash report(s) in ${t.localDir}:`);for(let e of i)s.log(` ${e}`)}}),Xr=g({name:`send`,description:`Submit a crash report to help improve the SDK.`,args:q.strictObject({file:W(q.string(),{description:`Path to the crash report file`,required:!0,completion:{type:`file`,extensions:[`log`]}})}),run:async e=>{let t;try{t=Y.readFileSync(e.file,`utf-8`)}catch{s.error(`Crash report file not found: ${e.file}`),process.exit(1)}let n=parseCrashLogFile(t);n||(s.error(`Failed to parse crash report file. The file may be corrupted.`),process.exit(1));let r=await Wn();s.info(`Sending crash report...`),await tr(n,r)?s.success(`Crash report submitted successfully. Thank you!`):(s.error(`Failed to submit crash report. The server may be unavailable.`),process.exit(1))}});function parseCrashLogFile(e){try{let t=e.replace(/\r\n/g,`
5
+ `),n=`\n${Qn}\n`,r=t.lastIndexOf(n);if(r===-1)return;let i=t.slice(r+n.length).split(`
6
+ `)[0];return i?JSON.parse(i):void 0}catch{return}}const Zr=G({name:`crashreport`,description:`Manage crash reports.`,subCommands:{list:Yr,send:Xr},async run(){await K(Yr,[])}}),Qr=g({name:`deploy`,description:`Deploy your application by applying the Tailor configuration.`,args:q.strictObject({...d,...ue,...M,"create-workspace":W(q.boolean().optional(),{description:`Create a workspace when the account has none`}),"workspace-name":W(q.string().optional(),{description:`Name for a workspace created during deploy`}),"workspace-region":W(q.string().optional(),{description:`Region for a workspace created during deploy`}),"organization-id":W(q.string().optional(),{description:`Organization ID for a workspace created during deploy`,env:`TAILOR_PLATFORM_ORGANIZATION_ID`}),"folder-id":W(q.string().optional(),{description:`Folder ID for a workspace created during deploy`,env:`TAILOR_PLATFORM_FOLDER_ID`}),"dry-run":W(q.boolean().optional(),{alias:`d`,description:`Run the command without making any changes`}),"no-schema-check":W(q.boolean().optional(),{description:`Skip schema diff check against migration snapshots`}),"no-validate":W(q.boolean().optional(),{description:`Skip client-side validation against platform resource constraints`}),"no-cache":W(q.boolean().optional(),{description:`Disable bundle caching for this run`}),"clean-cache":W(q.boolean().optional(),{description:`Clean the bundle cache before building`})}),run:async e=>{await N({profile:e.profile});let{initTelemetry:t}=await import(`../telemetry-DXHP3VVi.mjs`);await t(),await f({workspaceId:e[`workspace-id`],profile:e.profile,configPath:e.config,dryRun:e[`dry-run`],yes:e.yes,createWorkspace:e[`create-workspace`],workspaceName:e[`workspace-name`],workspaceRegion:e[`workspace-region`],organizationId:e[`organization-id`],folderId:e[`folder-id`],noSchemaCheck:e[`no-schema-check`],noValidate:e[`no-validate`],noCache:e[`no-cache`],cleanCache:e[`clean-cache`]},{envFile:e[`env-file`],envFileIfExists:e[`env-file-if-exists`],verbose:e.verbose,json:e.json})}}),$r=G({name:`executor`,description:`Manage executors`,subCommands:{trigger:xe,jobs:fn,list:ne,get:We,webhook:ve},async run(){await K(ne,[])}});function scriptNameToRegistryName(e,t){if(t===a.JOB)return`workflow--${e}`;let n=/^([^.]+)\.(.+)\.body\.js$/.exec(e);if(n){let[,e,t]=n;return`resolver--${e}--${t}`}let r=/^(.+)\.operation\.js$/.exec(e);if(r){let[,e]=r;return`executor--${e}`}let i=/^([^.]+)\.([^.]+)\.hook\.js$/.exec(e);if(i){let[,e,t]=i;return`auth-hook--${e}--${t}`}return t===a.UNSPECIFIED&&!e.includes(`.`)?`workflow--${e}`:null}async function downloadFunctionScript(e){let{client:t,workspaceId:n,name:r,contentHash:i}=e;try{let e=[];for await(let a of t.downloadFunctionRegistryScript({workspaceId:n,name:r,contentHash:i}))a.payload.case===`chunk`&&e.push(a.payload.value);return e.length===0?null:{code:Buffer.concat(e).toString(`utf-8`)}}catch(t){return s.debug(`Failed to download function script "${e.name}": ${t}`),null}}const ei=/^\s+at\s+(?:(.+?)\s+\()?(file:\/\/\/.+?):(\d+):(\d+)\)?$/;function parseStackTrace(e){let t=e.split(`
7
7
  `),n=[],r=[];for(let e of t)/^\s+at\s+/.test(e)?r.push(e):r.length===0&&n.push(e);let i=n.join(`
8
- `);i.startsWith(`rpc error: code = Aborted desc = `)&&(i=i.slice(33));let a=[];for(let e of r){let t=ii.exec(e);t&&a.push({functionName:t[1]||`<anonymous>`,file:o(t[2],`stack frame file missing`),line:Number(o(t[3],`stack frame line missing`)),column:Number(o(t[4],`stack frame column missing`))})}return{errorMessage:i,frames:a}}const ai=/\/\/[#@]\s*sourceMappingURL=data:application\/json[^,]*;base64,(.+)$/m;function extractInlineSourcemap(e){let t=ai.exec(e);if(!t)return null;try{let e=Buffer.from(o(t[1],`sourcemap base64 data missing`),`base64`).toString(`utf-8`),n=JSON.parse(e);return new jr(n)}catch{return null}}function mapStackFrames(e,t){return e.map(e=>{if(!t)return{original:e,mapped:null};try{for(let n=t.sources.length-1;n>=0;n--){let r=t.sources[n];if(r==null)continue;let i=Mr(t,{source:r,line:e.line,column:e.column-1});if(i.line==null)continue;let a=Nr(t,{line:i.line,column:i.column});if(a.source===r&&a.line===e.line&&a.column===e.column-1)return{original:e,mapped:{source:r,line:e.line,column:e.column,name:null}}}return{original:e,mapped:null}}catch{return{original:e,mapped:null}}})}function detectEditorScheme(){let e=process.env.VISUAL||process.env.EDITOR||``;return/\bcode\b/.test(e)?`vscode`:null}function osc8Link(e,t){return`\x1b]8;;${e}\x07${t}\x1b]8;;\x07`}function buildSourceLink(e,t,n,r){let i=`${e}:${n}:${r}`;return detectEditorScheme()===`vscode`?osc8Link(`vscode://file${t}:${n}:${r}`,i):osc8Link(`file://${t}`,i)}function buildCodeSnippet(e,t){let n=e.split(`
8
+ `);i.startsWith(`rpc error: code = Aborted desc = `)&&(i=i.slice(33));let a=[];for(let e of r){let t=ei.exec(e);t&&a.push({functionName:t[1]||`<anonymous>`,file:o(t[2],`stack frame file missing`),line:Number(o(t[3],`stack frame line missing`)),column:Number(o(t[4],`stack frame column missing`))})}return{errorMessage:i,frames:a}}const ti=/\/\/[#@]\s*sourceMappingURL=data:application\/json[^,]*;base64,(.+)$/m;function extractInlineSourcemap(e){let t=ti.exec(e);if(!t)return null;try{let e=Buffer.from(o(t[1],`sourcemap base64 data missing`),`base64`).toString(`utf-8`),n=JSON.parse(e);return new Dr(n)}catch{return null}}function mapStackFrames(e,t){return e.map(e=>{if(!t)return{original:e,mapped:null};try{for(let n=t.sources.length-1;n>=0;n--){let r=t.sources[n];if(r==null)continue;let i=Or(t,{source:r,line:e.line,column:e.column-1});if(i.line==null)continue;let a=kr(t,{line:i.line,column:i.column});if(a.source===r&&a.line===e.line&&a.column===e.column-1)return{original:e,mapped:{source:r,line:e.line,column:e.column,name:null}}}return{original:e,mapped:null}}catch{return{original:e,mapped:null}}})}function detectEditorScheme(){let e=process.env.VISUAL||process.env.EDITOR||``;return/\bcode\b/.test(e)?`vscode`:null}function osc8Link(e,t){return`\x1b]8;;${e}\x07${t}\x1b]8;;\x07`}function buildSourceLink(e,t,n,r){let i=`${e}:${n}:${r}`;return detectEditorScheme()===`vscode`?osc8Link(`vscode://file${t}:${n}:${r}`,i):osc8Link(`file://${t}`,i)}function buildCodeSnippet(e,t){let n=e.split(`
9
9
  `),r=Math.max(0,t-1-2),i=Math.min(n.length,t+2),a=String(i).length,o=[];for(let e=r;e<i;e++){let r=e+1,i=String(r).padStart(a),s=n[e];r===t?o.push(` ${c.error(`>`)} ${c.error(`${i} | ${s}`)}`):o.push(` ${c.dim(`${i} | ${s}`)}`)}return o.join(`
10
- `)}function formatMappedError(e,t,n,r){let i=[` ${c.error(e)}`];for(let e of t)if(e.mapped){let{source:t,line:a,column:o,name:s}=e.mapped,c=r?W.resolve(r,t):W.resolve(t),l=W.relative(process.cwd(),c),u=l.startsWith(`..`)?l:`./${l}`,d=s??e.original.functionName,f=buildSourceLink(u,c,a,o);if(i.push(`\n at ${d} (${f})`),n){let e=n.sources.indexOf(t);if(e!==-1){let t=n.sourcesContent?.[e];t&&i.push(buildCodeSnippet(t,a))}}}else{let t=`${e.original.file.replace(/^file:\/\/\//,``)}:${e.original.line}:${e.original.column}`;i.push(`\n ${c.dim(`at ${e.original.functionName} (${t})`)}`)}return i.join(`
11
- `)}function formatErrorWithSourcemap(e,t,n){try{let{errorMessage:r,frames:i}=parseStackTrace(e);if(i.length===0)return null;let a=extractInlineSourcemap(t);if(!a)return null;let o=mapStackFrames(i,a);return o.some(e=>e.mapped!==null)?formatMappedError(r,o,a,n):null}catch{return null}}function functionExecutionTypeToString(e){switch(e){case i.STANDARD:return`STANDARD`;case i.JOB:return`JOB`;default:return`UNSPECIFIED`}}function toFunctionExecutionListInfo(e){return{id:e.id,scriptName:e.scriptName,status:Vt(e.status),type:functionExecutionTypeToString(e.type),startedAt:e.startedAt?br(e.startedAt):null,finishedAt:e.finishedAt?br(e.finishedAt):null}}function toFunctionExecutionDetailInfo(e){return{...toFunctionExecutionListInfo(e),logs:e.logs,result:e.result,error:e.error?{name:e.error.name,message:e.error.message,stackTrace:e.error.stackTrace}:null}}function composeExecutionErrorString(e){let{name:t,message:n,stackTrace:r}=e;if(!r)return`${t}: ${n}`;let i=r.split(`
10
+ `)}function formatMappedError(e,t,n,r){let i=[` ${c.error(e)}`];for(let e of t)if(e.mapped){let{source:t,line:a,column:o,name:s}=e.mapped,c=r?U.resolve(r,t):U.resolve(t),l=U.relative(process.cwd(),c),u=l.startsWith(`..`)?l:`./${l}`,d=s??e.original.functionName,f=buildSourceLink(u,c,a,o);if(i.push(`\n at ${d} (${f})`),n){let e=n.sources.indexOf(t);if(e!==-1){let t=n.sourcesContent?.[e];t&&i.push(buildCodeSnippet(t,a))}}}else{let t=`${e.original.file.replace(/^file:\/\/\//,``)}:${e.original.line}:${e.original.column}`;i.push(`\n ${c.dim(`at ${e.original.functionName} (${t})`)}`)}return i.join(`
11
+ `)}function formatErrorWithSourcemap(e,t,n){try{let{errorMessage:r,frames:i}=parseStackTrace(e);if(i.length===0)return null;let a=extractInlineSourcemap(t);if(!a)return null;let o=mapStackFrames(i,a);return o.some(e=>e.mapped!==null)?formatMappedError(r,o,a,n):null}catch{return null}}function functionExecutionTypeToString(e){switch(e){case a.STANDARD:return`STANDARD`;case a.JOB:return`JOB`;default:return`UNSPECIFIED`}}function toFunctionExecutionListInfo(e){return{id:e.id,scriptName:e.scriptName,status:qe(e.status),type:functionExecutionTypeToString(e.type),startedAt:e.startedAt?X(e.startedAt):null,finishedAt:e.finishedAt?X(e.finishedAt):null}}function toFunctionExecutionDetailInfo(e){return{...toFunctionExecutionListInfo(e),logs:e.logs,result:e.result,error:e.error?{name:e.error.name,message:e.error.message,stackTrace:e.error.stackTrace}:null}}function composeExecutionErrorString(e){let{name:t,message:n,stackTrace:r}=e;if(!r)return`${t}: ${n}`;let i=r.split(`
12
12
  `,1)[0]??``;return/^\s+at\s+/.test(i)?`${t}: ${n}\n${r}`:r}function formatExecutionErrorFallback(e){let[t=``,...n]=composeExecutionErrorString(e).split(`
13
13
  `);return[` ${c.error(t)}`,...n.map(e=>` ${c.dim(e)}`)].join(`
14
- `)}function formatExecutionError(e,t){if(t&&e.stackTrace){let n=formatErrorWithSourcemap(composeExecutionErrorString(e),t,process.cwd());if(n)return n}return formatExecutionErrorFallback(e)}function printFunctionExecutionDetail(e){let{detail:t,bundledCode:n}=e,formatDate=e=>e?e.toISOString():`N/A`,r=[[`id`,t.id],[`scriptName`,t.scriptName],[`status`,t.status],[`type`,t.type],[`startedAt`,formatDate(t.startedAt)],[`finishedAt`,formatDate(t.finishedAt)]];if(s.out($e(r)),t.logs){s.log(c.bold(`
14
+ `)}function formatExecutionError(e,t){if(t&&e.stackTrace){let n=formatErrorWithSourcemap(composeExecutionErrorString(e),t,process.cwd());if(n)return n}return formatExecutionErrorFallback(e)}function printFunctionExecutionDetail(e){let{detail:t,bundledCode:n}=e,formatDate=e=>e?e.toISOString():`N/A`,r=[[`id`,t.id],[`scriptName`,t.scriptName],[`status`,t.status],[`type`,t.type],[`startedAt`,formatDate(t.startedAt)],[`finishedAt`,formatDate(t.finishedAt)]];if(s.out(Ut(r)),t.logs){s.log(c.bold(`
15
15
  Logs:`));for(let e of t.logs.split(`
16
16
  `))s.log(` ${e}`)}if(t.result){s.log(c.bold(`
17
17
  Result:`));try{let e=JSON.parse(t.result);s.log(` ${JSON.stringify(e,null,2).split(`
18
18
  `).join(`
19
19
  `)}`)}catch{s.log(` ${t.result}`)}}t.error&&(s.log(c.bold(`
20
- Error:`)),s.log(formatExecutionError(t.error,n??null)))}async function downloadScriptForMapping(e){let{client:t,workspaceId:n,scriptName:r,executionType:i,executionContentHash:a}=e,o=scriptNameToRegistryName(r,i);if(o==null)return s.debug(`Script "${r}" is not a deployed registry script (e.g. function run or seed); skipping sourcemap mapping.`),null;if(a===``)return s.debug(`Function execution "${r}" has no contentHash; skipping sourcemap mapping because the exact bundle cannot be identified.`),null;let c=await downloadFunctionScript({client:t,workspaceId:n,name:o,contentHash:a});return c==null?(s.debug(`Could not download pinned script "${r}" (registry: "${o}", contentHash: "${a}") for stack trace mapping; showing raw stack trace.`),null):c.code}const oi=g({name:`logs`,description:`List or get function execution logs.`,notes:`When viewing a specific execution that failed, the command displays error details with the stack trace mapped back to your original source files (clickable file links and code snippets, matching \`function run\` output).
20
+ Error:`)),s.log(formatExecutionError(t.error,n??null)))}async function downloadScriptForMapping(e){let{client:t,workspaceId:n,scriptName:r,executionType:i,executionContentHash:a}=e,o=scriptNameToRegistryName(r,i);if(o==null)return s.debug(`Script "${r}" is not a deployed registry script (e.g. function run or seed); skipping sourcemap mapping.`),null;if(a===``)return s.debug(`Function execution "${r}" has no contentHash; skipping sourcemap mapping because the exact bundle cannot be identified.`),null;let c=await downloadFunctionScript({client:t,workspaceId:n,name:o,contentHash:a});return c==null?(s.debug(`Could not download pinned script "${r}" (registry: "${o}", contentHash: "${a}") for stack trace mapping; showing raw stack trace.`),null):c.code}const ni=g({name:`logs`,description:`List or get function execution logs.`,notes:`When viewing a specific execution that failed, the command displays error details with the stack trace mapped back to your original source files (clickable file links and code snippets, matching \`function run\` output).
21
21
 
22
- Stack traces are mapped only when the execution includes a content hash for the exact build that ran. If the content hash is missing or the build is no longer available, the command falls back to a plain-text error display.`,examples:[{cmd:``,desc:`List all function execution logs`},{cmd:`<execution-id>`,desc:`Get execution details with logs`},{cmd:`--json`,desc:`Output as JSON`},{cmd:`<execution-id> --json`,desc:`Get execution details as JSON`}],args:J.strictObject({...N,...ce,"execution-id":G(J.string().optional(),{positional:!0,description:`Execution ID (if provided, shows details with logs)`})}),run:async e=>{let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile});if(e.executionId){let{execution:t}=await n.getFunctionExecution({workspaceId:r,executionId:e.executionId});if(!t)throw Error(`Function execution '${e.executionId}' not found.`);let i=toFunctionExecutionDetailInfo(t);e.json?s.out(i):printFunctionExecutionDetail({detail:i,bundledCode:i.error?await downloadScriptForMapping({client:n,workspaceId:r,scriptName:i.scriptName,executionType:t.type,executionContentHash:t.contentHash}):null})}else{let t=qe(e.order),i=(await On(async(e,i)=>{let{executions:a,nextPageToken:o}=await n.listFunctionExecutions({workspaceId:r,pageToken:e,pageSize:i,pageDirection:t});return[a,o]},{limit:e.limit})).map(toFunctionExecutionListInfo);if(i.length===0&&!e.json){s.info(`No function execution logs found.`);return}s.out(i)}}});async function bundleForRun(e){let{detected:t,sourceFile:n,baseDir:r,env:i={},machineUser:a,workspaceId:o}=e,s=jn(e.inlineSourcemap),c=Pn(e.logLevel),l=W.resolve(In(),`test-run`);X.mkdirSync(l,{recursive:!0});let u=`test-run--${t.name}`,d=`${u}.js`,f=W.join(l,`${u}.entry.js`),p=generateEntry({detected:t,sourceFile:n,env:i,machineUser:a,workspaceId:o,defaultPermission:e.defaultPermission});X.writeFileSync(f,p);let m=await En(r),h=mn({tsconfig:m}),g=await Or.build({plugins:[hn(f,r),Bn(),_n],input:f,write:!1,output:{format:`esm`,sourcemap:!s||`inline`,minify:!s||{mangle:{keepNames:!0}},codeSplitting:!1,dir:process.cwd()},tsconfig:m,treeshake:gn([wn(c)]),...h.options});return h.assertAllResolved(),{bundledCode:g.output[0].code,scriptName:d}}function generateEntry(e){let{detected:t,sourceFile:n,env:r,machineUser:i,workspaceId:a,defaultPermission:s}=e,c=W.resolve(n);switch(t.type){case`plain`:return t.namedMain?U`
22
+ Stack traces are mapped only when the execution includes a content hash for the exact build that ran. If the content hash is missing or the build is no longer available, the command falls back to a plain-text error display.`,examples:[{cmd:``,desc:`List all function execution logs`},{cmd:`<execution-id>`,desc:`Get execution details with logs`},{cmd:`--json`,desc:`Output as JSON`},{cmd:`<execution-id> --json`,desc:`Get execution details as JSON`}],args:q.strictObject({...d,...Ke,"execution-id":W(q.string().optional(),{positional:!0,description:`Execution ID (if provided, shows details with logs)`})}),run:async e=>{let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile});if(e.executionId){let{execution:t}=await n.getFunctionExecution({workspaceId:r,executionId:e.executionId});if(!t)throw Error(`Function execution '${e.executionId}' not found.`);let i=toFunctionExecutionDetailInfo(t);e.json?s.out(i):printFunctionExecutionDetail({detail:i,bundledCode:i.error?await downloadScriptForMapping({client:n,workspaceId:r,scriptName:i.scriptName,executionType:t.type,executionContentHash:t.contentHash}):null})}else{let t=Oe(e.order),i=(await B(async(e,i)=>{let{executions:a,nextPageToken:o}=await n.listFunctionExecutions({workspaceId:r,pageToken:e,pageSize:i,pageDirection:t});return[a,o]},{limit:e.limit})).map(toFunctionExecutionListInfo);if(i.length===0&&!e.json){s.info(`No function execution logs found.`);return}s.out(i)}}});async function bundleForRun(e){let{detected:t,sourceFile:n,baseDir:r,env:i={},machineUser:a,workspaceId:o}=e,s=kn(e.inlineSourcemap),c=Mn(e.logLevel),l=U.resolve(Fn(),`test-run`);Y.mkdirSync(l,{recursive:!0});let u=`test-run--${t.name}`,d=`${u}.js`,f=U.join(l,`${u}.entry.js`),p=generateEntry({detected:t,sourceFile:n,env:i,machineUser:a,workspaceId:o,defaultPermission:e.defaultPermission});Y.writeFileSync(f,p);let m=await hn(r),h=yn({tsconfig:m}),g=await wr.build({plugins:[Cn(f,r),gn(),bn],input:f,write:!1,output:{format:`esm`,sourcemap:!s||`inline`,minify:!s||{mangle:{keepNames:!0}},codeSplitting:!1,dir:process.cwd()},tsconfig:m,treeshake:Nn([pn(c)]),...h.options});return h.assertAllResolved(),{bundledCode:g.output[0].code,scriptName:d}}function generateEntry(e){let{detected:t,sourceFile:n,env:r,machineUser:i,workspaceId:a,defaultPermission:s}=e,c=U.resolve(n);switch(t.type){case`plain`:return t.namedMain?H`
23
23
  export { main } from "${c}";
24
- `:U`
24
+ `:H`
25
25
  import _fn from "${c}";
26
26
  export { _fn as main };
27
- `;case`resolver`:{let e=buildMachinePrincipalExpr(i,a),n=An({permission:t.permission,defaultPermission:s});return U`
27
+ `;case`resolver`:{let e=buildMachinePrincipalExpr(i,a),n=On({permission:t.permission,defaultPermission:s});return H`
28
28
  import _internalResolver from "${c}";
29
29
  import { t } from "@tailor-platform/sdk";
30
30
 
31
31
  const $tailor_resolver_body = async (rawInput) => {
32
32
  const _caller = ${e};
33
- const invoker = (${Fn}) ?? _caller;
33
+ const invoker = (${Pn}) ?? _caller;
34
34
  const context = { input: rawInput, env: ${JSON.stringify(r)}, caller: _caller, invoker };
35
35
  ${n}
36
36
  return _internalResolver.body(context);
37
37
  };
38
38
 
39
39
  export { $tailor_resolver_body as main };
40
- `}case`executor`:{let e=buildMachinePrincipalExpr(i,a);return U`
40
+ `}case`executor`:{let e=buildMachinePrincipalExpr(i,a);return H`
41
41
  import _internalExecutor from "${c}";
42
42
 
43
43
  const _env = ${JSON.stringify(r)};
44
44
  const _actor = ${e};
45
45
 
46
46
  const __executor_function = async (args) => {
47
- const _invoker = ${Fn} ?? _actor;
47
+ const _invoker = ${Pn} ?? _actor;
48
48
  return _internalExecutor.operation.body({ ...args, env: _env, actor: _actor, invoker: _invoker });
49
49
  };
50
50
 
51
51
  export { __executor_function as main };
52
- `}case`workflow-job`:{let e=o(t.exportName,`workflow job export name missing`),n=buildMachinePrincipalExpr(i,a);return U`
52
+ `}case`workflow-job`:{let e=o(t.exportName,`workflow job export name missing`),n=buildMachinePrincipalExpr(i,a);return H`
53
53
  import { ${e} } from "${c}";
54
54
 
55
55
  const env = ${JSON.stringify(r)};
56
56
  const fallbackInvoker = ${n};
57
57
 
58
58
  export async function main(input) {
59
- const invoker = ${Fn} ?? fallbackInvoker;
59
+ const invoker = ${Pn} ?? fallbackInvoker;
60
60
  return await ${e}.body(input, { env, invoker });
61
61
  }
62
- `}}}function buildMachinePrincipalExpr(e,t){return JSON.stringify({id:e.id,type:`machine_user`,workspaceId:t,attributes:e.attributes??{},attributeList:e.attributeList})}async function detectFunctionType(t){let{filePath:n,jobName:r}=t,i=await import(xr(n).href),a=Nn.safeParse(i.default);if(a.success){let t=i.default.input,n;if(t){let r=t;n={parse:t=>e({...t,fields:r})}}return{type:`resolver`,name:a.data.name,hasInput:t!=null,inputSchema:n,permission:a.data.permission}}let o=Un.safeParse(Wn(i.default));if(o.success){let{operation:e}=o.data;if(e.kind===`function`||e.kind===`jobFunction`)return{type:`executor`,name:o.data.name}}let s=detectWorkflowJob(i,r);if(s)return s;if(typeof i.default==`function`)return{type:`plain`,name:deriveNameFromPath(n)};if(typeof i.main==`function`)return{type:`plain`,name:deriveNameFromPath(n),namedMain:!0};throw Error(`Could not detect function type from ${n}.\nThe file must have one of:
62
+ `}}}function buildMachinePrincipalExpr(e,t){return JSON.stringify({id:e.id,type:`machine_user`,workspaceId:t,attributes:e.attributes??{},attributeList:e.attributeList})}async function detectFunctionType(t){let{filePath:n,jobName:r}=t,i=await import(vr(n).href),a=jn.safeParse(i.default);if(a.success){let t=i.default.input,n;if(t){let r=t;n={parse:t=>e({...t,fields:r})}}return{type:`resolver`,name:a.data.name,hasInput:t!=null,inputSchema:n,permission:a.data.permission}}let o=Vn.safeParse(Hn(i.default));if(o.success){let{operation:e}=o.data;if(e.kind===`function`||e.kind===`jobFunction`)return{type:`executor`,name:o.data.name}}let s=detectWorkflowJob(i,r);if(s)return s;if(typeof i.default==`function`)return{type:`plain`,name:deriveNameFromPath(n)};if(typeof i.main==`function`)return{type:`plain`,name:deriveNameFromPath(n),namedMain:!0};throw Error(`Could not detect function type from ${n}.\nThe file must have one of:
63
63
  - A default-exported resolver (createResolver)
64
64
  - A default-exported executor (createExecutor) with function/jobFunction operation
65
65
  - A named-exported workflow job (createWorkflowJob)
66
66
  - A default-exported function
67
- - A named-exported "main" function`)}function detectWorkflowJob(e,t){let n=[];for(let[t,r]of Object.entries(e)){if(t==="default")continue;let e=Rn.safeParse(r);e.success&&n.push({name:e.data.name,exportName:t})}if(n.length===0)return null;if(t){let e=n.find(e=>e.name===t);if(!e){let e=n.map(e=>` - "${e.name}" (export: ${e.exportName})`).join(`
67
+ - A named-exported "main" function`)}function detectWorkflowJob(e,t){let n=[];for(let[t,r]of Object.entries(e)){if(t==="default")continue;let e=Ln.safeParse(r);e.success&&n.push({name:e.data.name,exportName:t})}if(n.length===0)return null;if(t){let e=n.find(e=>e.name===t);if(!e){let e=n.map(e=>` - "${e.name}" (export: ${e.exportName})`).join(`
68
68
  `);throw Error(`Workflow job "${t}" not found. Available jobs:\n${e}`)}return{type:`workflow-job`,name:e.name,exportName:e.exportName}}if(n.length===1){let[e]=n,t=o(e,`workflow job missing`);return{type:`workflow-job`,name:t.name,exportName:t.exportName}}let r=n.map(e=>` - "${e.name}" (export: ${e.exportName})`).join(`
69
- `);throw Error(`Multiple workflow jobs found. Specify one with --name:\n${r}`)}function deriveNameFromPath(e){return W.basename(e,W.extname(e))}const si=`db.ts`,ci=`db.snapshot.json`,li=[`/**`,` * Auto-generated Kysely types for one-off scripts in this directory.`," * Generated by `tailor function script` from the selected TailorDB schema.",` *`," * DO NOT EDIT - Re-run `tailor function script` to refresh.",` */`].join(`
70
- `);function generateScriptDbTypes(e){let t=Object.values(e.tables).map(e=>ar(e.name,e.fields)),n=t.reduce((e,t)=>({Timestamp:e.Timestamp||t.usedUtilityTypes.Timestamp,Serial:e.Serial||t.usedUtilityTypes.Serial}),{Timestamp:!1,Serial:!1}),r=or([{namespace:e.namespace,types:t,usedUtilityTypes:n}]);return`${li}\n\n${r}`}function isGeneratedScriptDbTypes(e){return e.includes("Generated by `tailor function script`")}function assertGeneratedTypeScript(e,t){let{errors:n}=kr(W.basename(e),t);if(n.length>0)throw Error(`Generated ${e} does not parse as TypeScript: ${n.map(e=>e.message).join(`; `)}`)}function generateScriptSkeleton(e){let{getDBImportPath:t,namespace:n}=e;return[`/**`,` * One-off script. Run it on the platform without deploying:`,` *`,` * tailor function run <this file>`,` *`,` * For large tables, batch updates by primary-key range instead of one`,` * statement over the whole table; see the "Performance and Large Tables"`,` * section in @tailor-platform/sdk's docs/services/tailordb-migration.md.`,` */`,``,`import { getDB } from ${JSON.stringify(t)};`,``,`export default async function main() {`,` const db = getDB(${JSON.stringify(n)});`,``,` // A transaction rolls every change back when any statement fails.`,` await db.transaction().execute(async (trx) => {`,` // e.g. await trx.updateTable("MyTable").set({ ... }).where("id", "=", "...").execute();`,` });`,`}`,``].join(`
71
- `)}function loadScriptSchemaSnapshot(e){let t=W.join(W.dirname(e),ci);if(!X.existsSync(t))return null;let n;try{n=JSON.parse(X.readFileSync(t,`utf-8`))}catch(e){throw Error(`Failed to parse schema snapshot ${t}: ${e instanceof Error?e.message:e}. Re-run \`tailor function script\` to regenerate it.`,{cause:e})}let r=n;if(typeof r!=`object`||!r||typeof r.namespace!=`string`||typeof r.tables!=`object`||r.tables===null)throw unexpectedSnapshotShapeError(t);let i=r.source??`remote`;if(i!==`local`&&i!==`remote`)throw unexpectedSnapshotShapeError(t);let a={...r};delete a.source;try{return{snapshotPath:t,source:i,snapshot:qt(a)}}catch{throw unexpectedSnapshotShapeError(t)}}function unexpectedSnapshotShapeError(e){return Error(`Schema snapshot ${e} has an unexpected shape. Re-run \`tailor function script\` to regenerate it.`)}async function verifyScriptSchemaSnapshot(e){let{client:t,workspaceId:n,config:r,configArgValue:i,sidecar:a}=e,{snapshot:o}=a,s=o.namespace;if(sn(r).includes(s)){let{namespaces:t}=await Ne({configPath:i,namespaces:[s]}),n=t[0];if(n){let t=Object.fromEntries(Object.values(n.tables).map(e=>[e.name,Ee(e)])),r=et(generatedContractSnapshot(o),generatedContractSnapshot({...o,tables:t}));if(pt(r))throw schemaDriftError(`the local table definitions`,r,e)}}let c=await ot(t,n,s),l=et(a.source===`local`?generatedContractSnapshot(o):qt(pickTableFields(o)),a.source===`local`?generatedContractSnapshot(c):qt(pickTableFields(c)));if(pt(l))throw schemaDriftError(`the deployed schema`,l,e)}function fieldsOnlySnapshot(e){return qt(pickTableFields(St(e)))}function generatedContractSnapshot(e){let t=fieldsOnlySnapshot(e),n=Object.fromEntries(Object.entries(t.tables).map(([t,n])=>{let r=e.tables[t],i=Object.fromEntries(Object.entries(n.fields).map(([e,t])=>[e,preserveGeneratedContract(t,r?.fields[e])]));return[t,{...n,fields:i}]}));return qt({...t,tables:n})}function preserveGeneratedContract(e,t){let n=e.fields?Object.fromEntries(Object.entries(e.fields).map(([e,n])=>[e,preserveGeneratedContract(n,t?.fields?.[e])])):void 0,r=t?.hooks?.create!==void 0||t?.default!==void 0||t?.optionalOnCreate===!0;return{...e,...n===void 0?{}:{fields:n},...r?{optionalOnCreate:!0}:{}}}function pickTableFields(e){let t=Object.fromEntries(Object.entries(e.tables).map(([e,t])=>[e,{name:t.name,pluralForm:t.pluralForm,fields:t.fields}]));return{...e,tables:t}}function schemaDriftError(e,t,n){let r=[...n.configArgValue===`tailor.config.ts`?[]:[`--config=${n.configArgValue}`],`--workspace-id=${n.workspaceId}`,...n.profileArgValue===void 0?[]:[`--profile=${n.profileArgValue}`]],i=Yn([`tailor`,`function`,`script`,n.scriptArgValue,...n.sidecar.source===`remote`?[`--remote`]:[],...r]),a=Yn([`tailor`,`function`,`run`,n.scriptArgValue,`--allow-schema-drift`,...r]);return Error(`Schema drift detected: ${ci} next to the script no longer matches ${e}.\n\n${st(t)}\n\nRefresh the generated types with ${i}, or run anyway with ${a}.`)}const ui=g({name:`run`,aliases:[`test-run`],description:`Run a function on the Tailor Platform server without deploying.`,args:J.object({...N,file:G(J.string(),{positional:!0,description:`Path to the function file`}),name:G(J.string().optional(),{alias:`n`,description:"Workflow job name to run (matches the `name` field of createWorkflowJob)"}),arg:G(J.string().optional(),{alias:`a`,description:`JSON argument to pass to the function`}),"machine-user":G(J.string().optional(),{alias:`m`,description:`Machine user name for authentication. Falls back to the active profile's default machine user.`,env:`TAILOR_PLATFORM_MACHINE_USER_NAME`}),config:G(J.string().default(`tailor.config.ts`),{alias:`c`,description:`Path to SDK config file`}),"allow-schema-drift":G(J.boolean().default(!1),{description:`Run a scaffolded script even when its schema snapshot no longer matches`})}),notes:"You can pass either a source file (`.ts`) or a pre-bundled file (`.js`).\nWhen a `.js` file is provided, detection and bundling are skipped and the file is executed as-is.\n\nA script scaffolded by `function script` with a generated `db.ts` is checked against its `db.snapshot.json` before execution and refused on schema drift; pass `--allow-schema-drift` to run it anyway. The check compares table and field structure; hook and validator code changes are not detected.\n\n`test-run` is a deprecated alias of this command and will be removed in v3.\n\n> [!WARNING]\n> Workflow job `.start()` calls do not work in this mode.\n> Started jobs are not executed; only the target job's `body` function runs in isolation.",examples:[{cmd:`resolvers/add.ts --arg '{"a":1,"b":2}'`,desc:`Run a resolver with input arguments`},{cmd:`workflows/sample.ts --name validate-order`,desc:`Run a specific workflow job by name`},{cmd:`build/resolvers/add.js --arg '{"a":1,"b":2}'`,desc:`Run a pre-bundled .js file directly`}],run:async e=>{invokedViaTestRunAlias(process.argv)&&s.warn("`tailor function test-run` is deprecated and will be removed in v3. Use `tailor function run` instead.");let t=s.jsonMode,n=W.resolve(e.file);if(!X.existsSync(n))throw Error(`File not found: ${n}`);let{config:i}=await B(e.config),a=resolveAuthNamespace(i.auth),o=await resolveMachineUserName({cliMachineUser:e[`machine-user`],cliMachineUserSource:He(e[`machine-user`]),profile:e.profile,authConfig:i.auth}),l=await D({profile:e.profile}),u=await H(l),d=await j({workspaceId:e[`workspace-id`],profile:e.profile}),f=await resolveMachineUser({client:u,workspaceId:d,authNamespace:a,machineUserName:o,authConfig:i.auth}),p=W.relative(process.cwd(),n),m=n.endsWith(`.js`);if(!m){if(e[`allow-schema-drift`])X.existsSync(W.join(W.dirname(n),`db.snapshot.json`))&&s.warn(`Skipping the schema snapshot check (--allow-schema-drift).`);else{let t=loadScriptSchemaSnapshot(n);t&&(s.info(`Checking the script's schema snapshot for drift...`),await verifyScriptSchemaSnapshot({client:u,workspaceId:d,config:i,configArgValue:e.config,scriptArgValue:e.file,profileArgValue:e.profile,sidecar:t}))}}let h,g,_,v;if(m)g=W.basename(n),h=X.readFileSync(n,`utf-8`),s.info(`Using pre-bundled script ${c.bold(g)}`);else{s.info(`Detecting function type from ${c.path(p)}`);let t=await detectFunctionType({filePath:n,jobName:e.name});_=t.type,v=t.name,s.info(`Detected: ${c.bold(t.type)} ${c.info(`"${t.name}"`)}`),t.type===`resolver`&&e.arg&&!t.hasInput&&(s.warn(`--arg is ignored because this resolver has no input schema. Define "input" in your resolver to use --arg.`),e.arg=void 0),s.info(`Bundling...`);let r=W.dirname(i.path);({bundledCode:h,scriptName:g}=await bundleForRun({detected:t,sourceFile:n,baseDir:r,defaultPermission:t.type===`resolver`?Mn({config:i.resolver,filePath:n,baseDir:r}):void 0,env:i.env??{},inlineSourcemap:i.inlineSourcemap,logLevel:i.logLevel,machineUser:f,workspaceId:d})),s.info(`Bundled as ${c.bold(g)}`)}let y=gr(r,{namespace:a,machineUserName:f.name});s.info(`Executing on workspace ${c.dim(d)}...`);let b;if(e.arg!==void 0)try{b=JSON.parse(e.arg)}catch(e){throw Error(`Invalid --arg JSON: ${e instanceof Error?e.message:e}`,{cause:e})}let x=await nn({client:u,workspaceId:d,name:g,code:h,arg:b,invoker:y});if(t)s.out({success:x.success,scriptName:g,functionType:_,functionName:v,logs:x.logs,result:x.result,error:x.error});else{if(x.success?s.success(`Execution succeeded`):s.error(`Execution failed`),x.logs.trim()){s.log(c.bold(`
69
+ `);throw Error(`Multiple workflow jobs found. Specify one with --name:\n${r}`)}function deriveNameFromPath(e){return U.basename(e,U.extname(e))}const ri=`db.ts`,ii=`db.snapshot.json`,ai=[`/**`,` * Auto-generated Kysely types for one-off scripts in this directory.`," * Generated by `tailor function script` from the selected TailorDB schema.",` *`," * DO NOT EDIT - Re-run `tailor function script` to refresh.",` */`].join(`
70
+ `);function generateScriptDbTypes(e){let t=Object.values(e.tables).map(e=>rr(e.name,e.fields)),n=t.reduce((e,t)=>({Timestamp:e.Timestamp||t.usedUtilityTypes.Timestamp,Serial:e.Serial||t.usedUtilityTypes.Serial}),{Timestamp:!1,Serial:!1}),r=ir([{namespace:e.namespace,types:t,usedUtilityTypes:n}]);return`${ai}\n\n${r}`}function isGeneratedScriptDbTypes(e){return e.includes("Generated by `tailor function script`")}function assertGeneratedTypeScript(e,t){let{errors:n}=Tr(U.basename(e),t);if(n.length>0)throw Error(`Generated ${e} does not parse as TypeScript: ${n.map(e=>e.message).join(`; `)}`)}function generateScriptSkeleton(e){let{getDBImportPath:t,namespace:n}=e;return[`/**`,` * One-off script. Run it on the platform without deploying:`,` *`,` * tailor function run <this file>`,` *`,` * For large tables, batch updates by primary-key range instead of one`,` * statement over the whole table; see the "Performance and Large Tables"`,` * section in @tailor-platform/sdk's docs/services/tailordb-migration.md.`,` */`,``,`import { getDB } from ${JSON.stringify(t)};`,``,`export default async function main() {`,` const db = getDB(${JSON.stringify(n)});`,``,` // A transaction rolls every change back when any statement fails.`,` await db.transaction().execute(async (trx) => {`,` // e.g. await trx.updateTable("MyTable").set({ ... }).where("id", "=", "...").execute();`,` });`,`}`,``].join(`
71
+ `)}function loadScriptSchemaSnapshot(e){let t=U.join(U.dirname(e),ii);if(!Y.existsSync(t))return null;let n;try{n=JSON.parse(Y.readFileSync(t,`utf-8`))}catch(e){throw Error(`Failed to parse schema snapshot ${t}: ${e instanceof Error?e.message:e}. Re-run \`tailor function script\` to regenerate it.`,{cause:e})}let r=n;if(typeof r!=`object`||!r||typeof r.namespace!=`string`||typeof r.tables!=`object`||r.tables===null)throw unexpectedSnapshotShapeError(t);let i=r.source??`remote`;if(i!==`local`&&i!==`remote`)throw unexpectedSnapshotShapeError(t);let a={...r};delete a.source;try{return{snapshotPath:t,source:i,snapshot:I(a)}}catch{throw unexpectedSnapshotShapeError(t)}}function unexpectedSnapshotShapeError(e){return Error(`Schema snapshot ${e} has an unexpected shape. Re-run \`tailor function script\` to regenerate it.`)}async function verifyScriptSchemaSnapshot(e){let{client:t,workspaceId:n,config:r,configArgValue:i,sidecar:a}=e,{snapshot:o}=a,s=o.namespace;if(rn(r).includes(s)){let{namespaces:t}=await Ne({configPath:i,namespaces:[s]}),n=t[0];if(n){let t=Object.fromEntries(Object.values(n.tables).map(e=>[e.name,Ee(e)])),r=nt(generatedContractSnapshot(o),generatedContractSnapshot({...o,tables:t}));if(pt(r))throw schemaDriftError(`the local table definitions`,r,e)}}let c=await Lt(t,n,s),l=nt(a.source===`local`?generatedContractSnapshot(o):I(pickTableFields(o)),a.source===`local`?generatedContractSnapshot(c):I(pickTableFields(c)));if(pt(l))throw schemaDriftError(`the deployed schema`,l,e)}function fieldsOnlySnapshot(e){return I(pickTableFields(Ct(e)))}function generatedContractSnapshot(e){let t=fieldsOnlySnapshot(e),n=Object.fromEntries(Object.entries(t.tables).map(([t,n])=>{let r=e.tables[t],i=Object.fromEntries(Object.entries(n.fields).map(([e,t])=>[e,preserveGeneratedContract(t,r?.fields[e])]));return[t,{...n,fields:i}]}));return I({...t,tables:n})}function preserveGeneratedContract(e,t){let n=e.fields?Object.fromEntries(Object.entries(e.fields).map(([e,n])=>[e,preserveGeneratedContract(n,t?.fields?.[e])])):void 0,r=t?.hooks?.create!==void 0||t?.default!==void 0||t?.optionalOnCreate===!0;return{...e,...n===void 0?{}:{fields:n},...r?{optionalOnCreate:!0}:{}}}function pickTableFields(e){let t=Object.fromEntries(Object.entries(e.tables).map(([e,t])=>[e,{name:t.name,pluralForm:t.pluralForm,fields:t.fields}]));return{...e,tables:t}}function schemaDriftError(e,t,n){let r=[...n.configArgValue===`tailor.config.ts`?[]:[`--config=${n.configArgValue}`],`--workspace-id=${n.workspaceId}`,...n.profileArgValue===void 0?[]:[`--profile=${n.profileArgValue}`]],i=qn([`tailor`,`function`,`script`,n.scriptArgValue,...n.sidecar.source===`remote`?[`--remote`]:[],...r]),a=qn([`tailor`,`function`,`run`,n.scriptArgValue,`--allow-schema-drift`,...r]);return Error(`Schema drift detected: ${ii} next to the script no longer matches ${e}.\n\n${st(t)}\n\nRefresh the generated types with ${i}, or run anyway with ${a}.`)}const oi=g({name:`run`,aliases:[`test-run`],description:`Run a function on the Tailor Platform server without deploying.`,args:q.object({...d,file:W(q.string(),{positional:!0,description:`Path to the function file`}),name:W(q.string().optional(),{alias:`n`,description:"Workflow job name to run (matches the `name` field of createWorkflowJob)"}),arg:W(q.string().optional(),{alias:`a`,description:`JSON argument to pass to the function`}),"machine-user":W(q.string().optional(),{alias:`m`,description:`Machine user name for authentication. Falls back to the active profile's default machine user.`,env:`TAILOR_PLATFORM_MACHINE_USER_NAME`}),config:W(q.string().default(`tailor.config.ts`),{alias:`c`,description:`Path to SDK config file`}),"allow-schema-drift":W(q.boolean().default(!1),{description:`Run a scaffolded script even when its schema snapshot no longer matches`})}),notes:"You can pass either a source file (`.ts`) or a pre-bundled file (`.js`).\nWhen a `.js` file is provided, detection and bundling are skipped and the file is executed as-is.\n\nA script scaffolded by `function script` with a generated `db.ts` is checked against its `db.snapshot.json` before execution and refused on schema drift; pass `--allow-schema-drift` to run it anyway. The check compares table and field structure; hook and validator code changes are not detected.\n\n`test-run` is a deprecated alias of this command and will be removed in v3.\n\n> [!WARNING]\n> Workflow job `.start()` calls do not work in this mode.\n> Started jobs are not executed; only the target job's `body` function runs in isolation.",examples:[{cmd:`resolvers/add.ts --arg '{"a":1,"b":2}'`,desc:`Run a resolver with input arguments`},{cmd:`workflows/sample.ts --name validate-order`,desc:`Run a specific workflow job by name`},{cmd:`build/resolvers/add.js --arg '{"a":1,"b":2}'`,desc:`Run a pre-bundled .js file directly`}],run:async e=>{invokedViaTestRunAlias(process.argv)&&s.warn("`tailor function test-run` is deprecated and will be removed in v3. Use `tailor function run` instead.");let t=s.jsonMode,n=U.resolve(e.file);if(!Y.existsSync(n))throw Error(`File not found: ${n}`);let{config:r}=await R(e.config),a=resolveAuthNamespace(r.auth),o=await resolveMachineUserName({cliMachineUser:e[`machine-user`],cliMachineUserSource:Xe(e[`machine-user`]),profile:e.profile,authConfig:r.auth}),l=await E({profile:e.profile}),u=await V(l),d=await k({workspaceId:e[`workspace-id`],profile:e.profile}),f=await resolveMachineUser({client:u,workspaceId:d,authNamespace:a,machineUserName:o,authConfig:r.auth}),p=U.relative(process.cwd(),n),m=n.endsWith(`.js`);if(!m){if(e[`allow-schema-drift`])Y.existsSync(U.join(U.dirname(n),`db.snapshot.json`))&&s.warn(`Skipping the schema snapshot check (--allow-schema-drift).`);else{let t=loadScriptSchemaSnapshot(n);t&&(s.info(`Checking the script's schema snapshot for drift...`),await verifyScriptSchemaSnapshot({client:u,workspaceId:d,config:r,configArgValue:e.config,scriptArgValue:e.file,profileArgValue:e.profile,sidecar:t}))}}let h,g,_,v;if(m)g=U.basename(n),h=Y.readFileSync(n,`utf-8`),s.info(`Using pre-bundled script ${c.bold(g)}`);else{s.info(`Detecting function type from ${c.path(p)}`);let t=await detectFunctionType({filePath:n,jobName:e.name});_=t.type,v=t.name,s.info(`Detected: ${c.bold(t.type)} ${c.info(`"${t.name}"`)}`),t.type===`resolver`&&e.arg&&!t.hasInput&&(s.warn(`--arg is ignored because this resolver has no input schema. Define "input" in your resolver to use --arg.`),e.arg=void 0),s.info(`Bundling...`);let i=U.dirname(r.path);({bundledCode:h,scriptName:g}=await bundleForRun({detected:t,sourceFile:n,baseDir:i,defaultPermission:t.type===`resolver`?An({config:r.resolver,filePath:n,baseDir:i}):void 0,env:r.env??{},inlineSourcemap:r.inlineSourcemap,logLevel:r.logLevel,machineUser:f,workspaceId:d})),s.info(`Bundled as ${c.bold(g)}`)}let y=mr(i,{namespace:a,machineUserName:f.name});s.info(`Executing on workspace ${c.dim(d)}...`);let b;if(e.arg!==void 0)try{b=JSON.parse(e.arg)}catch(e){throw Error(`Invalid --arg JSON: ${e instanceof Error?e.message:e}`,{cause:e})}let x=await Ie({client:u,workspaceId:d,name:g,code:h,arg:b,invoker:y});if(t)s.out({success:x.success,scriptName:g,functionType:_,functionName:v,logs:x.logs,result:x.result,error:x.error});else{if(x.success?s.success(`Execution succeeded`):s.error(`Execution failed`),x.logs.trim()){s.log(c.bold(`
72
72
  Logs:`));for(let e of x.logs.split(`
73
73
  `))s.log(` ${e}`)}if(x.result&&x.success){s.log(c.bold(`
74
74
  Result:`));try{let e=JSON.parse(x.result);s.log(` ${JSON.stringify(e,null,2).split(`
75
75
  `).join(`
76
76
  `)}`)}catch{s.log(` ${x.result}`)}}if(x.error&&!x.success){s.log(c.bold(`
77
- Error:`));let e=formatErrorWithSourcemap(x.error,h,process.cwd());e?s.log(e):s.log(` ${c.error(x.error)}`)}}x.success||process.exit(1)}}),di=new Set(dr(J.strictObject(re)).fields.filter(e=>e.type!==`boolean`).flatMap(e=>[e.cliName,...e.alias??[]].flatMap(toFlagTokens)));function toFlagTokens(e){return e.length===1?[`-${e}`]:[`--${e}`,`--${pr(e)}`]}function invokedViaTestRunAlias(e){let t=[];for(let n=2;n<e.length&&t.length<2;n++){let r=e[n];if(r===void 0||r===`--`)break;if(!r.startsWith(`-`)){t.push(r);continue}!r.includes(`=`)&&di.has(r)&&n++}return t[0]===`function`&&t[1]===`test-run`}function resolveAuthNamespace(e){if(e?.name)return e.name;throw Error(`Auth namespace is required. Ensure tailor.config.ts has an auth config.`)}async function resolveMachineUserName(e){let{cliMachineUser:t,cliMachineUserSource:n,profile:r,authConfig:i}=e,a=await Et({machineUser:t,machineUserSource:n,profile:r});if(a)return a;if(i&&!(`external`in i&&i.external)){let e=i.machineUsers;if(e){let t=Object.keys(e);if(t.length>0)return o(t[0],`machine user key missing`)}}throw Error(`Machine user is required. Provide --machine-user, set TAILOR_PLATFORM_MACHINE_USER_NAME, set a profile default with 'tailor profile update <profile> --machine-user <name>', or ensure tailor.config.ts has machine users configured.`)}async function resolveMachineUser(e){let{client:t,workspaceId:n,authNamespace:r,machineUserName:i,authConfig:a}=e,o=`00000000-0000-0000-0000-000000000000`;try{let{machineUser:e}=await t.getAuthMachineUser({workspaceId:n,authNamespace:r,name:i});e?.id&&(o=e.id)}catch{s.debug(`Could not fetch machine user "${i}" from server, using nil UUID`)}let c=a?.machineUsers?.[i],l=null,u=[];if(c&&typeof c==`object`){let e=c;l=e.attributes??null,u=e.attributeList??[]}return{name:i,id:o,attributes:l,attributeList:u}}const fi=g({name:`script`,description:"Scaffold a one-off script to run with `function run`.",args:J.object({...N,...ze,file:G(J.string(),{positional:!0,description:`Path to create the script at (must end with .ts)`}),namespace:G(J.string().optional(),{description:`Target TailorDB namespace (required when the config does not pin one)`}),remote:G(J.boolean().default(!1),{description:`Generate script-scoped DB types from the deployed schema`})}),notes:"The scaffolded script is a plain default-exported function; execute it with `tailor function run <file>`.\n\nBy default, when the project configures `kyselyTypePlugin`, the skeleton imports `getDB()` from the plugin's generated types. Without the plugin, the command uses the namespace's local table definitions to write a script-scoped `db.ts` plus a `db.snapshot.json` next to the script; `function run` refuses to run the script when that snapshot no longer matches the deployed or locally defined table and field structure.\n\nPass `--remote` to generate the script-scoped files from the deployed schema instead, even when `kyselyTypePlugin` is configured. This is required for an external namespace. Re-running the command refreshes `db.ts` and `db.snapshot.json` from the selected source and leaves the script itself untouched.",examples:[{cmd:`scripts/fix-prices.ts`,desc:`Scaffold a one-off script (single-namespace project)`},{cmd:`scripts/fix-prices.ts --namespace tailordb`,desc:`Scaffold a script targeting a specific namespace`},{cmd:`scripts/fix-prices.ts --namespace shared --remote`,desc:`Scaffold from a deployed or external namespace`}],run:async e=>{let t=W.resolve(e.file);if(!t.endsWith(`.ts`))throw Error(`Script path must end with .ts: ${e.file}`);let n=W.dirname(t),r=X.existsSync(t),i=W.join(n,si),a=W.join(n,ci);if(t===i)throw Error(`${si} is reserved for the generated Kysely types written next to the script. Choose a different script file name.`);let{config:l,plugins:u}=await B(e.config),d=u.find(e=>e.id===sr),f=X.existsSync(a);if(e.remote&&d!==void 0&&r&&!f)throw Error(`Script already exists: ${W.relative(process.cwd(),t)}. Scaffold --remote at a new path so the generated script imports its script-scoped db.ts.`);let p=e.remote||d===void 0||f,m;if(p)try{m=loadScriptSchemaSnapshot(t)?.snapshot.namespace}catch{}let h=resolveNamespace({config:l,explicit:e.namespace,sidecarNamespace:m,remote:e.remote});if(m!==void 0&&m!==h)throw Error(`This directory's generated types target namespace "${m}" (${ci}). Scaffold scripts for namespace "${h}" in a separate directory.`);let g=[],_,v;if(p){let t;if(e.remote){let n=await D({profile:e.profile}),r=await H(n),i=await j({workspaceId:e[`workspace-id`],profile:e.profile});v=i,s.info(`Fetching deployed schema of namespace ${c.bold(h)}...`),t=await ot(r,i,h)}else{s.info(`Loading local definitions of namespace ${c.bold(h)}...`);let{namespaces:n}=await Ne({configPath:e.config,namespaces:[h]}),r=o(n[0],`namespace ${h}`);t=ye(r.tables,h)}if(Object.keys(t.tables).length===0){let t=e.remote?`deployed tables in workspace ${o(v,`workspace ID`)}`:`locally defined tables`;throw Error(`Namespace "${h}" has no ${t}.`)}if(X.existsSync(i)&&!isGeneratedScriptDbTypes(X.readFileSync(i,`utf-8`)))throw Error(`Refusing to overwrite ${W.relative(process.cwd(),i)}: it was not generated by \`tailor function script\`.`);let r=generateScriptDbTypes(t);assertGeneratedTypeScript(i,r),X.mkdirSync(n,{recursive:!0}),X.writeFileSync(i,r),g.push(i),X.writeFileSync(a,JSON.stringify({...t,source:e.remote?`remote`:`local`},null,2)+`
78
- `),g.push(a),_=`./db`}else{if(r)throw Error(`Script already exists: ${W.relative(process.cwd(),t)}. It imports the project's generated Kysely types, so there is nothing to refresh.`);let e=resolveKyselyTypesPath(u);_=toImportSpecifier(W.relative(n,e)),X.existsSync(e)||s.warn(`Generated Kysely types not found at ${c.path(W.relative(process.cwd(),e))}. Run \`tailor generate\` before executing the script.`)}if(!r){let e=generateScriptSkeleton({getDBImportPath:_,namespace:h});assertGeneratedTypeScript(t,e),X.mkdirSync(n,{recursive:!0}),X.writeFileSync(t,e),g.unshift(t)}let y=[`tailor`,`function`,`run`,W.relative(process.cwd(),t)];e.config!==`tailor.config.ts`&&y.push(`--config=${e.config}`);let b=v??e[`workspace-id`];if(b!==void 0&&y.push(`--workspace-id=${b}`),e.profile!==void 0&&y.push(`--profile=${e.profile}`),s.jsonMode){s.out({script:t,created:g,namespace:h,usesGeneratedDbTypes:p});return}r&&s.info(`Script already exists; refreshed generated types only.`);for(let e of g)s.success(`Created ${c.path(W.relative(process.cwd(),e))}`);s.info(`Next: edit the script, then run ${Yn(y)}`)}});function resolveNamespace(e){let{config:t,explicit:n,sidecarNamespace:r,remote:i}=e,a=x(t),o=sn(t),s=i?a:o;if(n){if(!i&&!o.includes(n))throw Error(`Namespace "${n}" is not owned by the config and requires --remote.`);return n}if(r!==void 0){if(!i&&!o.includes(r))throw Error(`Namespace "${r}" is not owned by the config and requires --remote.`);return r}if(s.length===1){let e=s[0];if(e!==void 0)return e}throw s.length>1?Error(`Multiple TailorDB namespaces are defined (${s.join(`, `)}). Specify one with --namespace.`):!i&&a.length>0?Error(`No owned TailorDB namespace is defined in the config. External namespaces require --remote: ${a.join(`, `)}.`):Error(`No TailorDB namespace is defined in the config.`)}function resolveKyselyTypesPath(e){let t=rt(e,`@tailor-platform/kysely-type`)?.distPath??`./generated/tailordb.ts`;if(t.length===0)throw Error(`kyselyTypePlugin is configured without a distPath; cannot locate getDB().`);return W.resolve(t)}function toImportSpecifier(e){let t=e.replace(/\.ts$/,``);return t.startsWith(`.`)?t:`./${t}`}const pi=K({name:`function`,description:`Manage functions`,subCommands:{get:w,list:Ie,logs:oi,run:ui,script:fi},async run(){await q(Ie,[])}}),mi=g({name:`generate`,description:`Generate files using Tailor configuration.`,args:J.strictObject({config:G(J.string().default(`tailor.config.ts`),{alias:`c`,description:`Path to SDK config file`})}),run:async e=>{let{initTelemetry:t}=await import(`../telemetry-DXHP3VVi.mjs`);await t(),await fn({configPath:e.config})}}),detectPackageManager$1=()=>{let e=[`npm`,`yarn`,`pnpm`,`bun`],t=process.env.npm_config_user_agent;if(!t)return;let[n]=t.split(`/`);if(e.includes(n))return n},hi=g({name:`init`,description:`Initialize a new project using create-sdk.`,args:J.strictObject({name:G(J.string().optional(),{positional:!0,description:`Project name`}),template:G(J.string().optional(),{alias:`t`,description:`Template name`})}),run:async e=>{let t=await Gn(),n=t.version&&t.version!==`0.0.0`?t.version:`latest`,r=detectPackageManager$1();r||=(s.warn(`Could not detect package manager, defaulting to npm`),`npm`);let i=[`create`,`@tailor-platform/sdk@${n}`,...e.name?[e.name]:[],...r===`npm`?[`--`]:[],...e.template?[`--template`,e.template]:[]];s.log(`Running: ${r} ${i.join(` `)}`),Fr(r,i,{stdio:`inherit`})}}),gi=8085,_i=`http://localhost:${gi}/callback`;function randomState(){return Cr.randomBytes(32).toString(`base64url`)}function getProfileUserMismatch(e,t,n){if(!(!e.profile||!e.profileUser||t===e.profileUser||n===e.profileUser))return{profile:e.profile,oldUser:e.profileUser,authenticatedUser:t,loginMode:e.loginMode??`user`}}function quoteCommandArg(e,t=process.platform){return t===`win32`?/^[A-Za-z0-9_./:@+=,-]+$/.test(e)?e:void 0:`'${e.replaceAll(`'`,`'\\''`)}'`}function profileUpdateCommand(e){let t=quoteCommandArg(e.profile),n=quoteCommandArg(e.authenticatedUser);return t&&n?`tailor profile update --user ${n} -- ${t}`:[`tailor profile update --user <authenticated-user> -- <profile>`,`profile = ${JSON.stringify(e.profile)}`,`authenticated user = ${JSON.stringify(e.authenticatedUser)}`].join(`
79
- `)}function retryInstruction(e){if(e.loginMode===`machine-user`)return`Then retry the original machine-user login command.`;let t=quoteCommandArg(e.profile);return t?`Then run:\n tailor login --profile ${t}`:`Then retry the browser login with the same profile value.`}function profileUserMismatchError(e){let t=profileUpdateCommand(e),n=retryInstruction(e);return Error(U`
77
+ Error:`));let e=formatErrorWithSourcemap(x.error,h,process.cwd());e?s.log(e):s.log(` ${c.error(x.error)}`)}}x.success||process.exit(1)}}),si=new Set(lr(q.strictObject(ae)).fields.filter(e=>e.type!==`boolean`).flatMap(e=>[e.cliName,...e.alias??[]].flatMap(toFlagTokens)));function toFlagTokens(e){return e.length===1?[`-${e}`]:[`--${e}`,`--${dr(e)}`]}function invokedViaTestRunAlias(e){let t=[];for(let n=2;n<e.length&&t.length<2;n++){let r=e[n];if(r===void 0||r===`--`)break;if(!r.startsWith(`-`)){t.push(r);continue}!r.includes(`=`)&&si.has(r)&&n++}return t[0]===`function`&&t[1]===`test-run`}function resolveAuthNamespace(e){if(e?.name)return e.name;throw Error(`Auth namespace is required. Ensure tailor.config.ts has an auth config.`)}async function resolveMachineUserName(e){let{cliMachineUser:t,cliMachineUserSource:n,profile:r,authConfig:i}=e,a=await Et({machineUser:t,machineUserSource:n,profile:r});if(a)return a;if(i&&!(`external`in i&&i.external)){let e=i.machineUsers;if(e){let t=Object.keys(e);if(t.length>0)return o(t[0],`machine user key missing`)}}throw Error(`Machine user is required. Provide --machine-user, set TAILOR_PLATFORM_MACHINE_USER_NAME, set a profile default with 'tailor profile update <profile> --machine-user <name>', or ensure tailor.config.ts has machine users configured.`)}async function resolveMachineUser(e){let{client:t,workspaceId:n,authNamespace:r,machineUserName:i,authConfig:a}=e,o=`00000000-0000-0000-0000-000000000000`;try{let{machineUser:e}=await t.getAuthMachineUser({workspaceId:n,authNamespace:r,name:i});e?.id&&(o=e.id)}catch{s.debug(`Could not fetch machine user "${i}" from server, using nil UUID`)}let c=a?.machineUsers?.[i],l=null,u=[];if(c&&typeof c==`object`){let e=c;l=e.attributes??null,u=e.attributeList??[]}return{name:i,id:o,attributes:l,attributeList:u}}const ci=g({name:`script`,description:"Scaffold a one-off script to run with `function run`.",args:q.object({...d,...Re,file:W(q.string(),{positional:!0,description:`Path to create the script at (must end with .ts)`}),namespace:W(q.string().optional(),{description:`Target TailorDB namespace (required when the config does not pin one)`}),remote:W(q.boolean().default(!1),{description:`Generate script-scoped DB types from the deployed schema`})}),notes:"The scaffolded script is a plain default-exported function; execute it with `tailor function run <file>`.\n\nBy default, when the project configures `kyselyTypePlugin`, the skeleton imports `getDB()` from the plugin's generated types. Without the plugin, the command uses the namespace's local table definitions to write a script-scoped `db.ts` plus a `db.snapshot.json` next to the script; `function run` refuses to run the script when that snapshot no longer matches the deployed or locally defined table and field structure.\n\nPass `--remote` to generate the script-scoped files from the deployed schema instead, even when `kyselyTypePlugin` is configured. This is required for an external namespace. Re-running the command refreshes `db.ts` and `db.snapshot.json` from the selected source and leaves the script itself untouched.",examples:[{cmd:`scripts/fix-prices.ts`,desc:`Scaffold a one-off script (single-namespace project)`},{cmd:`scripts/fix-prices.ts --namespace tailordb`,desc:`Scaffold a script targeting a specific namespace`},{cmd:`scripts/fix-prices.ts --namespace shared --remote`,desc:`Scaffold from a deployed or external namespace`}],run:async e=>{let t=U.resolve(e.file);if(!t.endsWith(`.ts`))throw Error(`Script path must end with .ts: ${e.file}`);let n=U.dirname(t),r=Y.existsSync(t),i=U.join(n,ri),a=U.join(n,ii);if(t===i)throw Error(`${ri} is reserved for the generated Kysely types written next to the script. Choose a different script file name.`);let{config:l,plugins:u}=await R(e.config),d=u.find(e=>e.id===ar),f=Y.existsSync(a);if(e.remote&&d!==void 0&&r&&!f)throw Error(`Script already exists: ${U.relative(process.cwd(),t)}. Scaffold --remote at a new path so the generated script imports its script-scoped db.ts.`);let p=e.remote||d===void 0||f,m;if(p)try{m=loadScriptSchemaSnapshot(t)?.snapshot.namespace}catch{}let h=resolveNamespace({config:l,explicit:e.namespace,sidecarNamespace:m,remote:e.remote});if(m!==void 0&&m!==h)throw Error(`This directory's generated types target namespace "${m}" (${ii}). Scaffold scripts for namespace "${h}" in a separate directory.`);let g=[],_,v;if(p){let t;if(e.remote){let n=await E({profile:e.profile}),r=await V(n),i=await k({workspaceId:e[`workspace-id`],profile:e.profile});v=i,s.info(`Fetching deployed schema of namespace ${c.bold(h)}...`),t=await Lt(r,i,h)}else{s.info(`Loading local definitions of namespace ${c.bold(h)}...`);let{namespaces:n}=await Ne({configPath:e.config,namespaces:[h]}),r=o(n[0],`namespace ${h}`);t=be(r.tables,h)}if(Object.keys(t.tables).length===0){let t=e.remote?`deployed tables in workspace ${o(v,`workspace ID`)}`:`locally defined tables`;throw Error(`Namespace "${h}" has no ${t}.`)}if(Y.existsSync(i)&&!isGeneratedScriptDbTypes(Y.readFileSync(i,`utf-8`)))throw Error(`Refusing to overwrite ${U.relative(process.cwd(),i)}: it was not generated by \`tailor function script\`.`);let r=generateScriptDbTypes(t);assertGeneratedTypeScript(i,r),Y.mkdirSync(n,{recursive:!0}),Y.writeFileSync(i,r),g.push(i),Y.writeFileSync(a,JSON.stringify({...t,source:e.remote?`remote`:`local`},null,2)+`
78
+ `),g.push(a),_=`./db`}else{if(r)throw Error(`Script already exists: ${U.relative(process.cwd(),t)}. It imports the project's generated Kysely types, so there is nothing to refresh.`);let e=resolveKyselyTypesPath(u);_=toImportSpecifier(U.relative(n,e)),Y.existsSync(e)||s.warn(`Generated Kysely types not found at ${c.path(U.relative(process.cwd(),e))}. Run \`tailor generate\` before executing the script.`)}if(!r){let e=generateScriptSkeleton({getDBImportPath:_,namespace:h});assertGeneratedTypeScript(t,e),Y.mkdirSync(n,{recursive:!0}),Y.writeFileSync(t,e),g.unshift(t)}let y=[`tailor`,`function`,`run`,U.relative(process.cwd(),t)];e.config!==`tailor.config.ts`&&y.push(`--config=${e.config}`);let b=v??e[`workspace-id`];if(b!==void 0&&y.push(`--workspace-id=${b}`),e.profile!==void 0&&y.push(`--profile=${e.profile}`),s.jsonMode){s.out({script:t,created:g,namespace:h,usesGeneratedDbTypes:p});return}r&&s.info(`Script already exists; refreshed generated types only.`);for(let e of g)s.success(`Created ${c.path(U.relative(process.cwd(),e))}`);s.info(`Next: edit the script, then run ${qn(y)}`)}});function resolveNamespace(e){let{config:t,explicit:n,sidecarNamespace:r,remote:i}=e,a=b(t),o=rn(t),s=i?a:o;if(n){if(!i&&!o.includes(n))throw Error(`Namespace "${n}" is not owned by the config and requires --remote.`);return n}if(r!==void 0){if(!i&&!o.includes(r))throw Error(`Namespace "${r}" is not owned by the config and requires --remote.`);return r}if(s.length===1){let e=s[0];if(e!==void 0)return e}throw s.length>1?Error(`Multiple TailorDB namespaces are defined (${s.join(`, `)}). Specify one with --namespace.`):!i&&a.length>0?Error(`No owned TailorDB namespace is defined in the config. External namespaces require --remote: ${a.join(`, `)}.`):Error(`No TailorDB namespace is defined in the config.`)}function resolveKyselyTypesPath(e){let t=at(e,`@tailor-platform/kysely-type`)?.distPath??`./generated/tailordb.ts`;if(t.length===0)throw Error(`kyselyTypePlugin is configured without a distPath; cannot locate getDB().`);return U.resolve(t)}function toImportSpecifier(e){let t=e.replace(/\.ts$/,``);return t.startsWith(`.`)?t:`./${t}`}const li=G({name:`function`,description:`Manage functions`,subCommands:{get:Dt,list:C,logs:ni,run:oi,script:ci},async run(){await K(C,[])}}),ui=g({name:`generate`,description:`Generate files using Tailor configuration.`,args:q.strictObject({config:W(q.string().default(`tailor.config.ts`),{alias:`c`,description:`Path to SDK config file`})}),run:async e=>{let{initTelemetry:t}=await import(`../telemetry-DXHP3VVi.mjs`);await t(),await un({configPath:e.config})}}),detectPackageManager=()=>{let e=[`npm`,`yarn`,`pnpm`,`bun`],t=process.env.npm_config_user_agent;if(!t)return;let[n]=t.split(`/`);if(e.includes(n))return n},di=g({name:`init`,description:`Initialize a new project using create-sdk.`,args:q.strictObject({name:W(q.string().optional(),{positional:!0,description:`Project name`}),template:W(q.string().optional(),{alias:`t`,description:`Template name`})}),run:async e=>{let t=await Un(),n=t.version&&t.version!==`0.0.0`?t.version:`latest`,r=detectPackageManager();r||=(s.warn(`Could not detect package manager, defaulting to npm`),`npm`);let i=[`create`,`@tailor-platform/sdk@${n}`,...e.name?[e.name]:[],...r===`npm`?[`--`]:[],...e.template?[`--template`,e.template]:[]];s.log(`Running: ${r} ${i.join(` `)}`),jr(r,i,{stdio:`inherit`})}}),fi=8085,pi=`http://localhost:${fi}/callback`;function randomState(){return br.randomBytes(32).toString(`base64url`)}function getProfileUserMismatch(e,t,n){if(!(!e.profile||!e.profileUser||t===e.profileUser||n===e.profileUser))return{profile:e.profile,oldUser:e.profileUser,authenticatedUser:t,loginMode:e.loginMode??`user`}}function quoteCommandArg(e,t=process.platform){return t===`win32`?/^[A-Za-z0-9_./:@+=,-]+$/.test(e)?e:void 0:`'${e.replaceAll(`'`,`'\\''`)}'`}function profileUpdateCommand(e){let t=quoteCommandArg(e.profile),n=quoteCommandArg(e.authenticatedUser);return t&&n?`tailor profile update --user ${n} -- ${t}`:[`tailor profile update --user <authenticated-user> -- <profile>`,`profile = ${JSON.stringify(e.profile)}`,`authenticated user = ${JSON.stringify(e.authenticatedUser)}`].join(`
79
+ `)}function retryInstruction(e){if(e.loginMode===`machine-user`)return`Then retry the original machine-user login command.`;let t=quoteCommandArg(e.profile);return t?`Then run:\n tailor login --profile ${t}`:`Then retry the browser login with the same profile value.`}function profileUserMismatchError(e){let t=profileUpdateCommand(e),n=retryInstruction(e);return Error(H`
80
80
  Profile "${e.profile}" is configured for "${e.oldUser}", but login authenticated "${e.authenticatedUser}".
81
81
  The authenticated user has been saved. To use it with this profile, run:
82
82
  ${t}
83
83
  ${n}
84
- `)}function shouldUpdateCurrentUser(e,t){return!e||kn(t)}const startAuthServer=async(e={})=>{let t=xn(e.platformConfig),n=randomState(),r=await Sr(),i=await t.authorizationCode.getAuthorizeUri({redirectUri:_i,state:n,codeVerifier:r}).catch(e=>{throw Error(`Failed to prepare the login authorization URL: ${qn(e).message}`,{cause:e})});return new Promise((a,c)=>{let handleCallback=async(i,s)=>{try{if(!i.url?.startsWith(`/callback`))throw Error(`Invalid callback URL`);let c=await t.authorizationCode.getTokenFromCodeRedirect(`http://${i.headers.host}${i.url}`,{redirectUri:_i,state:n,codeVerifier:r}),l=await Dn(c.accessToken,e.platformConfig),u=await M();await Ae(u,l.sub,{accessToken:c.accessToken,refreshToken:c.refreshToken??void 0},new Date(o(c.expiresAt,`token response missing expiresAt`)).toISOString(),{platformConfig:e.platformConfig,email:l.email});let d=getProfileUserMismatch(e,l.email,l.sub);if(d)throw V(u),profileUserMismatchError(d);(e.updateCurrentUser??!0)&&(u.current_user=l.sub),await ee(u,l.email,l.sub,e.platformConfig),V(u),s.writeHead(200,{"Content-Type":`application/json`}),s.end(JSON.stringify({status:`ok`,message:`Successfully authenticated. Please close this window.`})),a()}catch(e){s.writeHead(401),s.end(`Authentication failed`),c(qn(e))}finally{l.close()}},l=Er.createServer((e,t)=>void handleCallback(e,t)),u=setTimeout(()=>{l.close(),c(Error(`Login timeout exceeded`))},3e5);l.on(`close`,()=>{clearTimeout(u)}),l.on(`error`,e=>{c(e)});let openBrowser=async()=>{s.info(`Opening browser for login:\n\n${i}\n`);try{await Dr(i)}catch{s.warn(`Failed to open browser automatically. Please open the URL above manually.`)}};l.listen(gi,()=>void openBrowser())})};async function loginAsMachineUser(e){let t=e.clientSecret??await z.password({message:`Client secret`}),n=await yn(e.clientId,t,e.platformConfig),r=await M();await Ae(r,e.clientId,{accessToken:n.accessToken},new Date(o(n.expiresAt,`token response missing expiresAt`)).toISOString(),{platformConfig:e.platformConfig});let i=getProfileUserMismatch(e,e.clientId);if(i)throw V(r),profileUserMismatchError(i);(e.updateCurrentUser??!0)&&(r.current_user=e.clientId),V(r)}const vi=g({name:`login`,description:`Login to Tailor Platform.`,args:J.xor([J.strictObject({profile:G(J.string().optional(),{alias:`p`,description:`Workspace profile whose platform settings should be used for login.`,env:`TAILOR_PLATFORM_PROFILE`})}).describe(`User Login`),J.strictObject({"machine-user":G(J.literal(!0),{description:`Login as a platform machine user.`,required:!0}),"client-id":G(J.string(),{description:`Client ID`,env:`TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID`,required:!0}),"client-secret":G(J.string().optional(),{description:`Client secret`,env:`TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET`}),profile:G(J.string().optional(),{alias:`p`,description:`Workspace profile whose platform settings should be used for login.`,env:`TAILOR_PLATFORM_PROFILE`})}).describe(`Machine User Login`)]),run:async e=>{try{let t,n;if(`profile`in e&&e.profile){let r=(await M()).profiles[e.profile];if(!r)throw Error(`Profile "${e.profile}" not found`);t=be(r),n=r.user}let r=shouldUpdateCurrentUser(e.profile,t);`machine-user`in e?await loginAsMachineUser({clientId:e.clientId,clientSecret:e.clientSecret,profile:e.profile,profileUser:n,platformConfig:t,updateCurrentUser:r,loginMode:`machine-user`}):await startAuthServer({profile:e.profile,profileUser:n,platformConfig:t,updateCurrentUser:r,loginMode:`user`}),s.success(`Successfully logged in to Tailor Platform.`)}finally{await bn()}}}),yi=g({name:`logout`,description:`Logout from Tailor Platform.`,args:J.strictObject({profile:G(J.string().optional(),{alias:`p`,description:`Workspace profile whose platform settings should be used for logout.`,env:`TAILOR_PLATFORM_PROFILE`})}),run:async e=>{let t=e.profile||process.env.TAILOR_PLATFORM_PROFILE,n=await M(),r=t?n.profiles[t]:void 0;if(t&&!r)throw Error(`Profile "${t}" not found`);let i=r?be(r):void 0,a=r?r.user:n.current_user,o=kn(i),c=t?{allowLegacyUserKey:!0}:void 0;if(!a){s.info(`You are not logged in.`);return}let hasDefaultUserToken=()=>Fe(n,a,{platformUrl:Cn}),shouldClearCurrentUser=()=>n.current_user===a&&(o||!on(n,a))&&!hasDefaultUserToken(),l,u=!1;try{l=await Ct(n,a,i,c)}catch(e){u=!0,s.warn(`Failed to revoke token: ${e instanceof Error?e.message:e}`)}if(!l&&!u){s.info(`You are not logged in.`),shouldClearCurrentUser()&&(n.current_user=null),V(n);return}if(l)try{let e=xn(i),t=l.refreshToken?`refresh_token`:`access_token`;await e.revoke({accessToken:l.accessToken,refreshToken:l.refreshToken??null,expiresAt:Date.parse(l.userEntry.token_expires_at)},t)}catch(e){s.warn(`Failed to revoke token: ${e instanceof Error?e.message:e}`)}await Me(n,a,i,c),shouldClearCurrentUser()&&(n.current_user=null),V(n),s.success(`Successfully logged out from Tailor Platform.`)}}),bi=K({name:`machineuser`,description:`Manage machine users in your Tailor Platform application.`,subCommands:{list:Ze,token:_t},async run(){await q(Ze,[])}}),xi=K({name:`oauth2client`,description:`Manage OAuth2 clients in your Tailor Platform application.`,subCommands:{list:ct,get:Rt},async run(){await q(ct,[])}}),Si=g({name:`open`,description:`Open Tailor Platform Console.`,args:J.strictObject({...k}),run:async e=>{let t=await j({workspaceId:e[`workspace-id`],profile:e.profile}),{config:n}=await B(e.config),r=n.name,i=`/workspaces/${t}/applications/${encodeURIComponent(r)}/overview`,a=await we({profile:e.profile,...e[`workspace-id`]===void 0?{}:{allowMissingProfile:!0}}),o=new URL(i,a).toString(),c=s.jsonMode;s.info(`Opening Tailor Platform Console...`);let l=!0;try{await Dr(o)}catch{l=!1}if(c){s.out({consoleUrl:o,workspaceId:t,applicationName:r,opened:l});return}l?(s.out(`Console URL: ${o}`),s.out(`Workspace ID: ${t}`),s.out(`Application Name: ${r}`)):s.warn(`Failed to open browser automatically. Please open this URL manually:\n${o}`)}}),Ci=K({name:`folder`,description:`Manage organization folders.`,subCommands:{create:Ot,delete:Jt,get:tt,list:Gt,update:Zt}}),wi=K({name:`organization`,description:`Manage Tailor Platform organizations.`,subCommands:{folder:Ci,get:l,list:Ge,tree:Ve,update:zt},async run(){await q(Ge,[])}}),Ti=`api.auth.authconnection.crashreport.deploy.executor.function.generate.init.login.logout.machineuser.oauth2client.open.organization.plugin.profile.query.remove.secret.setup.show.skills.staticwebsite.tailordb.upgrade.user.workflow.workspace`.split(`.`),Ei={seed:`@tailor-platform/sdk-plugin-seed`,"tailordb-erd":`@tailor-platform/sdk-plugin-tailordb-erd`},Di=process.platform===`win32`?`;`:`:`;function*ancestorDirs(e){let t=W.resolve(e),n=W.dirname(t);for(;n!==t;)yield t,t=n,n=W.dirname(t);yield t}function windowsExecutableExts(){return(process.env.PATHEXT??`.COM;.EXE;.BAT;.CMD;.PS1`).split(`;`).map(e=>e.trim().toLowerCase()).filter(Boolean)}function isExecutable(e){try{_r(e,process.platform===`win32`?vr.F_OK:vr.X_OK)}catch{return!1}if(process.platform===`win32`){let t=W.extname(e).toLowerCase();return t===``||windowsExecutableExts().includes(t)}return!0}function binaryCandidates(e){return process.platform===`win32`?[e,...windowsExecutableExts().map(t=>`${e}${t}`)]:[e]}function pathDirs(){return(process.env.PATH??``).split(Di).filter(Boolean)}function nodeModulesBinDirs(){let e=[];for(let t of ancestorDirs(process.cwd()))e.push(W.join(t,`node_modules`,`.bin`));return e}function findExecutableIn(e,t){let n=binaryCandidates(t);for(let t of e)for(let e of n){let n=W.join(t,e);if(isExecutable(n))return n}}function resolvePlugin(e,t){if(e.includes(`/`)||e.includes(`\\`)||e.includes(`\0`))return null;let n=`${t}-${e}`,r=findExecutableIn(nodeModulesBinDirs(),n);if(r)return{name:e,path:r,source:`node_modules`};let i=findExecutableIn(pathDirs(),n);return i?{name:e,path:i,source:`path`}:null}function stripBinExt(e){if(process.platform!==`win32`)return e;let t=W.extname(e);return t?e.slice(0,-t.length):e}function listPlugins(e){let t=`${e}-`,n=new Map,scan=(e,r)=>{for(let i of e){let e;try{e=yr(i)}catch{continue}for(let a of e){let e=stripBinExt(a);if(!e.startsWith(t)||e.length===t.length)continue;let o=e.slice(t.length);if(n.has(o))continue;let s=W.join(i,a);isExecutable(s)&&n.set(o,{name:o,path:s,source:r})}}};return scan(nodeModulesBinDirs(),`node_modules`),scan(pathDirs(),`path`),[...n.values()]}async function resolveActiveUser(e){let t=await M(),n=e?t.profiles[e]?.user:t.current_user;if(n)return t.users[n]?.email??n}async function buildPluginEnv(e={}){let{profile:t}=e,n={},r=process.argv[1];r&&(n.TAILOR_BIN=r);try{let{version:e}=await Gn();e&&(n.TAILOR_VERSION=e)}catch{}let i=C();if(i&&(n.TAILOR_CONFIG_PATH=i),e.skipPlatformContext)return n;let a;try{a=await p({profile:t,allowMissingProfile:!0})}catch{}n.TAILOR_PLATFORM_URL=Ln(a),n.TAILOR_PLATFORM_OAUTH2_CLIENT_ID=vn(a);try{n.TAILOR_PLATFORM_WORKSPACE_ID=await j({profile:t})}catch{}try{let e=await resolveActiveUser(t);e&&(n.TAILOR_PLATFORM_USER=e)}catch{}try{let e=await D({profile:t});e&&(n.TAILOR_PLATFORM_TOKEN=e)}catch{}return n}function signalToExitCode(e){let t=Ar.constants.signals[e];return typeof t==`number`?128+t:1}function buildSpawnTarget(e,t){if(process.platform!==`win32`)return{command:e,args:[...t],shell:!1};let n=W.extname(e).toLowerCase();return n===`.exe`||n===`.com`?{command:e,args:[...t],shell:!1}:n===`.cmd`||n===`.bat`?{command:e,args:[...t],shell:!0}:n===`.ps1`?{command:findExecutableIn(pathDirs(),`pwsh`)??findExecutableIn(pathDirs(),`powershell`)??`powershell`,args:[`-NoProfile`,`-ExecutionPolicy`,`Bypass`,`-File`,e,...t],shell:!1}:{command:findExecutableIn(pathDirs(),`sh`)??`sh`,args:[`-c`,`command "$@"`,`--`,e,...t],shell:!1}}function hasEnvFileFlag(e){for(let t of e){if(t===`--`)return!1;if(t===`--env-file`||t===`-e`||t===`--env-file-if-exists`||t.startsWith(`--env-file=`)||t.startsWith(`-e=`)||t.startsWith(`--env-file-if-exists=`))return!0}return!1}function explicitProfileFromArgs(e){let t;for(let n=0;n<e.length;n++){let r=e[n];if(r===void 0||r===`--`)break;if(r===`--profile`||r===`-p`){let r=e[n+1];r!==void 0&&!r.startsWith(`-`)&&(t=r,n++);continue}r.startsWith(`--profile=`)?t=r.slice(10):r.startsWith(`-p=`)&&(t=r.slice(3))}return t||void 0}function pluginSlug(e,t){return[...e??[],t].join(`-`)}async function dispatchPlugin(e){let t=pluginSlug(e.commandPath,e.name),n=resolvePlugin(t,e.cliName);if(!n)return;let r=explicitProfileFromArgs(e.args)??e.profile,i={...process.env,...await buildPluginEnv({profile:r,skipPlatformContext:hasEnvFileFlag(e.args)})},{command:a,args:o,shell:c}=buildSpawnTarget(n.path,e.args);return await new Promise(n=>{let r=Pr(a,o,{stdio:`inherit`,env:i,shell:c});r.on(`error`,r=>{s.error(`Failed to run plugin "${e.cliName}-${t}": ${r.message}`),n(1)}),r.on(`close`,(e,t)=>{n(t?signalToExitCode(t):e??0)})})}async function dispatchPluginWithInstallHint(e){let t=await dispatchPlugin(e);if(t!==void 0)return t;let n=Ei[pluginSlug(e.commandPath,e.name)];if(!n)return;let r=[e.cliName,...e.commandPath??[],e.name].join(` `);return s.error(`"${r}" is provided by the ${n} CLI plugin, which is not installed.`),s.info(`Install it with: npm install -D ${n}`),1}const Oi=g({name:`list`,description:"List discovered plugins (executables named `<cli>-<name>` on PATH or node_modules/.bin).",args:J.strictObject({}),run:async()=>{let e=await Gn(),t=Object.keys(e.bin??{})[0]||`tailor`,n=new Set(Ti),r=listPlugins(t);if(r.length===0){s.info(U`
84
+ `)}function shouldUpdateCurrentUser(e,t){return!e||xn(t)}const startAuthServer=async(e={})=>{let t=En(e.platformConfig),n=randomState(),r=await yr(),i=await t.authorizationCode.getAuthorizeUri({redirectUri:pi,state:n,codeVerifier:r}).catch(e=>{throw Error(`Failed to prepare the login authorization URL: ${Gn(e).message}`,{cause:e})});return new Promise((a,c)=>{let handleCallback=async(i,s)=>{try{if(!i.url?.startsWith(`/callback`))throw Error(`Invalid callback URL`);let c=await t.authorizationCode.getTokenFromCodeRedirect(`http://${i.headers.host}${i.url}`,{redirectUri:pi,state:n,codeVerifier:r}),l=await _n(c.accessToken,e.platformConfig),u=await j();await Ae(u,l.sub,{accessToken:c.accessToken,refreshToken:c.refreshToken??void 0},new Date(o(c.expiresAt,`token response missing expiresAt`)).toISOString(),{platformConfig:e.platformConfig,email:l.email});let d=getProfileUserMismatch(e,l.email,l.sub);if(d)throw z(u),profileUserMismatchError(d);(e.updateCurrentUser??!0)&&(u.current_user=l.sub),await te(u,l.email,l.sub,e.platformConfig),z(u),s.writeHead(200,{"Content-Type":`application/json`}),s.end(JSON.stringify({status:`ok`,message:`Successfully authenticated. Please close this window.`})),a()}catch(e){s.writeHead(401),s.end(`Authentication failed`),c(Gn(e))}finally{l.close()}},l=Sr.createServer((e,t)=>void handleCallback(e,t)),u=setTimeout(()=>{l.close(),c(Error(`Login timeout exceeded`))},3e5);l.on(`close`,()=>{clearTimeout(u)}),l.on(`error`,e=>{c(e)});let openBrowser=async()=>{s.info(`Opening browser for login:\n\n${i}\n`);try{await Cr(i)}catch{s.warn(`Failed to open browser automatically. Please open the URL above manually.`)}};l.listen(fi,()=>void openBrowser())})};async function loginAsMachineUser(e){let t=e.clientSecret??await L.password({message:`Client secret`}),n=await Tn(e.clientId,t,e.platformConfig),r=await j();await Ae(r,e.clientId,{accessToken:n.accessToken},new Date(o(n.expiresAt,`token response missing expiresAt`)).toISOString(),{platformConfig:e.platformConfig});let i=getProfileUserMismatch(e,e.clientId);if(i)throw z(r),profileUserMismatchError(i);(e.updateCurrentUser??!0)&&(r.current_user=e.clientId),z(r)}const mi=g({name:`login`,description:`Login to Tailor Platform.`,args:q.xor([q.strictObject({profile:W(q.string().optional(),{alias:`p`,description:`Workspace profile whose platform settings should be used for login.`,env:`TAILOR_PLATFORM_PROFILE`})}).describe(`User Login`),q.strictObject({"machine-user":W(q.literal(!0),{description:`Login as a platform machine user.`,required:!0}),"client-id":W(q.string(),{description:`Client ID`,env:`TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID`,required:!0}),"client-secret":W(q.string().optional(),{description:`Client secret`,env:`TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET`}),profile:W(q.string().optional(),{alias:`p`,description:`Workspace profile whose platform settings should be used for login.`,env:`TAILOR_PLATFORM_PROFILE`})}).describe(`Machine User Login`)]),run:async e=>{try{let t,n;if(`profile`in e&&e.profile){let r=(await j()).profiles[e.profile];if(!r)throw Error(`Profile "${e.profile}" not found`);t=A(r),n=r.user}let r=shouldUpdateCurrentUser(e.profile,t);`machine-user`in e?await loginAsMachineUser({clientId:e.clientId,clientSecret:e.clientSecret,profile:e.profile,profileUser:n,platformConfig:t,updateCurrentUser:r,loginMode:`machine-user`}):await startAuthServer({profile:e.profile,profileUser:n,platformConfig:t,updateCurrentUser:r,loginMode:`user`}),s.success(`Successfully logged in to Tailor Platform.`)}finally{await Sn()}}}),hi=g({name:`logout`,description:`Logout from Tailor Platform.`,args:q.strictObject({profile:W(q.string().optional(),{alias:`p`,description:`Workspace profile whose platform settings should be used for logout.`,env:`TAILOR_PLATFORM_PROFILE`})}),run:async e=>{let t=e.profile||process.env.TAILOR_PLATFORM_PROFILE,n=await j(),r=t?n.profiles[t]:void 0;if(t&&!r)throw Error(`Profile "${t}" not found`);let i=r?A(r):void 0,a=r?r.user:n.current_user,o=xn(i),c=t?{allowLegacyUserKey:!0}:void 0;if(!a){s.info(`You are not logged in.`);return}let hasDefaultUserToken=()=>Fe(n,a,{platformUrl:zn}),shouldClearCurrentUser=()=>n.current_user===a&&(o||!nn(n,a))&&!hasDefaultUserToken(),l,u=!1;try{l=await wt(n,a,i,c)}catch(e){u=!0,s.warn(`Failed to revoke token: ${e instanceof Error?e.message:e}`)}if(!l&&!u){s.info(`You are not logged in.`),shouldClearCurrentUser()&&(n.current_user=null),z(n);return}if(l)try{let e=En(i),t=l.refreshToken?`refresh_token`:`access_token`;await e.revoke({accessToken:l.accessToken,refreshToken:l.refreshToken??null,expiresAt:Date.parse(l.userEntry.token_expires_at)},t)}catch(e){s.warn(`Failed to revoke token: ${e instanceof Error?e.message:e}`)}await Me(n,a,i,c),shouldClearCurrentUser()&&(n.current_user=null),z(n),s.success(`Successfully logged out from Tailor Platform.`)}}),gi=G({name:`machineuser`,description:`Manage machine users in your Tailor Platform application.`,subCommands:{list:$e,token:_t},async run(){await K($e,[])}}),_i=G({name:`oauth2client`,description:`Manage OAuth2 clients in your Tailor Platform application.`,subCommands:{list:ct,get:Rt},async run(){await K(ct,[])}}),vi=g({name:`open`,description:`Open Tailor Platform Console.`,args:q.strictObject({...O}),run:async e=>{let t=await k({workspaceId:e[`workspace-id`],profile:e.profile}),{config:n}=await R(e.config),r=n.name,i=`/workspaces/${t}/applications/${encodeURIComponent(r)}/overview`,a=await we({profile:e.profile,...e[`workspace-id`]===void 0?{}:{allowMissingProfile:!0}}),o=new URL(i,a).toString(),c=s.jsonMode;s.info(`Opening Tailor Platform Console...`);let l=!0;try{await Cr(o)}catch{l=!1}if(c){s.out({consoleUrl:o,workspaceId:t,applicationName:r,opened:l});return}l?(s.out(`Console URL: ${o}`),s.out(`Workspace ID: ${t}`),s.out(`Application Name: ${r}`)):s.warn(`Failed to open browser automatically. Please open this URL manually:\n${o}`)}}),yi=G({name:`folder`,description:`Manage organization folders.`,subCommands:{create:kt,delete:Wt,get:rt,list:Ht,update:Jt}}),bi=G({name:`organization`,description:`Manage Tailor Platform organizations.`,subCommands:{folder:yi,get:l,list:Je,tree:He,update:zt},async run(){await K(Je,[])}}),xi=`api.auth.authconnection.crashreport.deploy.executor.function.generate.init.login.logout.machineuser.oauth2client.open.organization.plugin.profile.query.remove.secret.show.skills.staticwebsite.tailordb.upgrade.user.workflow.workspace`.split(`.`),Si={seed:`@tailor-platform/sdk-plugin-seed`,setup:`@tailor-platform/sdk-plugin-setup`,"tailordb-erd":`@tailor-platform/sdk-plugin-tailordb-erd`},Ci=process.platform===`win32`?`;`:`:`;function*ancestorDirs(e){let t=U.resolve(e),n=U.dirname(t);for(;n!==t;)yield t,t=n,n=U.dirname(t);yield t}function windowsExecutableExts(){return(process.env.PATHEXT??`.COM;.EXE;.BAT;.CMD;.PS1`).split(`;`).map(e=>e.trim().toLowerCase()).filter(Boolean)}function isExecutable(e){try{hr(e,process.platform===`win32`?gr.F_OK:gr.X_OK)}catch{return!1}if(process.platform===`win32`){let t=U.extname(e).toLowerCase();return t===``||windowsExecutableExts().includes(t)}return!0}function binaryCandidates(e){return process.platform===`win32`?[e,...windowsExecutableExts().map(t=>`${e}${t}`)]:[e]}function pathDirs(){return(process.env.PATH??``).split(Ci).filter(Boolean)}function nodeModulesBinDirs(){let e=[];for(let t of ancestorDirs(process.cwd()))e.push(U.join(t,`node_modules`,`.bin`));return e}function findExecutableIn(e,t){let n=binaryCandidates(t);for(let t of e)for(let e of n){let n=U.join(t,e);if(isExecutable(n))return n}}function resolvePlugin(e,t){if(e.includes(`/`)||e.includes(`\\`)||e.includes(`\0`))return null;let n=`${t}-${e}`,r=findExecutableIn(nodeModulesBinDirs(),n);if(r)return{name:e,path:r,source:`node_modules`};let i=findExecutableIn(pathDirs(),n);return i?{name:e,path:i,source:`path`}:null}function stripBinExt(e){if(process.platform!==`win32`)return e;let t=U.extname(e);return t?e.slice(0,-t.length):e}function listPlugins(e){let t=`${e}-`,n=new Map,scan=(e,r)=>{for(let i of e){let e;try{e=_r(i)}catch{continue}for(let a of e){let e=stripBinExt(a);if(!e.startsWith(t)||e.length===t.length)continue;let o=e.slice(t.length);if(n.has(o))continue;let s=U.join(i,a);isExecutable(s)&&n.set(o,{name:o,path:s,source:r})}}};return scan(nodeModulesBinDirs(),`node_modules`),scan(pathDirs(),`path`),[...n.values()]}async function resolveActiveUser(e){let t=await j(),n=e?t.profiles[e]?.user:t.current_user;if(n)return t.users[n]?.email??n}async function buildPluginEnv(e={}){let{profile:t}=e,n={},r=process.argv[1];r&&(n.TAILOR_BIN=r);try{let{version:e}=await Un();e&&(n.TAILOR_VERSION=e)}catch{}let i=S();if(i&&(n.TAILOR_CONFIG_PATH=i),e.skipPlatformContext)return n;let a;try{a=await m({profile:t,allowMissingProfile:!0})}catch{}n.TAILOR_PLATFORM_URL=Dn(a),n.TAILOR_PLATFORM_OAUTH2_CLIENT_ID=In(a);try{n.TAILOR_PLATFORM_WORKSPACE_ID=await k({profile:t})}catch{}try{let e=await resolveActiveUser(t);e&&(n.TAILOR_PLATFORM_USER=e)}catch{}try{let e=await E({profile:t});e&&(n.TAILOR_PLATFORM_TOKEN=e)}catch{}return n}function signalToExitCode(e){let t=Er.constants.signals[e];return typeof t==`number`?128+t:1}function buildSpawnTarget(e,t){if(process.platform!==`win32`)return{command:e,args:[...t],shell:!1};let n=U.extname(e).toLowerCase();return n===`.exe`||n===`.com`?{command:e,args:[...t],shell:!1}:n===`.cmd`||n===`.bat`?{command:e,args:[...t],shell:!0}:n===`.ps1`?{command:findExecutableIn(pathDirs(),`pwsh`)??findExecutableIn(pathDirs(),`powershell`)??`powershell`,args:[`-NoProfile`,`-ExecutionPolicy`,`Bypass`,`-File`,e,...t],shell:!1}:{command:findExecutableIn(pathDirs(),`sh`)??`sh`,args:[`-c`,`command "$@"`,`--`,e,...t],shell:!1}}function hasEnvFileFlag(e){for(let t of e){if(t===`--`)return!1;if(t===`--env-file`||t===`-e`||t===`--env-file-if-exists`||t.startsWith(`--env-file=`)||t.startsWith(`-e=`)||t.startsWith(`--env-file-if-exists=`))return!0}return!1}function explicitProfileFromArgs(e){let t;for(let n=0;n<e.length;n++){let r=e[n];if(r===void 0||r===`--`)break;if(r===`--profile`||r===`-p`){let r=e[n+1];r!==void 0&&!r.startsWith(`-`)&&(t=r,n++);continue}r.startsWith(`--profile=`)?t=r.slice(10):r.startsWith(`-p=`)&&(t=r.slice(3))}return t||void 0}function pluginSlug(e,t){return[...e??[],t].join(`-`)}async function dispatchPlugin(e){let t=pluginSlug(e.commandPath,e.name),n=resolvePlugin(t,e.cliName);if(!n)return;let r=explicitProfileFromArgs(e.args)??e.profile,i={...process.env,...await buildPluginEnv({profile:r,skipPlatformContext:hasEnvFileFlag(e.args)})},{command:a,args:o,shell:c}=buildSpawnTarget(n.path,e.args);return await new Promise(n=>{let r=Ar(a,o,{stdio:`inherit`,env:i,shell:c});r.on(`error`,r=>{s.error(`Failed to run plugin "${e.cliName}-${t}": ${r.message}`),n(1)}),r.on(`close`,(e,t)=>{n(t?signalToExitCode(t):e??0)})})}async function dispatchPluginWithInstallHint(e){let t=await dispatchPlugin(e);if(t!==void 0)return t;let n=Si[pluginSlug(e.commandPath,e.name)];if(!n)return;let r=[e.cliName,...e.commandPath??[],e.name].join(` `);return s.error(`"${r}" is provided by the ${n} CLI plugin, which is not installed.`),s.info(`Install it with: npm install -D ${n}`),1}const wi=g({name:`list`,description:"List discovered plugins (executables named `<cli>-<name>` on PATH or node_modules/.bin).",args:q.strictObject({}),run:async()=>{let e=await Un(),t=Object.keys(e.bin??{})[0]||`tailor`,n=new Set(xi),r=listPlugins(t);if(r.length===0){s.info(H`
85
85
  No plugins found.
86
86
  Install an executable named "${t}-<name>" on your PATH or in node_modules/.bin,
87
87
  then run it with "${t} <name>".
88
- `),s.jsonMode&&s.out([]);return}let i=r.map(e=>({name:e.name,source:e.source,path:e.path,shadowed:n.has(e.name)}));s.out(i);for(let e of i)e.shadowed&&s.warn(`Plugin "${t}-${e.name}" is shadowed by the builtin "${t} ${e.name}" command and will not be dispatched.`)}}),ki=K({name:`plugin`,description:`Manage and inspect CLI plugins (beta).`,subCommands:{list:Oi},async run(){await q(Oi,[])}}),Ai=g({name:`create`,description:`Create a new profile.`,args:J.strictObject({name:G(J.string(),{positional:!0,description:`Profile name`}),user:G(J.string(),{alias:`u`,description:`User email address or machine user client ID`}),"workspace-id":G(J.string(),{alias:`w`,description:`Workspace ID`}),permission:G(J.enum([`write`,`read`]).default(`write`),{description:`Profile permission. 'read' blocks all write commands while the profile is active.`}),"machine-user":G(J.string().optional(),{alias:`m`,description:`Default machine user name for application-data commands (query, workflow start, function run, machineuser token).`}),"machine-user-override":G(J.enum([`allow`,`deny`]).optional(),{description:`Whether the command line or TAILOR_PLATFORM_MACHINE_USER_NAME may override the profile's machine user. 'deny' requires --machine-user.`}),"platform-url":G(J.url().optional(),{description:`Platform API base URL for this profile.`,env:`TAILOR_PLATFORM_URL`}),"oauth2-client-id":G(J.string().optional(),{description:`OAuth2 client ID for logging in to this profile's platform.`,env:`TAILOR_PLATFORM_OAUTH2_CLIENT_ID`}),"console-url":G(J.url().optional(),{description:`Console base URL for this profile.`,env:`TAILOR_PLATFORM_CONSOLE_URL`})}),run:async e=>{if(e[`machine-user-override`]===`deny`&&!e[`machine-user`])throw Error(`--machine-user-override deny requires --machine-user.`);let t=await M();if(t.profiles[e.name])throw Error(`Profile "${e.name}" already exists.`);let n={...e[`platform-url`]?{platformUrl:e[`platform-url`]}:{},...e[`oauth2-client-id`]?{oauth2ClientId:e[`oauth2-client-id`]}:{},...e[`console-url`]?{consoleUrl:e[`console-url`]}:{}},r=Object.keys(n).length>0?n:void 0,{accessToken:i,user:a}=await b(t,e.user,r),o=await H(i,r);if(!(await Tn(async(e,t)=>{let{workspaces:n,nextPageToken:r}=await o.listWorkspaces({pageToken:e,pageSize:t});return[n,r]})).find(t=>t.id===e[`workspace-id`]))throw Error(`Workspace "${e[`workspace-id`]}" not found.`);t.profiles[e.name]={user:a,workspace_id:e[`workspace-id`],...e.permission===`read`?{readonly:!0}:{},...e[`machine-user`]?{machine_user:e[`machine-user`]}:{},...e[`machine-user-override`]===`deny`?{machine_user_override:`deny`}:{},...e[`platform-url`]?{platform_url:e[`platform-url`]}:{},...e[`oauth2-client-id`]?{oauth2_client_id:e[`oauth2-client-id`]}:{},...e[`console-url`]?{console_url:e[`console-url`]}:{}},V(t),e.json||s.success(`Profile "${e.name}" created successfully.`);let c={name:e.name,user:a,workspaceId:e[`workspace-id`],permission:e.permission,...e[`machine-user`]?{machineUser:e[`machine-user`],machineUserOverride:e[`machine-user-override`]??`allow`}:{},...e[`platform-url`]?{platformUrl:e[`platform-url`]}:{},...e[`oauth2-client-id`]?{oauth2ClientId:e[`oauth2-client-id`]}:{},...e[`console-url`]?{consoleUrl:e[`console-url`]}:{}};s.out(c)}}),ji=g({name:`delete`,description:`Delete a profile.`,args:J.strictObject({name:G(J.string(),{positional:!0,description:`Profile name`})}),run:async e=>{let t=await M();if(!t.profiles[e.name])throw Error(`Profile "${e.name}" not found.`);delete t.profiles[e.name],V(t),s.success(`Profile "${e.name}" deleted successfully.`)}}),Mi=g({name:`list`,description:`List all profiles.`,args:J.strictObject({}),run:async()=>{let e=await M(),t=s.jsonMode,n=Object.entries(e.profiles);if(n.length===0){s.info(U`
88
+ `),s.jsonMode&&s.out([]);return}let i=r.map(e=>({name:e.name,source:e.source,path:e.path,shadowed:n.has(e.name)}));s.out(i);for(let e of i)e.shadowed&&s.warn(`Plugin "${t}-${e.name}" is shadowed by the builtin "${t} ${e.name}" command and will not be dispatched.`)}}),Ti=G({name:`plugin`,description:`Manage and inspect CLI plugins (beta).`,subCommands:{list:wi},async run(){await K(wi,[])}}),Ei=g({name:`create`,description:`Create a new profile.`,args:q.strictObject({name:W(q.string(),{positional:!0,description:`Profile name`}),user:W(q.string(),{alias:`u`,description:`User email address or machine user client ID`}),"workspace-id":W(q.string(),{alias:`w`,description:`Workspace ID`}),permission:W(q.enum([`write`,`read`]).default(`write`),{description:`Profile permission. 'read' blocks all write commands while the profile is active.`}),"machine-user":W(q.string().optional(),{alias:`m`,description:`Default machine user name for application-data commands (query, workflow start, function run, machineuser token).`}),"machine-user-override":W(q.enum([`allow`,`deny`]).optional(),{description:`Whether the command line or TAILOR_PLATFORM_MACHINE_USER_NAME may override the profile's machine user. 'deny' requires --machine-user.`}),"platform-url":W(q.url().optional(),{description:`Platform API base URL for this profile.`,env:`TAILOR_PLATFORM_URL`}),"oauth2-client-id":W(q.string().optional(),{description:`OAuth2 client ID for logging in to this profile's platform.`,env:`TAILOR_PLATFORM_OAUTH2_CLIENT_ID`}),"console-url":W(q.url().optional(),{description:`Console base URL for this profile.`,env:`TAILOR_PLATFORM_CONSOLE_URL`})}),run:async e=>{if(e[`machine-user-override`]===`deny`&&!e[`machine-user`])throw Error(`--machine-user-override deny requires --machine-user.`);let t=await j();if(t.profiles[e.name])throw Error(`Profile "${e.name}" already exists.`);let n={...e[`platform-url`]?{platformUrl:e[`platform-url`]}:{},...e[`oauth2-client-id`]?{oauth2ClientId:e[`oauth2-client-id`]}:{},...e[`console-url`]?{consoleUrl:e[`console-url`]}:{}},r=Object.keys(n).length>0?n:void 0,{accessToken:i,user:a}=await y(t,e.user,r),o=await V(i,r);if(!(await mn(async(e,t)=>{let{workspaces:n,nextPageToken:r}=await o.listWorkspaces({pageToken:e,pageSize:t});return[n,r]})).find(t=>t.id===e[`workspace-id`]))throw Error(`Workspace "${e[`workspace-id`]}" not found.`);t.profiles[e.name]={user:a,workspace_id:e[`workspace-id`],...e.permission===`read`?{readonly:!0}:{},...e[`machine-user`]?{machine_user:e[`machine-user`]}:{},...e[`machine-user-override`]===`deny`?{machine_user_override:`deny`}:{},...e[`platform-url`]?{platform_url:e[`platform-url`]}:{},...e[`oauth2-client-id`]?{oauth2_client_id:e[`oauth2-client-id`]}:{},...e[`console-url`]?{console_url:e[`console-url`]}:{}},z(t),e.json||s.success(`Profile "${e.name}" created successfully.`);let c={name:e.name,user:a,workspaceId:e[`workspace-id`],permission:e.permission,...e[`machine-user`]?{machineUser:e[`machine-user`],machineUserOverride:e[`machine-user-override`]??`allow`}:{},...e[`platform-url`]?{platformUrl:e[`platform-url`]}:{},...e[`oauth2-client-id`]?{oauth2ClientId:e[`oauth2-client-id`]}:{},...e[`console-url`]?{consoleUrl:e[`console-url`]}:{}};s.out(c)}}),Di=g({name:`delete`,description:`Delete a profile.`,args:q.strictObject({name:W(q.string(),{positional:!0,description:`Profile name`})}),run:async e=>{let t=await j();if(!t.profiles[e.name])throw Error(`Profile "${e.name}" not found.`);delete t.profiles[e.name],z(t),s.success(`Profile "${e.name}" deleted successfully.`)}}),Oi=g({name:`list`,description:`List all profiles.`,args:q.strictObject({}),run:async()=>{let e=await j(),t=s.jsonMode,n=Object.entries(e.profiles);if(n.length===0){s.info(H`
89
89
  No profiles found.
90
90
  Please create a profile first using 'tailor profile create' command.
91
- `),t&&s.out([]);return}let r=n.map(([e,t])=>{let n=o(t,`profile entry "${e}" is undefined`);return{name:e,user:n.user,workspaceId:n.workspace_id,permission:n.readonly===!0?`read`:`write`,...n.machine_user?{machineUser:n.machine_user,machineUserOverride:n.machine_user_override??`allow`}:{},...n.platform_url?{platformUrl:n.platform_url}:{},...n.oauth2_client_id?{oauth2ClientId:n.oauth2_client_id}:{},...n.console_url?{consoleUrl:n.console_url}:{}}});s.out(r)}}),Ni=g({name:`update`,description:`Update profile properties.`,args:J.strictObject({name:G(J.string(),{positional:!0,description:`Profile name`}),user:G(J.string().optional(),{alias:`u`,description:`New user email address or machine user client ID`}),"workspace-id":G(J.string().optional(),{alias:`w`,description:`New workspace ID`}),permission:G(J.enum([`write`,`read`]).optional(),{description:`Profile permission. 'read' blocks all write commands; 'write' lifts the restriction.`}),"machine-user":G(J.string().optional(),{alias:`m`,description:`Default machine user name for application-data commands (query, workflow start, function run, machineuser token). Pass an empty string to clear.`}),"machine-user-override":G(J.enum([`allow`,`deny`]).optional(),{description:`Whether the command line or TAILOR_PLATFORM_MACHINE_USER_NAME may override the profile's machine user. 'deny' requires --machine-user; 'allow' lifts the restriction.`}),"platform-url":G(J.union([J.url(),J.literal(``)]).optional(),{description:`Platform API base URL for this profile. Pass an empty string to clear.`}),"oauth2-client-id":G(J.string().optional(),{description:`OAuth2 client ID for logging in to this profile's platform. Pass an empty string to clear.`}),"console-url":G(J.union([J.url(),J.literal(``)]).optional(),{description:`Console base URL for this profile. Pass an empty string to clear.`})}),run:async e=>{let t=await M(),n=t.profiles[e.name];if(!n)throw Error(`Profile "${e.name}" not found.`);if(!e.user&&!e[`workspace-id`]&&e.permission===void 0&&e[`machine-user`]===void 0&&e[`machine-user-override`]===void 0&&e[`platform-url`]===void 0&&e[`oauth2-client-id`]===void 0&&e[`console-url`]===void 0)throw Error(`Please provide at least one property to update.`);let r=n.user,i=e.user||r,a=n.workspace_id,o=e[`workspace-id`]||a,c=i,l=e[`machine-user`]===``?void 0:e[`machine-user`]??n.machine_user,u=e[`machine-user-override`]===`allow`?void 0:e[`machine-user-override`]??n.machine_user_override,d=e[`platform-url`]===``?void 0:e[`platform-url`]??n.platform_url,f=e[`oauth2-client-id`]===``?void 0:e[`oauth2-client-id`]??n.oauth2_client_id,p=e[`console-url`]===``?void 0:e[`console-url`]??n.console_url,m={...d?{platformUrl:d}:{},...f?{oauth2ClientId:f}:{},...p?{consoleUrl:p}:{}},h=Object.keys(m).length>0?m:void 0,g=e[`platform-url`]===``?be(n):h;if((e[`machine-user`]!==void 0||e[`machine-user-override`]!==void 0)&&u===`deny`&&!l)throw e[`machine-user-override`]===`deny`?Error(`--machine-user-override deny requires --machine-user.`):Error(`Cannot clear the machine user while machine-user-override is "deny". Also pass --machine-user-override allow.`);if(e.user!==void 0||e[`workspace-id`]!==void 0||e[`platform-url`]!==void 0){let e=await b(t,i,g);c=e.user;let n=await H(e.accessToken,h);if(!(await Tn(async(e,t)=>{let{workspaces:r,nextPageToken:i}=await n.listWorkspaces({pageToken:e,pageSize:t});return[r,i]})).find(e=>e.id===o))throw Error(`Workspace "${o}" not found.`)}n.user=c,n.workspace_id=o,e.permission===`read`?n.readonly=!0:e.permission===`write`&&delete n.readonly,e[`machine-user`]!==void 0&&(e[`machine-user`]===``?delete n.machine_user:n.machine_user=e[`machine-user`]),e[`machine-user-override`]===`deny`?n.machine_user_override=`deny`:e[`machine-user-override`]===`allow`&&delete n.machine_user_override,e[`platform-url`]!==void 0&&(e[`platform-url`]===``?delete n.platform_url:n.platform_url=e[`platform-url`]),e[`oauth2-client-id`]!==void 0&&(e[`oauth2-client-id`]===``?delete n.oauth2_client_id:n.oauth2_client_id=e[`oauth2-client-id`]),e[`console-url`]!==void 0&&(e[`console-url`]===``?delete n.console_url:n.console_url=e[`console-url`]),V(t),e.json||s.success(`Profile "${e.name}" updated successfully`);let _={name:e.name,user:c,workspaceId:o,permission:n.readonly===!0?`read`:`write`,...n.machine_user?{machineUser:n.machine_user,machineUserOverride:n.machine_user_override??`allow`}:{},...n.platform_url?{platformUrl:n.platform_url}:{},...n.oauth2_client_id?{oauth2ClientId:n.oauth2_client_id}:{},...n.console_url?{consoleUrl:n.console_url}:{}};s.out(_)}}),Pi=K({name:`profile`,description:`Manage workspace profiles (user + workspace combinations).`,subCommands:{create:Ai,delete:ji,list:Mi,update:Ni},async run(){await q(Mi,[])}}),Fi={"vault-name":G(J.string(),{alias:`V`,description:`Vault name`})},Ii={...Fi,name:G(J.string(),{alias:`n`,description:`Secret name`})},Li={...Ii,value:G(J.string(),{alias:`v`,description:`Secret value`})};async function checkVaultManaged(e){let{client:t,workspaceId:n,vaultName:r}=e,i=R(n,`vault`,r),a={isManaged:!1,trn:i,existingLabels:{}},o,c;try{let{metadata:e}=await t.getMetadata({trn:i});c=e?.labels??{},o=c[yt]}catch{return a}return o?(s.warn(`Vault "${r}" is managed by defineSecretManager() in tailor.config.ts (owner: "${o}"). Changes made via CLI may conflict with the config on the next apply.`),{isManaged:!0,trn:i,existingLabels:c}):a}async function releaseVaultOwnership(e){let{client:t,trn:n}=e;await Xe(t,{trn:n,remove:[yt,gt,jt]}),s.info(`Config ownership has been removed from this vault. Remove it from defineSecretManager() in your config to prevent the next apply from re-claiming it.`)}const Ri=g({name:`create`,description:`Create a secret in a vault.`,args:J.strictObject({...N,...Li,...F}),run:async e=>{await I({profile:e.profile});let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile}),i=await checkVaultManaged({client:n,workspaceId:r,vaultName:e[`vault-name`]});if(!(i.isManaged&&!e.yes&&!await z.confirm({message:`Do you want to proceed?`,default:!1}))){try{await n.createSecretManagerSecret({workspaceId:r,secretmanagerVaultName:e[`vault-name`],secretmanagerSecretName:e.name,secretmanagerSecretValue:e.value})}catch(t){if(t instanceof Q){if(t.code===Z.NotFound)throw Error(`Vault "${e[`vault-name`]}" not found.`,{cause:t});if(t.code===Z.AlreadyExists)throw Error(`Secret "${e.name}" already exists.`,{cause:t})}throw t}i.isManaged&&await releaseVaultOwnership({client:n,...i}),s.success(`Secret: ${e.name} created in vault: ${e[`vault-name`]}`)}}}),zi=g({name:`delete`,description:`Delete a secret in a vault.`,args:J.strictObject({...N,...Ii,...F}),run:async e=>{await I({profile:e.profile});let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile}),i=await checkVaultManaged({client:n,workspaceId:r,vaultName:e[`vault-name`]});if(!e.yes&&await z.text({message:`Enter the secret name to confirm deletion ("${e.name}"):`})!==e.name){s.info(`Secret deletion cancelled.`);return}try{await n.deleteSecretManagerSecret({workspaceId:r,secretmanagerVaultName:e[`vault-name`],secretmanagerSecretName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Secret "${e.name}" not found in vault "${e[`vault-name`]}".`,{cause:t}):t}i.isManaged&&await releaseVaultOwnership({client:n,...i}),s.success(`Secret: ${e.name} deleted from vault: ${e[`vault-name`]}`)}});function secretInfo(e){return{name:e.name,createdAt:e.createTime?br(e.createTime):null,updatedAt:e.updateTime?br(e.updateTime):null}}async function secretList(e){let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e.workspaceId,profile:e.profile}),i=qe(e.order);return(await On(async(t,a)=>{let{secrets:o,nextPageToken:s}=await n.listSecretManagerSecrets({workspaceId:r,secretmanagerVaultName:e.vaultName,pageToken:t,pageSize:a,pageDirection:i});return[o,s]},{limit:e.limit})).map(secretInfo)}const Bi=g({name:`list`,description:`List all secrets in a vault.`,args:J.strictObject({...N,...Fi,...We()}),run:async e=>{try{let t=await secretList({workspaceId:e[`workspace-id`],profile:e.profile,vaultName:e[`vault-name`],order:e.order,limit:e.limit});s.out(t)}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Vault "${e[`vault-name`]}" not found.`,{cause:t}):t}}}),Vi=g({name:`update`,description:`Update a secret in a vault.`,args:J.strictObject({...N,...Li,...F}),run:async e=>{await I({profile:e.profile});let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile}),i=await checkVaultManaged({client:n,workspaceId:r,vaultName:e[`vault-name`]});if(!(i.isManaged&&!e.yes&&!await z.confirm({message:`Do you want to proceed?`,default:!1}))){try{await n.updateSecretManagerSecret({workspaceId:r,secretmanagerVaultName:e[`vault-name`],secretmanagerSecretName:e.name,secretmanagerSecretValue:e.value})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Secret "${e.name}" not found in vault "${e[`vault-name`]}".`,{cause:t}):t}i.isManaged&&await releaseVaultOwnership({client:n,...i}),s.success(`Secret: ${e.name} updated in vault: ${e[`vault-name`]}`)}}}),Hi={name:G(J.string(),{positional:!0,description:`Vault name`})},Ui=g({name:`create`,description:`Create a new Secret Manager vault.`,args:J.strictObject({...N,...Hi}),run:async e=>{await I({profile:e.profile});let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile});try{await n.createSecretManagerVault({workspaceId:r,secretmanagerVaultName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.AlreadyExists?Error(`Vault "${e.name}" already exists.`,{cause:t}):t}s.success(`Vault: ${e.name} created`)}}),Wi=g({name:`delete`,description:`Delete a Secret Manager vault.`,args:J.strictObject({...N,...Hi,...F}),run:async e=>{await I({profile:e.profile});let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile}),i=await checkVaultManaged({client:n,workspaceId:r,vaultName:e.name});if(!e.yes&&await z.text({message:`Enter the vault name to confirm deletion ("${e.name}"):`})!==e.name){s.info(`Vault deletion cancelled.`);return}try{await n.deleteSecretManagerVault({workspaceId:r,secretmanagerVaultName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Vault "${e.name}" not found.`,{cause:t}):t}i.isManaged&&s.info(`Remove this vault from defineSecretManager() in your config to prevent the next apply from re-creating it.`),s.success(`Vault: ${e.name} deleted`)}});function vaultInfo(e){return{name:e.name,createdAt:e.createTime?br(e.createTime):null,updatedAt:e.updateTime?br(e.updateTime):null}}async function vaultList(e){let t=await D({profile:e?.profile}),n=await H(t),r=await j({workspaceId:e?.workspaceId,profile:e?.profile}),i=qe(e?.order);return(await On(async(e,t)=>{let{vaults:a,nextPageToken:o}=await n.listSecretManagerVaults({workspaceId:r,pageToken:e,pageSize:t,pageDirection:i});return[a,o]},{limit:e?.limit})).map(vaultInfo)}const Gi=g({name:`list`,description:`List all Secret Manager vaults in the workspace.`,args:J.strictObject({...N,...We()}),run:async e=>{let t=await vaultList({workspaceId:e[`workspace-id`],profile:e.profile,order:e.order,limit:e.limit});s.out(t)}}),Ki=K({name:`vault`,description:`Manage Secret Manager vaults.`,subCommands:{create:Ui,delete:Wi,list:Gi},async run(){await q(Gi,[])}}),qi=K({name:`secret`,description:`Manage Secret Manager vaults and secrets.`,subCommands:{vault:Ki,create:Ri,update:Vi,list:Bi,delete:zi},async run(){await q(Ki,[])}}),defaultGitRunner=(e,t)=>{let n=Fr(`git`,e,{cwd:t,encoding:`utf-8`});return n.status!==0||typeof n.stdout!=`string`?null:n.stdout.trim()};function detectDefaultBranch(e,t=defaultGitRunner,n=`--branch`){let r=t([`symbolic-ref`,`--short`,`refs/remotes/origin/HEAD`],e),i=r?.startsWith(`origin/`)?r.slice(7):r;if(!i)throw Error(`Could not detect the default branch from git. Pass ${n} <name>, or run 'git remote set-head origin --auto' to record it.`);return i}const Ji=`.github/tailor.lock`;function assertSafeLockPath(e){for(let t of[`.github`,Ji])try{if(X.lstatSync(W.join(e,t)).isSymbolicLink())throw Error(`Refusing to use ${Ji}: "${t}" is a symbolic link.`)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)continue;throw e}}function hashContent(e){return`sha256:${wr(`sha256`).update(e,`utf-8`).digest(`hex`)}`}function lockPath(e){return W.join(e,Ji)}function readLock(e){assertSafeLockPath(e);let t=lockPath(e);if(!X.existsSync(t))return null;let n;try{n=JSON.parse(X.readFileSync(t,`utf-8`))}catch(e){throw Error(`${Ji} is not valid JSON. The lock file is machine-owned; restore it from git (git checkout -- .github/tailor.lock) and re-run setup.`,{cause:e})}if(typeof n.version!=`number`)throw Error(`${Ji} has no valid 'version' field. The lock file is machine-owned; restore it from git (git checkout -- .github/tailor.lock) and re-run setup.`);if(n.version>1)throw Error(`${Ji} was written by a newer SDK (lock version ${String(n.version)}). Update @tailor-platform/sdk to continue (e.g. pnpm update @tailor-platform/sdk).`);if(!Array.isArray(n.targets))throw Error(`${Ji} has no valid 'targets' array. The lock file is machine-owned; restore it from git (git checkout -- .github/tailor.lock) and re-run setup.`);return n}function writeLock(e,t){assertSafeLockPath(e);let n=lockPath(e);X.mkdirSync(W.dirname(n),{recursive:!0}),X.writeFileSync(n,`${JSON.stringify(t,null,2)}\n`,`utf-8`)}function findTarget(e,t,n){return e?.targets.find(e=>e.kind===t&&e.workspaceName===n)}var Yi=`# __HEADER__
92
- name: __WORKSPACE_NAME__
93
- description: >-
94
- Deploy __WORKSPACE_NAME__ to Tailor Platform.
95
- Checkout and dependency installation are expected to be handled by the caller.
96
-
97
- inputs:
98
- workspace-id:
99
- description: Tailor Platform workspace id
100
- required: true
101
- name:
102
- description: Workspace name (used in Slack notifications)
103
- required: true
104
- working-directory:
105
- description: App directory relative to the repository root
106
- required: false
107
- default: "."
108
- config:
109
- description: SDK config path, or comma-separated config paths for multi-config deploys
110
- required: false
111
- default: "tailor.config.ts"
112
- deploy:
113
- description: Whether to run the Tailor deploy step after build steps
114
- required: false
115
- default: "true"
116
- build-site:
117
- description: Whether to run the static website build slot when present
118
- required: false
119
- default: "true"
120
- platform-client-id:
121
- description: Machine-user client id
122
- required: true
123
- platform-client-secret:
124
- description: Machine-user client secret
125
- required: true
126
- slack-token:
127
- description: Slack bot token
128
- required: false
129
- slack-channel-id:
130
- description: Slack channel id
131
- required: false
132
- user-mapping:
133
- description: JSON string mapping GitHub usernames to Slack user IDs
134
- required: false
135
- package-manager:
136
- description: Package manager used for dependency installation (pnpm, npm, yarn, bun)
137
- required: false
138
- default: pnpm
139
-
140
- outputs:
141
- app-url:
142
- description: Deployed application URL
143
- value: \${{ steps.tailor-apply.outputs.app-url }}
144
-
145
- runs:
146
- using: composite
147
- steps:
148
- # __STATIC_WEBSITE_BUILD_START__
149
- - id: build-site
150
- if: inputs.build-site == 'true'
151
- shell: bash
152
- run: |
153
- # Replace with your static website build command.
154
- # Example: pnpm --filter <package-name> run build:static
155
- # Note: this run: command is user-editable. Custom build commands are preserved across
156
- # reruns and are not treated as drift by setup check. Other edits to this file are flagged
157
- # as drift and will be overwritten if you re-run setup action with --force.
158
- true
159
- # __STATIC_WEBSITE_BUILD_END__
160
- - id: tailor-apply
161
- if: inputs.deploy == 'true'
162
- uses: tailor-platform/actions/deploy@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
163
- env:
164
- TAILOR_PLATFORM_SDK_CONFIG_PATH: \${{ inputs.config }}
165
- with:
166
- workspace-id: \${{ inputs.workspace-id }}
167
- working-directory: \${{ inputs.working-directory }}
168
- package-manager: \${{ inputs.package-manager }}
169
- platform-client-id: \${{ inputs.platform-client-id }}
170
- platform-client-secret: \${{ inputs.platform-client-secret }}
171
- - id: tailor-notify
172
- if: failure() && inputs.slack-token != '' && inputs.slack-channel-id != ''
173
- uses: tailor-platform/actions/notify@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
174
- with:
175
- provider: slack
176
- status: failure
177
- workspace-name: \${{ inputs.name }}
178
- slack-token: \${{ inputs.slack-token }}
179
- slack-channel-id: \${{ inputs.slack-channel-id }}
180
- user-mapping: \${{ inputs.user-mapping }}
181
- `,Xi=`# __HEADER__
182
- name: Tailor (__WORKSPACE_NAME__)
183
-
184
- on:
185
- # __PULL_REQUEST_START__
186
- pull_request:
187
- branches: ["__BRANCH__"]
188
- # __PATHS__
189
- # __PULL_REQUEST_END__
190
- push:
191
- branches: ["__BRANCH__"]
192
- # __PATHS__
193
- workflow_dispatch:
194
- # __DISPATCH_INPUTS_START__
195
- inputs:
196
- dry-run:
197
- description: Preview changes without deploying
198
- type: boolean
199
- default: false
200
- # __DISPATCH_INPUTS_END__
201
-
202
- permissions:
203
- contents: read
204
-
205
- jobs:
206
- # __PLAN_JOB_START__
207
- tailor-plan:
208
- if: >-
209
- github.event_name == 'pull_request' ||
210
- (github.event_name == 'workflow_dispatch' && inputs['dry-run'])
211
- runs-on: ubuntu-latest
212
- timeout-minutes: 30
213
- environment: __ENVIRONMENT__
214
- permissions:
215
- contents: read
216
- pull-requests: write
217
- concurrency:
218
- group: tailor-plan-__WORKSPACE_NAME__-\${{ github.event.pull_request.number || github.run_id }}
219
- cancel-in-progress: true
220
- steps:
221
- - id: tailor-checkout
222
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
223
- - id: tailor-setup
224
- uses: tailor-platform/actions/setup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
225
- with:
226
- package-manager: __PACKAGE_MANAGER__
227
- - id: tailor-install
228
- uses: tailor-platform/actions/install@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
229
- with:
230
- package-manager: __PACKAGE_MANAGER__
231
- - id: tailor-generate-check
232
- uses: tailor-platform/actions/generate-check@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
233
- with:
234
- package-manager: __PACKAGE_MANAGER__
235
- # __WORKING_DIRECTORY__
236
- # __SEED_VALIDATE_START__
237
- - id: tailor-seed-validate
238
- run: __TAILOR_CLI__ seed validate
239
- # __WORKING_DIRECTORY__
240
- # __SEED_VALIDATE_END__
241
- - id: tailor-drift-check
242
- uses: tailor-platform/actions/drift-check@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
243
- with:
244
- package-manager: __PACKAGE_MANAGER__
245
- fail-on-drift: \${{ vars.TAILOR_PLATFORM_FAIL_ON_DRIFT == 'true' }}
246
- # __MIGRATION_DRIFT_CHECK_START__
247
- - id: tailor-migration-drift-check
248
- uses: tailor-platform/actions/migration-drift-check@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
249
- with:
250
- package-manager: __PACKAGE_MANAGER__
251
- # __WORKING_DIRECTORY__
252
- # __MIGRATION_DRIFT_CHECK_END__
253
- - id: tailor-plan
254
- # Fork PRs cannot read secrets; the checks above still run for them.
255
- if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork
256
- uses: tailor-platform/actions/plan@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
257
- with:
258
- workspace-id: \${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}
259
- package-manager: __PACKAGE_MANAGER__
260
- label: __WORKSPACE_NAME__
261
- # __WORKING_DIRECTORY__
262
- platform-client-id: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}
263
- platform-client-secret: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}
264
- github-token: \${{ secrets.GITHUB_TOKEN }}
265
- # __PLAN_JOB_END__
266
- # __ERD_PREVIEW_JOB_START__
267
- tailor-erd-preview-matrix:
268
- if: github.event_name == 'pull_request'
269
- runs-on: ubuntu-latest
270
- timeout-minutes: 5
271
- permissions:
272
- contents: read
273
- outputs:
274
- namespaces: \${{ steps.tailor-erd-preview-matrix.outputs.namespaces }}
275
- base-app-dir: \${{ steps.tailor-erd-preview-matrix.outputs['base-app-dir'] }}
276
- steps:
277
- - id: tailor-checkout
278
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
279
- with:
280
- persist-credentials: false
281
- - id: tailor-checkout-base
282
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
283
- with:
284
- repository: \${{ github.event.pull_request.base.repo.full_name }}
285
- ref: \${{ github.event.pull_request.base.sha }}
286
- path: .tailor-erd-base
287
- persist-credentials: false
288
- - id: tailor-erd-preview-matrix
289
- shell: bash
290
- env:
291
- APP_DIR: "__APP_DIR__"
292
- WORKSPACE_NAME: "__WORKSPACE_NAME__"
293
- run: |
294
- set -euo pipefail
295
- node <<'NODE'
296
- const fs = require("node:fs");
297
-
298
- const appDir = process.env.APP_DIR || ".";
299
- const workspaceName = process.env.WORKSPACE_NAME;
300
- const output = process.env.GITHUB_OUTPUT;
301
- const dirPattern = /^[A-Za-z0-9._/-]+$/;
302
- const namespacePattern = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
303
-
304
- function lockTarget(file) {
305
- try {
306
- const lock = JSON.parse(fs.readFileSync(file, "utf8"));
307
- return lock.targets?.find(
308
- (candidate) =>
309
- candidate.kind === "branch" &&
310
- candidate.workspaceName === workspaceName,
311
- );
312
- } catch (error) {
313
- if (error && error.code === "ENOENT") return undefined;
314
- throw error;
315
- }
316
- }
317
-
318
- function namespacesFromTarget(target, label) {
319
- const namespaces =
320
- target?.inputs?.erdPreview === true && Array.isArray(target.inputs?.erdNamespaces)
321
- ? target.inputs.erdNamespaces
322
- : [];
323
- for (const namespace of namespaces) {
324
- if (typeof namespace !== "string" || !namespacePattern.test(namespace)) {
325
- throw new Error(\`Invalid ERD namespace in \${label}: \${String(namespace)}\`);
326
- }
327
- }
328
- return namespaces;
329
- }
330
-
331
- function normalizeDir(value, label) {
332
- const raw = typeof value === "string" && value.length > 0 ? value : appDir;
333
- const normalized =
334
- raw.replaceAll("\\\\", "/").replace(/\\/{2,}/g, "/").replace(/^\\.\\//, "").replace(/\\/$/, "") ||
335
- ".";
336
- if (
337
- !dirPattern.test(normalized) ||
338
- normalized.startsWith("/") ||
339
- normalized.split("/").includes("..")
340
- ) {
341
- throw new Error(\`Invalid ERD app dir in \${label}: \${raw}\`);
342
- }
343
- return normalized;
344
- }
345
-
346
- const headTarget = lockTarget(".github/tailor.lock");
347
- const baseTarget = lockTarget(".tailor-erd-base/.github/tailor.lock");
348
- const baseAppDir = normalizeDir(baseTarget?.inputs?.dir, "base setup lock");
349
- const namespaces = [
350
- ...new Set([
351
- ...namespacesFromTarget(headTarget, "head setup lock"),
352
- ...namespacesFromTarget(baseTarget, "base setup lock"),
353
- ]),
354
- ].sort((a, b) => a.localeCompare(b));
355
-
356
- if (namespaces.length === 0) {
357
- console.error("No ERD preview namespaces found in the head or base setup lock.");
358
- process.exit(1);
359
- }
360
-
361
- fs.appendFileSync(output, \`namespaces=\${JSON.stringify(namespaces)}\\n\`);
362
- fs.appendFileSync(output, \`base-app-dir=\${baseAppDir}\\n\`);
363
- NODE
364
-
365
- tailor-erd-preview:
366
- needs: tailor-erd-preview-matrix
367
- if: github.event_name == 'pull_request'
368
- runs-on: ubuntu-latest
369
- timeout-minutes: 15
370
- permissions:
371
- contents: read
372
- strategy:
373
- fail-fast: false
374
- matrix:
375
- namespace: \${{ fromJSON(needs.tailor-erd-preview-matrix.outputs.namespaces) }}
376
- steps:
377
- - id: tailor-checkout
378
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
379
- with:
380
- persist-credentials: false
381
- - id: tailor-setup
382
- uses: tailor-platform/actions/setup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
383
- with:
384
- package-manager: __PACKAGE_MANAGER__
385
- - id: tailor-checkout-base
386
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
387
- with:
388
- repository: \${{ github.event.pull_request.base.repo.full_name }}
389
- ref: \${{ github.event.pull_request.base.sha }}
390
- path: .tailor-erd-base
391
- persist-credentials: false
392
- - id: tailor-detect-base-package-manager
393
- shell: bash
394
- run: |
395
- set -euo pipefail
396
- cd .tailor-erd-base
397
- base_package_manager="$(
398
- if [ -f pnpm-lock.yaml ]; then
399
- echo pnpm
400
- elif [ -f yarn.lock ]; then
401
- echo yarn
402
- elif [ -f bun.lockb ] || [ -f bun.lock ]; then
403
- echo bun
404
- elif [ -f package-lock.json ]; then
405
- echo npm
406
- else
407
- echo "__PACKAGE_MANAGER__"
408
- fi
409
- )"
410
- echo "package-manager=$base_package_manager" >> "$GITHUB_OUTPUT"
411
- if [ "$base_package_manager" = "pnpm" ]; then
412
- base_pnpm_version="$(node <<'NODE'
413
- const fs = require("node:fs");
414
-
415
- const fallback = "10";
416
-
417
- function readManifest(file) {
418
- try {
419
- return JSON.parse(fs.readFileSync(file, "utf8"));
420
- } catch {
421
- return {};
422
- }
423
- }
424
-
425
- function pnpmVersion(manifest) {
426
- const packageManager = manifest.packageManager;
427
- if (typeof packageManager === "string" && packageManager.startsWith("pnpm@")) {
428
- return packageManager.slice("pnpm@".length).split("+")[0];
429
- }
430
-
431
- const devPackageManager = manifest.devEngines?.packageManager;
432
- if (devPackageManager?.name === "pnpm" && devPackageManager.version) {
433
- return devPackageManager.version;
434
- }
435
-
436
- return undefined;
437
- }
438
-
439
- process.stdout.write(
440
- pnpmVersion(readManifest("package.json")) ?? fallback,
441
- );
442
- NODE
443
- )"
444
- echo "pnpm-version=$base_pnpm_version" >> "$GITHUB_OUTPUT"
445
- fi
446
- - id: tailor-setup-base-pnpm
447
- if: steps.tailor-detect-base-package-manager.outputs['package-manager'] == 'pnpm'
448
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
449
- with:
450
- version: \${{ steps.tailor-detect-base-package-manager.outputs['pnpm-version'] }}
451
- package_json_file: .tailor-erd-base/package.json
452
- run_install: false
453
- - id: tailor-setup-base-node
454
- if: steps.tailor-detect-base-package-manager.outputs['package-manager'] != 'bun'
455
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
456
- with:
457
- node-version-file: .tailor-erd-base/package.json
458
- - id: tailor-setup-base-yarn
459
- if: steps.tailor-detect-base-package-manager.outputs['package-manager'] == 'yarn'
460
- shell: bash
461
- working-directory: .tailor-erd-base
462
- run: |
463
- set -euo pipefail
464
- corepack enable
465
- - id: tailor-setup-base-bun
466
- if: steps.tailor-detect-base-package-manager.outputs['package-manager'] == 'bun'
467
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
468
- - id: tailor-install-base
469
- shell: bash
470
- working-directory: .tailor-erd-base
471
- env:
472
- BASE_PACKAGE_MANAGER: \${{ steps.tailor-detect-base-package-manager.outputs['package-manager'] }}
473
- run: |
474
- set -euo pipefail
475
- case "$BASE_PACKAGE_MANAGER" in
476
- pnpm) pnpm install --frozen-lockfile ;;
477
- npm) npm ci ;;
478
- yarn)
479
- if grep -q '^__metadata:' yarn.lock; then
480
- yarn install --immutable
481
- else
482
- yarn install --frozen-lockfile
483
- fi
484
- ;;
485
- bun) bun install --frozen-lockfile ;;
486
- *)
487
- echo "::error::Unsupported base package-manager '$BASE_PACKAGE_MANAGER' (expected pnpm, npm, yarn, or bun)"
488
- exit 1
489
- ;;
490
- esac
491
- - id: tailor-restore-head-setup
492
- uses: tailor-platform/actions/setup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
493
- with:
494
- package-manager: __PACKAGE_MANAGER__
495
- - id: tailor-build-erd-preview
496
- shell: bash
497
- env:
498
- APP_DIR: "__APP_DIR__"
499
- BASE_APP_DIR: \${{ needs.tailor-erd-preview-matrix.outputs['base-app-dir'] }}
500
- BASE_PACKAGE_MANAGER: \${{ steps.tailor-detect-base-package-manager.outputs['package-manager'] }}
501
- NAMESPACE: \${{ matrix.namespace }}
502
- run: |
503
- set -euo pipefail
504
-
505
- run_tailor_cli() {
506
- case "__PACKAGE_MANAGER__" in
507
- pnpm) pnpm exec tailor "$@" ;;
508
- npm) npx @tailor-platform/sdk "$@" ;;
509
- yarn) yarn tailor "$@" ;;
510
- bun) bun run tailor "$@" ;;
511
- *)
512
- echo "::error::Unsupported package-manager '__PACKAGE_MANAGER__' (expected pnpm, npm, yarn, or bun)"
513
- exit 1
514
- ;;
515
- esac
516
- }
517
-
518
- run_head_node() {
519
- case "__PACKAGE_MANAGER__" in
520
- pnpm) pnpm exec node "$@" ;;
521
- npm) node "$@" ;;
522
- yarn) yarn node "$@" ;;
523
- bun) node "$@" ;;
524
- *)
525
- echo "::error::Unsupported package-manager '__PACKAGE_MANAGER__' (expected pnpm, npm, yarn, or bun)"
526
- exit 1
527
- ;;
528
- esac
529
- }
530
-
531
- tailor_cli_bin="$(
532
- run_head_node - <<'NODE'
533
- const path = require("node:path");
534
- const { createRequire } = require("node:module");
535
- const appDir = process.env.APP_DIR || ".";
536
- const githubWorkspace = process.env.GITHUB_WORKSPACE;
537
- if (!githubWorkspace) {
538
- throw new Error("GITHUB_WORKSPACE is required.");
539
- }
540
-
541
- let lastError;
542
- for (const manifestPath of [
543
- path.join(githubWorkspace, appDir, "package.json"),
544
- path.join(githubWorkspace, "package.json"),
545
- ]) {
546
- try {
547
- const requireFromManifest = createRequire(manifestPath);
548
- process.stdout.write(
549
- path.join(
550
- path.dirname(requireFromManifest.resolve("@tailor-platform/sdk/cli")),
551
- "index.mjs",
552
- ),
553
- );
554
- process.exit(0);
555
- } catch (error) {
556
- lastError = error;
557
- }
558
- }
559
- throw lastError || new Error("Failed to resolve @tailor-platform/sdk/cli.");
560
- NODE
561
- )"
562
-
563
- run_head_tailor_cli_bin() {
564
- local command_cwd="$1"
565
- shift
566
-
567
- run_head_cli_env() {
568
- env TAILOR_CLI_BIN="$tailor_cli_bin" TAILOR_CLI_CWD="$command_cwd" "$@"
569
- }
570
-
571
- (
572
- cd "$GITHUB_WORKSPACE" || exit 1
573
- case "__PACKAGE_MANAGER__" in
574
- pnpm) run_head_cli_env pnpm exec node "$head_cli_runner" "$@" ;;
575
- npm) run_head_cli_env node "$head_cli_runner" "$@" ;;
576
- yarn) run_head_cli_env yarn node "$head_cli_runner" "$@" ;;
577
- bun) run_head_cli_env bun "$head_cli_runner" "$@" ;;
578
- *)
579
- echo "::error::Unsupported package-manager '__PACKAGE_MANAGER__' (expected pnpm, npm, yarn, or bun)"
580
- exit 1
581
- ;;
582
- esac
583
- )
584
- }
585
-
586
- run_base_tailor_cli_bin() {
587
- local command_cwd="$1"
588
- shift
589
-
590
- run_head_cli_env() {
591
- env TAILOR_CLI_BIN="$tailor_cli_bin" TAILOR_CLI_CWD="$command_cwd" "$@"
592
- }
593
-
594
- (
595
- cd "$command_cwd" || exit 1
596
- case "$BASE_PACKAGE_MANAGER" in
597
- pnpm) run_head_cli_env pnpm exec node "$head_cli_runner" "$@" ;;
598
- npm) run_head_cli_env node "$head_cli_runner" "$@" ;;
599
- yarn) run_head_cli_env yarn node "$head_cli_runner" "$@" ;;
600
- bun) run_head_cli_env bun "$head_cli_runner" "$@" ;;
601
- *)
602
- echo "::error::Unsupported base package-manager '$BASE_PACKAGE_MANAGER' (expected pnpm, npm, yarn, or bun)"
603
- exit 1
604
- ;;
605
- esac
606
- )
607
- }
608
-
609
- head_output="$RUNNER_TEMP/tailor-erd/head"
610
- base_output="$RUNNER_TEMP/tailor-erd/base"
611
- preview_output="$RUNNER_TEMP/tailor-erd/preview"
612
- dts_output="$RUNNER_TEMP/tailor-erd/dts"
613
- head_cli_runner="$RUNNER_TEMP/tailor-erd/run-head-cli.mjs"
614
- head_log="$RUNNER_TEMP/tailor-erd/head-$NAMESPACE.log"
615
- base_log="$RUNNER_TEMP/tailor-erd/base-$NAMESPACE.log"
616
- rm -rf "$head_output" "$base_output" "$preview_output" "$dts_output"
617
- mkdir -p "$head_output" "$base_output" "$preview_output" "$dts_output"
618
- cat > "$head_cli_runner" <<'NODE'
619
- import { pathToFileURL } from "node:url";
620
-
621
- const cliBin = process.env.TAILOR_CLI_BIN;
622
- const commandCwd = process.env.TAILOR_CLI_CWD;
623
- if (!cliBin || !commandCwd) {
624
- throw new Error("TAILOR_CLI_BIN and TAILOR_CLI_CWD are required.");
625
- }
626
-
627
- process.chdir(commandCwd);
628
- process.argv = [process.argv[0], cliBin, ...process.argv.slice(2)];
629
- await import(pathToFileURL(cliBin).href);
630
- NODE
631
-
632
- head_config="$GITHUB_WORKSPACE/$APP_DIR/tailor.config.ts"
633
- base_config="$GITHUB_WORKSPACE/.tailor-erd-base/$BASE_APP_DIR/tailor.config.ts"
634
- head_html="$head_output/$NAMESPACE/dist/index.html"
635
- base_html="$base_output/$NAMESPACE/dist/index.html"
636
- preview_html="$preview_output/$NAMESPACE-viewer.html"
637
-
638
- head_missing="false"
639
- if [ ! -f "$head_config" ]; then
640
- echo "Head ERD config not found; rendering base objects as removed."
641
- head_missing="true"
642
- elif ! (
643
- cd "$GITHUB_WORKSPACE/$APP_DIR" || exit 1
644
- TAILOR_PLATFORM_SDK_DTS_PATH="$dts_output/head-$NAMESPACE.d.ts" \\
645
- run_tailor_cli tailordb erd export --config "$head_config" --namespace "$NAMESPACE" --output "$head_output"
646
- ) >"$head_log" 2>&1; then
647
- if grep -q 'not found in local config.db' "$head_log"; then
648
- cat "$head_log"
649
- echo "Head ERD namespace '$NAMESPACE' not found; rendering base objects as removed."
650
- head_missing="true"
651
- else
652
- cat "$head_log"
653
- exit 1
654
- fi
655
- elif [ -s "$head_log" ]; then
656
- cat "$head_log"
657
- fi
658
-
659
- base_missing="false"
660
- if [ ! -f "$base_config" ]; then
661
- echo "Base ERD config not found; rendering current objects as added."
662
- base_missing="true"
663
- elif ! (
664
- TAILOR_PLATFORM_SDK_DTS_PATH="$dts_output/base-$NAMESPACE.d.ts" \\
665
- run_base_tailor_cli_bin "$GITHUB_WORKSPACE/.tailor-erd-base/$BASE_APP_DIR" tailordb erd export --config "$base_config" --namespace "$NAMESPACE" --output "$base_output"
666
- ) >"$base_log" 2>&1; then
667
- if grep -q 'not found in local config.db' "$base_log"; then
668
- cat "$base_log"
669
- echo "Base ERD namespace '$NAMESPACE' not found; rendering current objects as added."
670
- base_missing="true"
671
- else
672
- cat "$base_log"
673
- exit 1
674
- fi
675
- elif [ -s "$base_log" ]; then
676
- cat "$base_log"
677
- fi
678
-
679
- if [ "$head_missing" = "true" ] && [ "$base_missing" = "true" ]; then
680
- echo "::error::ERD namespace '$NAMESPACE' was not found in head or base."
681
- exit 1
682
- fi
683
- if [ "$head_missing" = "false" ] && [ ! -f "$head_html" ]; then
684
- echo "::error::Head ERD viewer was not generated at $head_html"
685
- exit 1
686
- fi
687
- if [ "$base_missing" = "false" ] && [ ! -f "$base_html" ]; then
688
- echo "::error::Base ERD viewer was not generated at $base_html"
689
- exit 1
690
- fi
691
-
692
- diff_args=(--namespace "$NAMESPACE" --output "$preview_html")
693
- if [ "$head_missing" = "false" ]; then
694
- diff_args+=(--head-html "$head_html")
695
- fi
696
- if [ "$base_missing" = "false" ]; then
697
- diff_args+=(--base-html "$base_html")
698
- fi
699
- run_head_tailor_cli_bin "$GITHUB_WORKSPACE" tailordb erd diff "\${diff_args[@]}"
700
- - id: tailor-upload-erd-viewer
701
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
702
- with:
703
- name: \${{ matrix.namespace }}-viewer.html
704
- path: \${{ runner.temp }}/tailor-erd/preview/\${{ matrix.namespace }}-viewer.html
705
- if-no-files-found: error
706
- archive: false
707
- retention-days: 7
708
-
709
- # __ERD_PREVIEW_JOB_END__
710
- # __ERD_PREVIEW_COMMENT_JOB_START__
711
- tailor-erd-preview-comment:
712
- needs: tailor-erd-preview
713
- if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
714
- runs-on: ubuntu-latest
715
- timeout-minutes: 5
716
- permissions:
717
- actions: read
718
- pull-requests: write
719
- steps:
720
- - id: tailor-comment-erd-preview
721
- env:
722
- GH_TOKEN: \${{ github.token }}
723
- REPO: \${{ github.repository }}
724
- RUN_ID: \${{ github.run_id }}
725
- SERVER: \${{ github.server_url }}
726
- PR_NUMBER: \${{ github.event.pull_request.number }}
727
- BASE_REF: \${{ github.event.pull_request.base.ref }}
728
- HEAD_SHA: \${{ github.event.pull_request.head.sha }}
729
- MARKER: "<!-- tailor-erd-preview: __WORKSPACE_NAME__ -->"
730
- run: |
731
- set -euo pipefail
732
-
733
- current_head=$(gh api "repos/$REPO/pulls/$PR_NUMBER" --jq '.head.sha')
734
- if [ "$current_head" != "$HEAD_SHA" ]; then
735
- echo "Skipping stale ERD preview comment for $HEAD_SHA; current head is $current_head."
736
- exit 0
737
- fi
738
-
739
- body="$MARKER"$'\\n'"### TailorDB ERD preview (__WORKSPACE_NAME__)"$'\\n\\n'
740
- body+="Self-contained ERD viewer HTML artifacts for this pull request. Each viewer can switch between the current schema and a diff against base branch \\\`$BASE_REF\\\`."$'\\n'
741
-
742
- while IFS=$'\\t' read -r name id; do
743
- [ -z "$name" ] && continue
744
- if [[ "$name" != *-viewer.html ]]; then
745
- continue
746
- fi
747
- ns=\${name%-viewer.html}
748
- label="$ns viewer"
749
- body+=$'\\n'"- **$label**: [$name]($SERVER/$REPO/actions/runs/$RUN_ID/artifacts/$id)"
750
- done < <(gh api "repos/$REPO/actions/runs/$RUN_ID/artifacts" --paginate \\
751
- --jq '.artifacts[] | select(.name | endswith("-viewer.html")) | [.name, (.id|tostring)] | @tsv' | sort)
752
-
753
- existing=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" --paginate \\
754
- --jq 'map(select(.body | contains(env.MARKER))) | .[0].id // empty')
755
- if [ -n "$existing" ]; then
756
- gh api --method PATCH "repos/$REPO/issues/comments/$existing" -f body="$body" >/dev/null
757
- else
758
- gh api --method POST "repos/$REPO/issues/$PR_NUMBER/comments" -f body="$body" >/dev/null
759
- fi
760
-
761
- # __ERD_PREVIEW_COMMENT_JOB_END__
762
- tailor-deploy:
763
- # __DEPLOY_IF__
764
- runs-on: ubuntu-latest
765
- timeout-minutes: 30
766
- permissions:
767
- contents: read
768
- environment: __ENVIRONMENT__
769
- concurrency:
770
- group: tailor-deploy-__WORKSPACE_NAME__
771
- cancel-in-progress: false
772
- steps:
773
- - id: tailor-checkout
774
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
775
- - id: tailor-setup
776
- uses: tailor-platform/actions/setup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
777
- with:
778
- package-manager: __PACKAGE_MANAGER__
779
- - id: tailor-install
780
- uses: tailor-platform/actions/install@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
781
- with:
782
- package-manager: __PACKAGE_MANAGER__
783
- - id: tailor-apply
784
- uses: tailor-platform/actions/deploy@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
785
- with:
786
- workspace-id: \${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}
787
- package-manager: __PACKAGE_MANAGER__
788
- # __WORKING_DIRECTORY__
789
- platform-client-id: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}
790
- platform-client-secret: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}
791
- # __SEED_DATA_START__
792
- - id: seed-data
793
- if: false
794
- shell: bash
795
- # __WORKING_DIRECTORY__
796
- run: |
797
- # Uncomment and implement to seed data on deploy.
798
- # Run after apply so the schema is ready.
799
- # Example: node scripts/seed.mjs
800
- true
801
- # __SEED_DATA_END__
802
- - id: slack-prereq
803
- if: always()
804
- shell: bash
805
- env:
806
- SLACK_TOKEN: \${{ secrets.TAILOR_SLACK_BOT_TOKEN }}
807
- SLACK_CHANNEL_ID: \${{ vars.TAILOR_SLACK_CHANNEL_ID }}
808
- run: |
809
- if [[ -n "$SLACK_TOKEN" && -n "$SLACK_CHANNEL_ID" ]]; then
810
- echo "ready=true" >> "$GITHUB_OUTPUT"
811
- fi
812
- - id: tailor-notify
813
- if: always() && steps.slack-prereq.outputs.ready == 'true'
814
- uses: tailor-platform/actions/notify@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
815
- with:
816
- provider: slack
817
- status: \${{ job.status }}
818
- workspace-name: __WORKSPACE_NAME__
819
- slack-token: \${{ secrets.TAILOR_SLACK_BOT_TOKEN }}
820
- slack-channel-id: \${{ vars.TAILOR_SLACK_CHANNEL_ID }}
821
- # user-mapping: \${{ vars.TAILOR_SLACK_USER_MAPPING }}
822
- `,Zi=`# __HEADER__
823
- name: Tailor Coordinator (__WORKSPACE_NAME__)
824
-
825
- on:
826
- # __PULL_REQUEST_START__
827
- pull_request:
828
- branches: ["__BRANCH__"]
829
- # __PULL_REQUEST_END__
830
- push:
831
- # __PUSH_BRANCHES_START__
832
- branches: ["__BRANCH__"]
833
- # __PUSH_BRANCHES_END__
834
- # __PUSH_TAGS_START__
835
- tags: [__TAG_PATTERN__]
836
- # __PUSH_TAGS_END__
837
- workflow_dispatch:
838
- inputs:
839
- dry-run:
840
- description: Preview changes without deploying
841
- type: boolean
842
- default: false
843
-
844
- permissions:
845
- contents: read
846
-
847
- jobs:
848
- # __TAG_GUARD_JOB_START__
849
- tailor-tag-guard:
850
- runs-on: ubuntu-latest
851
- timeout-minutes: 5
852
- permissions:
853
- contents: read
854
- outputs:
855
- on-branch: \${{ steps.tailor-tag-guard.outputs.on-branch }}
856
- steps:
857
- - id: tailor-checkout
858
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
859
- with:
860
- fetch-depth: 0
861
- - id: tailor-tag-guard
862
- uses: tailor-platform/actions/tag-guard@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
863
- with:
864
- target-branch: __BRANCH__
865
- # __TAG_GUARD_JOB_END__
866
-
867
- tailor-plan:
868
- # __PLAN_NEEDS__
869
- # __PLAN_IF__
870
- runs-on: ubuntu-latest
871
- timeout-minutes: 60
872
- environment: __ENVIRONMENT__
873
- permissions:
874
- contents: read
875
- pull-requests: write
876
- concurrency:
877
- group: tailor-plan-__WORKSPACE_NAME__-\${{ github.event.pull_request.number || github.run_id }}
878
- cancel-in-progress: true
879
- steps:
880
- - id: tailor-checkout
881
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
882
- - id: tailor-setup
883
- uses: ./.github/actions/tailor-setup
884
- # __PER_APP_PLAN_STEPS__
885
-
886
- tailor-deploy:
887
- # __DEPLOY_NEEDS__
888
- # __DEPLOY_IF__
889
- # __DEPLOY_ENVIRONMENT__
890
- runs-on: ubuntu-latest
891
- timeout-minutes: 60
892
- permissions:
893
- contents: read
894
- concurrency:
895
- group: tailor-deploy-__WORKSPACE_NAME__
896
- cancel-in-progress: false
897
- steps:
898
- - id: tailor-checkout
899
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
900
- - id: tailor-setup
901
- uses: ./.github/actions/tailor-setup
902
- # __PER_APP_DEPLOY_STEPS__
903
- `,Qi=`# __HEADER__
904
- name: Tailor Preview (__WORKSPACE_NAME__)
905
-
906
- on:
907
- pull_request:
908
- branches: ["__BRANCH__"]
909
- # __PR_TYPES__
910
- # To deploy only for PRs that carry the \`tailor:preview\` label instead of all PRs,
911
- # re-run: tailor setup preview --require-preview-label
912
- # __PATHS__
913
-
914
- permissions:
915
- contents: read
916
- pull-requests: write
917
-
918
- jobs:
919
- tailor-preview-deploy:
920
- # __DEPLOY_IF__
921
- runs-on: ubuntu-latest
922
- timeout-minutes: 30
923
- environment: __ENVIRONMENT__
924
- permissions:
925
- contents: read
926
- pull-requests: write
927
- concurrency:
928
- group: tailor-preview-__WORKSPACE_NAME__-\${{ github.event.pull_request.number }}
929
- cancel-in-progress: true
930
- steps:
931
- - id: tailor-checkout
932
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
933
- - id: tailor-setup
934
- uses: tailor-platform/actions/setup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
935
- with:
936
- package-manager: __PACKAGE_MANAGER__
937
- - id: tailor-install
938
- uses: tailor-platform/actions/install@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
939
- with:
940
- package-manager: __PACKAGE_MANAGER__
941
- - id: tailor-generate-check
942
- uses: tailor-platform/actions/generate-check@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
943
- with:
944
- package-manager: __PACKAGE_MANAGER__
945
- # __WORKING_DIRECTORY__
946
- - id: tailor-drift-check
947
- uses: tailor-platform/actions/drift-check@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
948
- with:
949
- package-manager: __PACKAGE_MANAGER__
950
- fail-on-drift: \${{ vars.TAILOR_PLATFORM_FAIL_ON_DRIFT == 'true' }}
951
- - id: tailor-preview-deploy
952
- uses: tailor-platform/actions/preview-deploy@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
953
- with:
954
- workspace-name-prefix: __WORKSPACE_NAME__
955
- region: "__REGION__"
956
- organization-id: \${{ vars.TAILOR_PLATFORM_ORGANIZATION_ID }}
957
- folder-id: \${{ vars.TAILOR_PLATFORM_FOLDER_ID }}
958
- package-manager: __PACKAGE_MANAGER__
959
- # __WORKING_DIRECTORY__
960
- platform-client-id: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}
961
- platform-client-secret: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}
962
- github-token: \${{ secrets.GITHUB_TOKEN }}
963
- - id: tailor-preview-comment
964
- if: always()
965
- uses: tailor-platform/actions/preview-comment@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
966
- with:
967
- workspace-id: \${{ steps.tailor-preview-deploy.outputs.workspace-id }}
968
- workspace-name: \${{ steps.tailor-preview-deploy.outputs.workspace-name }}
969
- status: \${{ job.status == 'success' && 'success' || 'failure' }}
970
- app-url: \${{ steps.tailor-preview-deploy.outputs.app-url }}
971
- github-token: \${{ secrets.GITHUB_TOKEN }}
972
-
973
- tailor-preview-cleanup:
974
- # __CLEANUP_IF__
975
- runs-on: ubuntu-latest
976
- timeout-minutes: 15
977
- environment: __ENVIRONMENT__
978
- permissions:
979
- contents: read
980
- pull-requests: write
981
- steps:
982
- - id: tailor-checkout
983
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
984
- - id: tailor-setup
985
- uses: tailor-platform/actions/setup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
986
- with:
987
- package-manager: __PACKAGE_MANAGER__
988
- - id: tailor-install
989
- uses: tailor-platform/actions/install@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
990
- with:
991
- package-manager: __PACKAGE_MANAGER__
992
- - id: tailor-preview-cleanup
993
- uses: tailor-platform/actions/preview-cleanup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
994
- with:
995
- workspace-name-prefix: __WORKSPACE_NAME__
996
- package-manager: __PACKAGE_MANAGER__
997
- # __WORKING_DIRECTORY__
998
- platform-client-id: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}
999
- platform-client-secret: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}
1000
- github-token: \${{ secrets.GITHUB_TOKEN }}
1001
- `,$i=`# __HEADER__
1002
- name: Tailor (__WORKSPACE_NAME__)
1003
-
1004
- on:
1005
- push:
1006
- tags: ["__TAG_PATTERN__"]
1007
- workflow_dispatch:
1008
- inputs:
1009
- dry-run:
1010
- description: Preview changes without deploying
1011
- type: boolean
1012
- default: false
1013
-
1014
- permissions:
1015
- contents: read
1016
-
1017
- jobs:
1018
- # __TAG_GUARD_JOB_START__
1019
- tailor-tag-guard:
1020
- runs-on: ubuntu-latest
1021
- timeout-minutes: 10
1022
- permissions:
1023
- contents: read
1024
- outputs:
1025
- on-branch: \${{ steps.tailor-tag-guard.outputs.on-branch }}
1026
- steps:
1027
- - id: tailor-checkout
1028
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
1029
- with:
1030
- fetch-depth: 0
1031
- - id: tailor-tag-guard
1032
- uses: tailor-platform/actions/tag-guard@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1033
- with:
1034
- target-branch: "__BRANCH__"
1035
- # __TAG_GUARD_JOB_END__
1036
- tailor-plan:
1037
- # __PLAN_NEEDS__
1038
- # __PLAN_IF__
1039
- runs-on: ubuntu-latest
1040
- timeout-minutes: 30
1041
- environment: __ENVIRONMENT__
1042
- permissions:
1043
- contents: read
1044
- steps:
1045
- - id: tailor-checkout
1046
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
1047
- - id: tailor-setup
1048
- uses: tailor-platform/actions/setup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1049
- with:
1050
- package-manager: __PACKAGE_MANAGER__
1051
- - id: tailor-install
1052
- uses: tailor-platform/actions/install@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1053
- with:
1054
- package-manager: __PACKAGE_MANAGER__
1055
- - id: tailor-generate-check
1056
- uses: tailor-platform/actions/generate-check@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1057
- with:
1058
- package-manager: __PACKAGE_MANAGER__
1059
- # __WORKING_DIRECTORY__
1060
- # __SEED_VALIDATE_START__
1061
- - id: tailor-seed-validate
1062
- run: __TAILOR_CLI__ seed validate
1063
- # __WORKING_DIRECTORY__
1064
- # __SEED_VALIDATE_END__
1065
- - id: tailor-drift-check
1066
- uses: tailor-platform/actions/drift-check@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1067
- with:
1068
- package-manager: __PACKAGE_MANAGER__
1069
- fail-on-drift: \${{ vars.TAILOR_PLATFORM_FAIL_ON_DRIFT == 'true' }}
1070
- # __MIGRATION_DRIFT_CHECK_START__
1071
- - id: tailor-migration-drift-check
1072
- uses: tailor-platform/actions/migration-drift-check@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1073
- with:
1074
- package-manager: __PACKAGE_MANAGER__
1075
- # __WORKING_DIRECTORY__
1076
- # __MIGRATION_DRIFT_CHECK_END__
1077
- - id: tailor-plan
1078
- uses: tailor-platform/actions/plan@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1079
- with:
1080
- workspace-id: \${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}
1081
- package-manager: __PACKAGE_MANAGER__
1082
- label: __WORKSPACE_NAME__
1083
- # __WORKING_DIRECTORY__
1084
- platform-client-id: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}
1085
- platform-client-secret: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}
1086
-
1087
- tailor-deploy:
1088
- needs: tailor-plan
1089
- if: \${{ !(github.event_name == 'workflow_dispatch' && inputs['dry-run']) }}
1090
- environment: __ENVIRONMENT__
1091
- runs-on: ubuntu-latest
1092
- timeout-minutes: 30
1093
- permissions:
1094
- contents: read
1095
- concurrency:
1096
- group: tailor-deploy-__WORKSPACE_NAME__
1097
- cancel-in-progress: false
1098
- steps:
1099
- - id: tailor-checkout
1100
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
1101
- - id: tailor-setup
1102
- uses: tailor-platform/actions/setup@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1103
- with:
1104
- package-manager: __PACKAGE_MANAGER__
1105
- - id: tailor-install
1106
- uses: tailor-platform/actions/install@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1107
- with:
1108
- package-manager: __PACKAGE_MANAGER__
1109
- - id: tailor-apply
1110
- uses: tailor-platform/actions/deploy@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1111
- with:
1112
- workspace-id: \${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}
1113
- package-manager: __PACKAGE_MANAGER__
1114
- # __WORKING_DIRECTORY__
1115
- platform-client-id: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}
1116
- platform-client-secret: \${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}
1117
- # __SEED_DATA_START__
1118
- - id: seed-data
1119
- if: false
1120
- shell: bash
1121
- # __WORKING_DIRECTORY__
1122
- run: |
1123
- # Uncomment and implement to seed data on deploy.
1124
- # Run after apply so the schema is ready.
1125
- # Example: node scripts/seed.mjs
1126
- true
1127
- # __SEED_DATA_END__
1128
- - id: slack-prereq
1129
- if: always()
1130
- shell: bash
1131
- env:
1132
- SLACK_TOKEN: \${{ secrets.TAILOR_SLACK_BOT_TOKEN }}
1133
- SLACK_CHANNEL_ID: \${{ vars.TAILOR_SLACK_CHANNEL_ID }}
1134
- run: |
1135
- if [[ -n "$SLACK_TOKEN" && -n "$SLACK_CHANNEL_ID" ]]; then
1136
- echo "ready=true" >> "$GITHUB_OUTPUT"
1137
- fi
1138
- - id: tailor-notify
1139
- if: always() && steps.slack-prereq.outputs.ready == 'true'
1140
- uses: tailor-platform/actions/notify@33ae978702edd2de673419e84b66065e7a364dab # v2.3.0
1141
- with:
1142
- provider: slack
1143
- status: \${{ job.status }}
1144
- workspace-name: __WORKSPACE_NAME__
1145
- slack-token: \${{ secrets.TAILOR_SLACK_BOT_TOKEN }}
1146
- slack-channel-id: \${{ vars.TAILOR_SLACK_CHANNEL_ID }}
1147
- # user-mapping: \${{ vars.TAILOR_SLACK_USER_MAPPING }}
1148
- `;const ea={pnpm:`pnpm exec tailor`,npm:`npx @tailor-platform/sdk`,yarn:`yarn tailor`,bun:`bun run tailor`},ta=`# Generated by \`tailor setup\` — managed by the Tailor SDK.
1149
- #
1150
- # - Jobs and steps whose id starts with \`tailor-\` are managed by the SDK.
1151
- # Do not edit or rename them.
1152
- # - State is tracked in .github/tailor.lock (machine-owned: commit it, never edit it).
1153
- # - Re-running \`tailor setup\` regenerates this file. If you have
1154
- # edited it by hand, regeneration stops and asks for --force (which discards
1155
- # your edits), so prefer keeping customizations in your own jobs/steps and
1156
- # re-running setup after SDK updates.`;function detectPackageManager(e){return X.existsSync(W.join(e,`pnpm-lock.yaml`))?`pnpm`:X.existsSync(W.join(e,`yarn.lock`))?`yarn`:X.existsSync(W.join(e,`bun.lockb`))||X.existsSync(W.join(e,`bun.lock`))?`bun`:(X.existsSync(W.join(e,`package-lock.json`)),`npm`)}function block(e,t,n){return n?e.replace(RegExp(`^ *# __${t}_(?:START|END)__\\n`,`gm`),``):e.replace(RegExp(`^ *# __${t}_START__\\n[\\s\\S]*?^ *# __${t}_END__\\n`,`m`),``)}function line(e,t,n){let r=RegExp(`^([ \\t]*)# __${t}__\\n`,`gm`);return e.replace(r,(e,t)=>n===void 0?``:n.split(`
1157
- `).map(e=>e&&t+e).join(`
1158
- `)+`
1159
- `)}function applyCommon(e,t){let{workingDirectory:n,environment:r,packageManager:i}=t,a=line(e,`HEADER`,ta);return a=line(a,`WORKING_DIRECTORY`,n?`working-directory: ${n}`:void 0),a.replaceAll(`__WORKSPACE_NAME__`,()=>t.workspaceName).replaceAll(`__ENVIRONMENT__`,()=>r).replaceAll(`__PACKAGE_MANAGER__`,()=>i).replaceAll(`__TAILOR_CLI__`,()=>ea[i]).replaceAll(`__APP_DIR__`,()=>n??`.`)}function renderBranchWorkflow(e){let{branch:t}=e,n=e.seedValidate??!1,r=e.migrationDriftCheck??!1,i=e.erdPreview,a=Xi;a=block(a,`PLAN_JOB`,!0),a=block(a,`ERD_PREVIEW_JOB`,i!==null),a=block(a,`ERD_PREVIEW_COMMENT_JOB`,i!==null),a=block(a,`PULL_REQUEST`,!0),a=block(a,`DISPATCH_INPUTS`,!0),a=block(a,`SEED_VALIDATE`,n),a=block(a,`MIGRATION_DRIFT_CHECK`,r),a=block(a,`SEED_DATA`,!1),a=line(a,`DEPLOY_IF`,`if: >-
1160
- github.event_name == 'push' ||
1161
- (github.event_name == 'workflow_dispatch' && !inputs['dry-run'])`),a=line(a,`PATHS`,e.workingDirectory?`paths: ["${e.workingDirectory}/**"]`:void 0),a=applyCommon(a,e).replaceAll(`__BRANCH__`,()=>t);let o=[`tailor-plan`,`tailor-plan/tailor-checkout`,`tailor-plan/tailor-setup`,`tailor-plan/tailor-install`,`tailor-plan/tailor-generate-check`];return n&&o.push(`tailor-plan/tailor-seed-validate`),o.push(`tailor-plan/tailor-drift-check`),r&&o.push(`tailor-plan/tailor-migration-drift-check`),o.push(`tailor-plan/tailor-plan`),i&&o.push(`tailor-erd-preview-matrix`,`tailor-erd-preview-matrix/tailor-checkout`,`tailor-erd-preview-matrix/tailor-checkout-base`,`tailor-erd-preview-matrix/tailor-erd-preview-matrix`,`tailor-erd-preview`,`tailor-erd-preview/tailor-checkout`,`tailor-erd-preview/tailor-setup`,`tailor-erd-preview/tailor-checkout-base`,`tailor-erd-preview/tailor-detect-base-package-manager`,`tailor-erd-preview/tailor-setup-base-pnpm`,`tailor-erd-preview/tailor-setup-base-node`,`tailor-erd-preview/tailor-setup-base-yarn`,`tailor-erd-preview/tailor-setup-base-bun`,`tailor-erd-preview/tailor-install-base`,`tailor-erd-preview/tailor-restore-head-setup`,`tailor-erd-preview/tailor-build-erd-preview`,`tailor-erd-preview/tailor-upload-erd-viewer`,`tailor-erd-preview-comment`,`tailor-erd-preview-comment/tailor-comment-erd-preview`),o.push(`tailor-deploy`,`tailor-deploy/tailor-checkout`,`tailor-deploy/tailor-setup`,`tailor-deploy/tailor-install`,`tailor-deploy/tailor-apply`,`tailor-deploy/tailor-notify`),{content:a,generatedIds:o}}function renderTagWorkflow(e){let{tagPattern:t,branch:n}=e,r=n!==void 0,i=e.seedValidate??!1,a=e.migrationDriftCheck??!1,o=$i;o=block(o,`TAG_GUARD_JOB`,r),o=block(o,`SEED_VALIDATE`,i),o=block(o,`MIGRATION_DRIFT_CHECK`,a),o=block(o,`SEED_DATA`,!1),o=line(o,`PLAN_NEEDS`,r?`needs: tailor-tag-guard`:void 0),o=line(o,`PLAN_IF`,r?`if: >-
1162
- github.event_name == 'workflow_dispatch' ||
1163
- needs.tailor-tag-guard.outputs.on-branch == 'true'`:void 0),o=applyCommon(o,e).replaceAll(`__TAG_PATTERN__`,()=>t),r&&(o=o.replaceAll(`__BRANCH__`,()=>n));let s=[];return r&&s.push(`tailor-tag-guard`,`tailor-tag-guard/tailor-checkout`,`tailor-tag-guard/tailor-tag-guard`),s.push(`tailor-plan`,`tailor-plan/tailor-checkout`,`tailor-plan/tailor-setup`,`tailor-plan/tailor-install`,`tailor-plan/tailor-generate-check`),i&&s.push(`tailor-plan/tailor-seed-validate`),s.push(`tailor-plan/tailor-drift-check`),a&&s.push(`tailor-plan/tailor-migration-drift-check`),s.push(`tailor-plan/tailor-plan`,`tailor-deploy`,`tailor-deploy/tailor-checkout`,`tailor-deploy/tailor-setup`,`tailor-deploy/tailor-install`,`tailor-deploy/tailor-apply`,`tailor-deploy/tailor-notify`),{content:o,generatedIds:s}}function renderPreviewWorkflow(e){let{branch:t}=e,n=e.requirePreviewLabel??!1,r=Qi;return r=line(r,`PATHS`,e.workingDirectory?`paths: ["${e.workingDirectory}/**"]`:void 0),r=line(r,`PR_TYPES`,n?`types: [labeled, synchronize, reopened, closed]`:`types: [opened, synchronize, reopened, closed]`),r=line(r,`DEPLOY_IF`,n?`if: >-
1164
- contains(github.event.pull_request.labels.*.name, 'tailor:preview') &&
1165
- github.event.action != 'closed' &&
1166
- !github.event.pull_request.draft &&
1167
- !github.event.pull_request.head.repo.fork`:`if: >-
1168
- github.event.action != 'closed' &&
1169
- !github.event.pull_request.draft &&
1170
- !github.event.pull_request.head.repo.fork`),r=line(r,`CLEANUP_IF`,`if: >-
1171
- github.event.action == 'closed' &&
1172
- !github.event.pull_request.head.repo.fork`),r=applyCommon(r,e).replaceAll(`__BRANCH__`,()=>t).replaceAll(`__REGION__`,()=>e.region),{content:r,generatedIds:[`tailor-preview-deploy`,`tailor-preview-deploy/tailor-checkout`,`tailor-preview-deploy/tailor-setup`,`tailor-preview-deploy/tailor-install`,`tailor-preview-deploy/tailor-generate-check`,`tailor-preview-deploy/tailor-drift-check`,`tailor-preview-deploy/tailor-preview-deploy`,`tailor-preview-deploy/tailor-preview-comment`,`tailor-preview-cleanup`,`tailor-preview-cleanup/tailor-checkout`,`tailor-preview-cleanup/tailor-setup`,`tailor-preview-cleanup/tailor-install`,`tailor-preview-cleanup/tailor-preview-cleanup`]}}function renderActionWorkflow(e){let t=Yi;return t=line(t,`HEADER`,ta),t=block(t,`STATIC_WEBSITE_BUILD`,e.hasStaticWebsites??!1),t=t.replaceAll(`__WORKSPACE_NAME__`,()=>e.workspaceName),{content:t,generatedIds:[`tailor-apply`,`tailor-notify`]}}const na=`33ae978702edd2de673419e84b66065e7a364dab`,ra=`v2.3.0`;function renderCoordinateWorkflow(e){let{coordinatorName:t,kind:n,actionGroups:r,environment:i,packageManager:a}=e,o=n===`tag`,s=e.branch,c=e.tagPattern??`v*`,l=Zi;l=line(l,`HEADER`,ta),l=block(l,`PULL_REQUEST`,!o),l=block(l,`PUSH_BRANCHES`,!o),l=block(l,`PUSH_TAGS`,o),l=block(l,`TAG_GUARD_JOB`,o&&s!==void 0),o&&s!==void 0?(l=line(l,`PLAN_NEEDS`,`needs: tailor-tag-guard`),l=line(l,`PLAN_IF`,`if: >-
1173
- github.event_name == 'workflow_dispatch' ||
1174
- needs.tailor-tag-guard.outputs.on-branch == 'true'`)):o?(l=line(l,`PLAN_NEEDS`,void 0),l=line(l,`PLAN_IF`,void 0)):(l=line(l,`PLAN_NEEDS`,void 0),l=line(l,`PLAN_IF`,`if: >-
1175
- github.event_name == 'pull_request' ||
1176
- (github.event_name == 'workflow_dispatch' && inputs['dry-run'])`)),o?(l=line(l,`DEPLOY_NEEDS`,`needs: tailor-plan`),l=line(l,`DEPLOY_IF`,"if: ${{ !(github.event_name == 'workflow_dispatch' && inputs['dry-run']) }}"),l=line(l,`DEPLOY_ENVIRONMENT`,`environment: ${i}`)):(l=line(l,`DEPLOY_NEEDS`,void 0),l=line(l,`DEPLOY_IF`,`if: >-
1177
- github.event_name == 'push' ||
1178
- (github.event_name == 'workflow_dispatch' && !inputs['dry-run'])`),l=line(l,`DEPLOY_ENVIRONMENT`,`environment: ${i}`));let u=[`- id: tailor-drift-check`,` uses: tailor-platform/actions/drift-check@${na} # ${ra}`,` with:`,` package-manager: ${a}`," fail-on-drift: ${{ vars.TAILOR_PLATFORM_FAIL_ON_DRIFT == 'true' }}"].join(`
1179
- `),configPath=e=>e.dir===`.`?`tailor.config.ts`:`${e.dir}/tailor.config.ts`,groupConfigPath=e=>e.apps.map(configPath).join(`,`),firstApp=e=>{let[t]=e.apps;if(!t)throw Error(`Coordinate action groups must contain at least one app.`);return t},singleAppPlanStep=(e,n)=>{let r=n.dir===`.`?void 0:n.dir,i=r?`\n working-directory: ${r}`:``;return[`- id: tailor-plan-${e.id}`,` if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork`,` uses: tailor-platform/actions/plan@${na} # ${ra}`,` with:`," workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}",` package-manager: ${a}${i}`,` label: ${t}/${e.id}`," platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}"," platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}"," github-token: ${{ secrets.GITHUB_TOKEN }}"]},multiConfigPlanStep=e=>[`- id: tailor-plan-${e.id}`,` if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork`,` uses: tailor-platform/actions/plan@${na} # ${ra}`,` env:`,` TAILOR_PLATFORM_SDK_CONFIG_PATH: ${groupConfigPath(e)}`,` with:`," workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}",` package-manager: ${a}`,` label: ${t}/${e.id}`," platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}"," platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}"," github-token: ${{ secrets.GITHUB_TOKEN }}"],d=r.flatMap(e=>{let t=e.apps.flatMap(e=>{let t=e.dir===`.`?void 0:e.dir,n=t?`\n working-directory: ${t}`:``;return[`- id: tailor-generate-check-${e.name}`,` uses: tailor-platform/actions/generate-check@${na} # ${ra}`,` with:`,` package-manager: ${a}${n}`]}),n=e.apps.length===1?singleAppPlanStep(e,firstApp(e)):multiConfigPlanStep(e);return[...t,...n]}).join(`
1180
- `);l=line(l,`PER_APP_PLAN_STEPS`,`${u}\n${d}`);let singleAppDeployStep=(e,t)=>[`- id: tailor-deploy-${e.id}`,` uses: ./.github/actions/tailor-${t.name}`,` with:`," workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}",` name: ${t.name}`,` working-directory: ${t.dir}`,` package-manager: ${a}`," platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}"," platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}"," slack-token: ${{ secrets.TAILOR_SLACK_BOT_TOKEN }}"," slack-channel-id: ${{ vars.TAILOR_SLACK_CHANNEL_ID }}",` # editable: api-url:`],buildSiteStep=e=>[`- id: tailor-build-site-${e.name}`,` uses: ./.github/actions/tailor-${e.name}`,` with:`," workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}",` name: ${e.name}`,` working-directory: ${e.dir}`,` deploy: "false"`,` package-manager: ${a}`," platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}"," platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}"," slack-token: ${{ secrets.TAILOR_SLACK_BOT_TOKEN }}"," slack-channel-id: ${{ vars.TAILOR_SLACK_CHANNEL_ID }}"],multiConfigDeployStep=e=>[...e.apps.filter(e=>e.hasStaticWebsites).flatMap(buildSiteStep),`- id: tailor-deploy-${e.id}`,` uses: ./.github/actions/tailor-${firstApp(e).name}`,` with:`," workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}",` name: ${t}/${e.id}`,` working-directory: .`,` config: ${groupConfigPath(e)}`,` build-site: "false"`,` package-manager: ${a}`," platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}"," platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}"," slack-token: ${{ secrets.TAILOR_SLACK_BOT_TOKEN }}"," slack-channel-id: ${{ vars.TAILOR_SLACK_CHANNEL_ID }}",` # editable: api-url:`],f=r.flatMap(e=>e.apps.length===1?singleAppDeployStep(e,firstApp(e)):multiConfigDeployStep(e)).join(`
1181
- `);l=line(l,`PER_APP_DEPLOY_STEPS`,f),l=l.replaceAll(`__WORKSPACE_NAME__`,()=>t),l=l.replaceAll(`__ENVIRONMENT__`,()=>i),s!==void 0&&(l=l.replaceAll(`__BRANCH__`,()=>s)),o&&(l=l.replaceAll(`__TAG_PATTERN__`,()=>c));let p=[];o&&s!==void 0&&p.push(`tailor-tag-guard`,`tailor-tag-guard/tailor-checkout`,`tailor-tag-guard/tailor-tag-guard`),p.push(`tailor-plan`,`tailor-plan/tailor-checkout`,`tailor-plan/tailor-setup`,`tailor-plan/tailor-drift-check`);for(let e of r){for(let t of e.apps)p.push(`tailor-plan/tailor-generate-check-${t.name}`);p.push(`tailor-plan/tailor-plan-${e.id}`)}p.push(`tailor-deploy`,`tailor-deploy/tailor-checkout`,`tailor-deploy/tailor-setup`);for(let e of r){for(let t of e.apps)e.apps.length>1&&t.hasStaticWebsites&&p.push(`tailor-deploy/tailor-build-site-${t.name}`);p.push(`tailor-deploy/tailor-deploy-${e.id}`)}return{content:l,generatedIds:p}}function renderTailorSetupAction(e){let{packageManager:t}=e;return["# This file is user-owned. Generated once by `tailor setup coordinate` and never overwritten.",`# Customize freely: add pre/post steps, change install flags, etc.`,`name: Tailor Setup`,`description: Install dependencies and run tailor setup for composite action callers.`,`runs:`,` using: composite`,` steps:`,` - uses: tailor-platform/actions/setup@${na} # ${ra}`,` with:`,` package-manager: ${t}`,` # Add custom steps here (e.g. private registry authentication)`,` - uses: tailor-platform/actions/install@${na} # ${ra}`,` with:`,` package-manager: ${t}`,` # editable: install-command:`,``].join(`
1182
- `)}function actionName(e){return e.startsWith(`tailor-`)?e.slice(7):e}function splitActionGroup(e){let t=e.split(`,`).map(e=>actionName(e.trim()));if(t.some(e=>e.length===0))throw Error(`--action must contain one or more non-empty action names.`);return t}function uniqueGroupId(e,t){let n=e.join(`-`),r=n,i=2;for(;t.has(r);)r=`${n}-${i}`,i+=1;return t.add(r),r}async function defaultLoadConfigName(e){let{config:t}=await B(e);return t.name}async function defaultLoadErdNamespaces$1(e){let{config:t}=await B(e);return sn(t)}async function defaultLoadHasMigrations$1(e){let{config:t}=await B(e);return S(t,W.dirname(e)).length>0}async function defaultLoadHasSeeds$1(e){let{plugins:t}=await B(e);return t.some(e=>e.id===`@tailor-platform/seed`)}async function defaultLoadHasStaticWebsites$1(e){let{config:t}=await B(e);return(t.staticWebsites?.length??0)>0}function validateWorkspaceName(e){if(!Ft.safeParse(e).success)throw Error(`Invalid workspace name "${e}". Names must be 3-63 characters of lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen. Pass a valid name with --name.`)}const ia=/^[A-Za-z0-9._/-]+$/,aa=/^[A-Za-z0-9._/*?![\]-]+$/;function validateBranch(e){if(!ia.test(e))throw Error(`Invalid branch name "${e}". Only letters, numbers, ".", "_", "/", and "-" are supported here.`)}function validateTagPattern(e){if(!aa.test(e))throw Error(`Invalid tag pattern "${e}". Only letters, numbers, ".", "_", "/", "-", and the glob characters "*?![]" are supported.`)}const oa=/^[A-Za-z0-9._/-]+$/;function validateEnvironment(e){if(!oa.test(e))throw Error(`Invalid environment name "${e}". Only letters, numbers, ".", "_", "/", and "-" are supported.`)}const sa=/^[A-Za-z0-9._-]+$/;function validateRegion(e){if(!sa.test(e))throw Error(`Invalid region "${e}". Only letters, numbers, ".", "_", and "-" are supported.`)}const ca=/^[A-Za-z0-9._/-]+$/;function validateDir(e){if(!ca.test(e))throw Error(`Invalid --dir "${e}". Only letters, numbers, ".", "_", "/", and "-" are supported.`)}const la=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;function validateErdNamespaces(e){for(let t of e)if(!la.test(t))throw Error(`TailorDB namespace "${t}" cannot be used in --erd-preview. Only letters, numbers, '.', '_', and '-' are supported, and the name must start with a letter or number.`)}function escapesRoot$1(e){return e===`..`||e.startsWith(`..${W.sep}`)||e.startsWith(`../`)||W.isAbsolute(e)}function resolveConfigPath(e,t){let n=W.resolve(e,t),r=W.relative(e,n);if(W.isAbsolute(t)||escapesRoot$1(r))throw Error(`--dir must be a relative path inside the repository (got "${t}").`);if(X.existsSync(n)){let r=W.normalize(X.realpathSync(n)),i=W.normalize(X.realpathSync(e));if(escapesRoot$1(W.relative(i,r)))throw Error(`--dir must resolve to a directory inside the repository (got "${t}", which links outside it).`)}let i=W.join(n,`tailor.config.ts`);if(!X.existsSync(i))throw Error(`tailor.config.ts not found at ${i}. Run this from your SDK project root, or pass the app directory with --dir.`);return i}async function resolve$1(e){let t=e.dir.replaceAll(`\\`,`/`).replace(/\/{2,}/g,`/`).replace(/^\.\//,``).replace(/\/$/,``)||`.`;validateDir(t);let n=t===`.`?void 0:t,r=resolveConfigPath(e.outputDir,t),i=e.loadConfigName??defaultLoadConfigName,a=e.workspaceName??await i(r);if(!a)throw Error(`Could not determine the workspace name. Pass --name, or set 'name' in tailor.config.ts.`);validateWorkspaceName(a);let{kind:o}=e,s=detectPackageManager(e.outputDir),c=e.environment??a;validateEnvironment(c),o===`tag`&&validateTagPattern(e.tagPattern);let l=null,u=!1,d,f=[],p=!1,m=!1,h=!1,g=e.loadHasMigrations??defaultLoadHasMigrations$1,_=e.loadHasSeeds??defaultLoadHasSeeds$1,v=e.loadHasStaticWebsites??defaultLoadHasStaticWebsites$1;if(o===`branch`){if(e.erdPreview){if(f=await(e.loadErdNamespaces??defaultLoadErdNamespaces$1)(r),f.length===0)throw Error(`No TailorDB namespaces found for --erd-preview. Define owned db namespaces in tailor.config.ts.`);validateErdNamespaces(f)}u=e.branch===void 0,l=e.branch??detectDefaultBranch(e.outputDir,e.gitRunner,`--target`),validateBranch(l),p=await g(r),m=await _(r),d=renderBranchWorkflow({workspaceName:a,branch:l,workingDirectory:n,environment:c,packageManager:s,erdPreview:e.erdPreview?{namespaces:f}:null,migrationDriftCheck:p,seedValidate:m})}else o===`tag`?(l=e.branch??null,l!==null&&validateBranch(l),p=await g(r),m=await _(r),d=renderTagWorkflow({workspaceName:a,tagPattern:e.tagPattern,branch:e.branch,workingDirectory:n,environment:c,packageManager:s,migrationDriftCheck:p,seedValidate:m})):o===`preview`?(u=e.branch===void 0,l=e.branch??detectDefaultBranch(e.outputDir,e.gitRunner),validateBranch(l),validateRegion(e.region),d=renderPreviewWorkflow({workspaceName:a,branch:l,workingDirectory:n,environment:c,packageManager:s,region:e.region,requirePreviewLabel:e.requirePreviewLabel??!1})):(h=await v(r),d=renderActionWorkflow({workspaceName:a,workingDirectory:n,hasStaticWebsites:h}));let y=o===`action`?`.github/actions/tailor-${a}/action.yml`:`.github/workflows/tailor-${a}${o===`tag`?`-tag`:o===`preview`?`-preview`:``}.yml`,b={branch:o===`action`?null:l,branchAutoDetected:o===`branch`||o===`preview`?u:void 0,tagPattern:o===`tag`?e.tagPattern:null,environment:c,dir:t,packageManager:s,region:o===`preview`?e.region:void 0,requirePreviewLabel:o===`preview`?e.requirePreviewLabel??!1:void 0,erdPreview:o===`branch`&&e.erdPreview,erdNamespaces:o===`branch`&&e.erdPreview?f:void 0,migrationDriftCheck:o===`branch`||o===`tag`?p:void 0,seedValidate:o===`branch`||o===`tag`?m:void 0,hasStaticWebsites:o===`action`?h:void 0};return{kind:o,workspaceName:a,branch:l,environment:c,packageManager:s,erdNamespaces:f,render:d,inputs:b,file:y,configPath:r}}const ua=/([ \t]*- id: build-site\n(?:[ \t]+if: [^\n]+\n)?[ \t]+shell: bash\n[ \t]+run: \|)([\s\S]*?)(\n[ \t]*- |\n*$)/;function normalizeActionContent(e){return e.replace(ua,(e,t,n,r)=>`${t}\n true${r}`)}function extractBuildSiteRunBody(e){let t=ua.exec(e);return t?t[2]??null:null}function injectBuildSiteRunBody(e,t){return e.replace(ua,(e,n,r,i)=>`${n}${t}${i}`)}function decideAction(e){let{existing:t,fileExists:n,currentContent:r,force:i,normalize:a}=e;return t?n?r!==null&&hashContent(a?a(r):r)===t.contentHash||i?{action:`regenerate`}:{action:`conflict`,reason:`This workflow file has been edited by hand since it was generated. Re-run with --force to discard those edits and regenerate, or revert your changes.`}:{action:`restore`}:n?i?{action:`regenerate`}:{action:`conflict`,reason:`An unmanaged workflow file already exists at this path. Delete it, or pass --force to bring it under SDK management (this overwrites it).`}:{action:`create`}}function assertNoKindCollision(e){let{lock:t,kind:n,workspaceName:r,file:i}=e,a=t?.targets.find(e=>e.file===i&&(e.kind!==n||e.workspaceName!==r));if(a)throw Error(`A ${a.kind} target already owns ${i}, which conflicts with this ${n} target. Pass a different name with --name to generate a separate workflow.`)}function printNextSteps(e){let{environment:t,idInjected:n}=e;s.newline(),s.info(`Next steps:`),s.newline(),s.log(`1. Set the machine-user credentials as secrets on the "${t}" environment:`),s.log(` gh secret set TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID --env ${t}`),s.log(` gh secret set TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET --env ${t}`),s.newline(),s.log(`2. Provision the workspace and set its id as the TAILOR_PLATFORM_WORKSPACE_ID variable on the "${t}" environment:`),s.log(` tailor workspace create # if it does not exist yet; copy the id`),s.log(` gh variable set TAILOR_PLATFORM_WORKSPACE_ID --env ${t}`),s.newline(),s.log(`3. Commit the generated files:`),s.log(` - .github/workflows/tailor-*.yml`),s.log(` - .github/tailor.lock`),n&&s.log(` - tailor.config.ts (app id was added)`)}async function setupTarget(e){P(`setup`);let t=await resolve$1(e),n=readLock(e.outputDir),r=W.join(e.outputDir,t.file);assertNoKindCollision({lock:n,kind:t.kind,workspaceName:t.workspaceName,file:t.file});let i=findTarget(n,t.kind,t.workspaceName),a=X.existsSync(r),o=a?X.readFileSync(r,`utf-8`):null,l=t.kind===`action`?normalizeActionContent:void 0,u=decideAction({existing:i,fileExists:a,currentContent:o,force:e.force,normalize:l});if(u.action===`conflict`)throw Error(`${t.file}: ${u.reason}`);let d=await Kt(t.configPath);d===null&&s.warn(`Could not find a defineConfig() call to confirm an app id. The CI deploy will fail unless your config resolves to one with an 'id'.`);let f=d?.injected??!1,p=t.render.content;if(u.action===`regenerate`&&l&&o!==null){let e=extractBuildSiteRunBody(o);e!==null&&(p=injectBuildSiteRunBody(p,e))}X.mkdirSync(W.dirname(r),{recursive:!0}),X.writeFileSync(r,p,`utf-8`);let m={kind:t.kind,workspaceName:t.workspaceName,file:t.file,templateVersion:11,inputs:t.inputs,generatedIds:t.render.generatedIds,ejectedIds:i?.ejectedIds??[],contentHash:hashContent(l?l(t.render.content):t.render.content)},h=[...n?.targets??[]],g=h.findIndex(e=>e.kind===m.kind&&e.workspaceName===m.workspaceName);g===-1?h.push(m):h[g]=m,writeLock(e.outputDir,{version:1,targets:h}),u.action===`restore`?s.success(`Regenerated ${c.path(t.file)} (was missing on disk)`):u.action===`regenerate`?s.success(`Regenerated ${c.path(t.file)}`):s.success(`Generated ${c.path(t.file)}`),t.kind===`action`?(s.newline(),s.info(`Next steps:`),s.newline(),s.log(`The composite action has been generated at ${c.path(t.file)}.`),s.log("Use `tailor setup coordinate` to generate a coordinator workflow that orchestrates this action.")):printNextSteps({environment:t.environment,idInjected:f})}async function setupCoordinate(e){P(`setup`);let{coordinatorName:t,coordinateKind:n,actions:r,force:i,outputDir:a}=e;if(validateWorkspaceName(t),r.length===0)throw Error("At least one --action is required. Run `tailor setup action --dir <app-dir>` for each app first.");let o=e.environment??t;validateEnvironment(o);let l=null,u=!1;n===`branch`?(u=e.branch===void 0,l=e.branch??detectDefaultBranch(a,e.gitRunner),validateBranch(l)):e.branch!==void 0&&(validateBranch(e.branch),l=e.branch);let d=e.tagPattern??`v*`;n===`tag`&&validateTagPattern(d);let f=detectPackageManager(a),p=readLock(a);if(!p)throw Error(".github/tailor.lock not found. Run `tailor setup action --name <name>` for each app before running setup coordinate.");let m=new Map(p.targets.filter(e=>e.kind===`action`).map(e=>[e.workspaceName,e])),h=new Set,g=new Set,_=r.map(e=>{let t=splitActionGroup(e),n=t.map(e=>{if(h.has(e))throw Error(`Duplicate --action "${e}". Each composite action can only appear once in a coordinator.`);h.add(e);let n=m.get(e);if(!n)throw Error(`Action target "${e}" not found in .github/tailor.lock. Run \`tailor setup action --name ${e}\` first.`);if(t.length>1&&n.templateVersion<11)throw Error(`Action target "${e}" was generated with an older setup template. Run \`tailor setup action --name ${e} --force\` before grouping it in setup coordinate.`);return validateDir(n.inputs.dir),{name:e,dir:n.inputs.dir,hasStaticWebsites:n.inputs.hasStaticWebsites}});return{id:uniqueGroupId(t,g),apps:n}}),v=renderCoordinateWorkflow({coordinatorName:t,kind:n,actionGroups:_,branch:l??void 0,tagPattern:n===`tag`?d:void 0,environment:o,packageManager:f}),y=`.github/workflows/tailor-coordinate-${t}${n===`tag`?`-tag`:``}.yml`,b=W.join(a,y);assertNoKindCollision({lock:p,kind:`coordinate`,workspaceName:t,file:y});let x=findTarget(p,`coordinate`,t),S=X.existsSync(b),C=decideAction({existing:x,fileExists:S,currentContent:S?X.readFileSync(b,`utf-8`):null,force:i});if(C.action===`conflict`)throw Error(`${y}: ${C.reason}`);X.mkdirSync(W.dirname(b),{recursive:!0}),X.writeFileSync(b,v.content,`utf-8`);let w=`.github/actions/tailor-setup/action.yml`,T=W.join(a,w);X.existsSync(T)||(X.mkdirSync(W.dirname(T),{recursive:!0}),X.writeFileSync(T,renderTailorSetupAction({packageManager:f}),`utf-8`),s.success(`Generated ${c.path(w)}`));let E={kind:`coordinate`,workspaceName:t,file:y,templateVersion:11,inputs:{branch:l,branchAutoDetected:n===`branch`?u:l===null&&void 0,tagPattern:n===`tag`?d:null,environment:o,dir:`.`,packageManager:f,actionDirs:_.flatMap(e=>e.apps.map(e=>e.dir))},generatedIds:v.generatedIds,ejectedIds:x?.ejectedIds??[],contentHash:hashContent(v.content)},D=[...p.targets],O=D.findIndex(e=>e.kind===E.kind&&e.workspaceName===E.workspaceName);O===-1?D.push(E):D[O]=E,writeLock(a,{version:1,targets:D}),C.action===`restore`?s.success(`Regenerated ${c.path(y)} (was missing on disk)`):C.action===`regenerate`?s.success(`Regenerated ${c.path(y)}`):s.success(`Generated ${c.path(y)}`),s.newline(),s.info(`Next steps:`),s.newline(),s.log(`1. Set the machine-user credentials as secrets on the "${o}" environment:`),s.log(` gh secret set TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID --env ${o}`),s.log(` gh secret set TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET --env ${o}`),s.newline(),s.log(`2. Provision the target workspace and set TAILOR_PLATFORM_WORKSPACE_ID on the "${o}" environment:`),s.log(` tailor workspace create # if it does not exist yet; copy the id`),s.log(` gh variable set TAILOR_PLATFORM_WORKSPACE_ID --env ${o}`),s.newline(),s.log(`3. Commit the generated files:`),s.log(` - ${y}`),s.log(` - ${w} (if newly created)`),s.log(` - .github/tailor.lock`)}function findTargetDrift(e,t){let n=`${e.kind} ${e.workspaceName}`,r=[];if(t.fileExists?t.currentHash!==null&&t.currentHash!==e.contentHash&&r.push({target:n,rule:`hand-edit`,message:`${e.file} was edited by hand since it was generated. Re-run setup with --force to regenerate, or keep customizations in your own jobs/steps.`}):r.push({target:n,rule:`missing-file`,message:`${e.file} is missing or unreadable. Re-run setup to restore it.`}),e.templateVersion<t.templateVersion&&r.push({target:n,rule:`template-version`,message:`A newer workflow template is available (generated with v${String(e.templateVersion)}, current v${String(t.templateVersion)}). Re-run setup to update.`}),t.configExists||r.push({target:n,rule:`config-dir`,message:`tailor.config.ts not found under "${e.inputs.dir}". The app directory may have moved; re-run setup with the correct --dir.`}),(e.kind===`branch`||e.kind===`coordinate`||e.kind===`preview`)&&e.inputs.branchAutoDetected!==!1&&t.defaultBranch!==null&&e.inputs.branch!==null&&e.inputs.branch!==t.defaultBranch&&r.push({target:n,rule:`default-branch`,message:`The workflow triggers on "${e.inputs.branch}" but the repository default branch is now "${t.defaultBranch}". If this is intentional, ignore this; otherwise re-run setup so the trigger matches the default branch.`}),e.kind===`branch`&&e.inputs.erdPreview&&t.configExists){let i=[...e.inputs.erdNamespaces??[]].toSorted((e,t)=>e.localeCompare(t)),a=t.erdNamespaces?.toSorted((e,t)=>e.localeCompare(t))??null;(a===null||i.length!==a.length||i.some((e,t)=>e!==a[t]))&&r.push({target:n,rule:`erd-namespaces`,message:`TailorDB namespaces for ERD preview changed. Re-run setup so the ERD preview matrix is regenerated.`})}return(e.kind===`branch`||e.kind===`tag`)&&e.inputs.migrationDriftCheck===!1&&t.hasMigrations===!0&&r.push({target:n,rule:`migration-drift`,message:`TailorDB namespaces with migrations were added to the config. Re-run setup so the tailor-migration-drift-check step is included in the plan job.`}),(e.kind===`branch`||e.kind===`tag`)&&e.inputs.seedValidate===!1&&t.hasSeeds===!0&&r.push({target:n,rule:`seed-validate`,message:`Seed plugin detected in the current config. Re-run setup so the tailor-seed-validate step is included in the plan job.`}),e.kind===`action`&&e.inputs.hasStaticWebsites===!1&&t.hasStaticWebsites===!0&&r.push({target:n,rule:`static-websites`,message:`Static websites were added to the config. Re-run setup so the build-site slot is included in the composite action.`}),r}function detectDefaultBranchSafe(e,t){try{return detectDefaultBranch(e,t)}catch{return null}}function escapesRoot(e){return W.isAbsolute(e)||e===`..`||e.startsWith(`..${W.sep}`)||e.startsWith(`../`)}function resolveWithinRoot(e,t){if(W.isAbsolute(t))return null;let n=W.join(e,t);if(escapesRoot(W.relative(e,n)))return null;try{if(escapesRoot(W.relative(X.realpathSync(e),X.realpathSync(n))))return null}catch{}return n}function readHash(e,t){try{let n=X.readFileSync(e,`utf-8`);return hashContent(t?t(n):n)}catch{return null}}async function defaultLoadErdNamespaces(e){let{config:t}=await B(e);return sn(t)}async function defaultLoadHasMigrations(e){let{config:t}=await B(e);return S(t,W.dirname(e)).length>0}async function defaultLoadHasSeeds(e){let{plugins:t}=await B(e);return t.some(e=>e.id===`@tailor-platform/seed`)}async function defaultLoadHasStaticWebsites(e){let{config:t}=await B(e);return(t.staticWebsites?.length??0)>0}async function checkGitHub(e){P(`setup`);let{outputDir:t}=e,n=readLock(t);if(!n||n.targets.length===0)throw Error("No managed workflows found (.github/tailor.lock is missing or empty). Run `tailor setup branch` (or another setup subcommand) first.");if(!e.ci&&n.targets.some(e=>e.kind===`branch`||e.kind===`tag`||e.kind===`coordinate`)&&!process.env.TAILOR_PLATFORM_WORKSPACE_ID)throw Error(`TAILOR_PLATFORM_WORKSPACE_ID is not set. Provision the workspace and set the variable:
1183
- tailor workspace create # if it does not exist yet; copy the id
1184
- gh variable set TAILOR_PLATFORM_WORKSPACE_ID --env <environment>`);let r=!!process.env.TAILOR_SLACK_BOT_TOKEN;if(r!==!!process.env.TAILOR_SLACK_CHANNEL_ID)throw Error(`Slack is partially configured: ${r?`TAILOR_SLACK_BOT_TOKEN is set`:`TAILOR_SLACK_CHANNEL_ID is set`} but not both. TAILOR_SLACK_BOT_TOKEN (secret) and TAILOR_SLACK_CHANNEL_ID (variable) must be set together, or neither should be set.`);let i=e.configExistsAt??(e=>X.existsSync(e)),a=detectDefaultBranchSafe(t,e.gitRunner),o=e.loadErdNamespaces??defaultLoadErdNamespaces,c=e.loadHasMigrations??defaultLoadHasMigrations,l=e.loadHasSeeds??defaultLoadHasSeeds,u=e.loadHasStaticWebsites??defaultLoadHasStaticWebsites,d=[];for(let e of n.targets){let n=resolveWithinRoot(t,e.file),r=n===null?null:readHash(n,e.kind===`action`?normalizeActionContent:void 0),s=e.kind===`coordinate`?null:resolveWithinRoot(t,W.join(e.inputs.dir,`tailor.config.ts`)),f=e.kind===`coordinate`||s!==null&&i(s),p=e.kind===`branch`&&e.inputs.erdPreview&&s!==null&&f?await o(s):null,m=(e.kind===`branch`||e.kind===`tag`)&&e.inputs.migrationDriftCheck!==void 0&&s!==null&&f?await c(s):void 0,h=(e.kind===`branch`||e.kind===`tag`)&&e.inputs.seedValidate!==void 0&&s!==null&&f?await l(s):void 0,g=e.kind===`action`&&e.inputs.hasStaticWebsites!==void 0&&s!==null&&f?await u(s):void 0;d.push(...findTargetDrift(e,{fileExists:r!==null,currentHash:r,configExists:f,defaultBranch:a,templateVersion:11,erdNamespaces:p,hasMigrations:m,hasSeeds:h,hasStaticWebsites:g}))}let f=n.targets.length;if(d.length===0){s.success(`No drift detected across ${String(f)} target(s).`);return}for(let e of d)s.warn(`[${e.target}] ${e.message} (ignore key: ${e.rule})`);throw e.ci&&s.log(`TAILOR_SETUP_CHECK_DRIFT_COUNT=${String(d.length)}`),Error(`Detected ${String(d.length)} drift finding(s) across ${String(f)} target(s). Re-run \`tailor setup\` to regenerate, or address each finding above.`)}function normalizeRelPath(e){return e.replaceAll(`\\`,`/`).replace(/\/{2,}/g,`/`).replace(/^\.\//,``).replace(/\/$/,``)}function targetKey(e){return`${e.kind}:${e.workspaceName}`}function resolveMatch(e,t,n){let r=normalizeRelPath(n),i=resolveWithinRoot(e,r);if(i===null)throw Error(`"${n}" must be a path inside the repository.`);let a=t.find(e=>e.file===r);if(!a)throw Error(`"${r}" is not a managed workflow/action file (not recorded in .github/tailor.lock). Only files generated by \`tailor setup\` can be deleted with this command.`);return{relPath:r,absPath:i,target:a}}function warnCoordinatorReferences(e,t,n){if(n.target.kind===`action`)for(let r of e)r.kind===`coordinate`&&r.inputs.actionDirs?.includes(n.target.inputs.dir)&&!t.has(targetKey(r))&&s.warn(`Coordinator "${r.workspaceName}" still references this action's directory (${n.target.inputs.dir}). Remove \`${n.target.workspaceName}\` from the relevant \`--action\` value and re-run \`tailor setup coordinate\` to update it.`)}async function setupDelete(e){P(`setup`);let{outputDir:t,yes:n}=e,r=readLock(t);if(!r||r.targets.length===0)throw Error("No managed workflows found (.github/tailor.lock is missing or empty). Run `tailor setup branch` (or another setup subcommand) first.");let i=[...new Set(e.files.map(normalizeRelPath))].map(e=>resolveMatch(t,r.targets,e)),a=new Set(i.map(e=>targetKey(e.target)));for(let e of i)warnCoordinatorReferences(r.targets,a,e);if(!n){let e=i.map(e=>e.relPath).join(`
1185
- `);if(!await z.confirm({message:`This will delete the following file(s) and their .github/tailor.lock entries:\n ${e}\nContinue?`,default:!1})){s.info(`Delete cancelled.`);return}}let o=[...r.targets];try{for(let{relPath:e,absPath:t,target:n}of i){if(X.rmSync(t,{force:!0}),n.kind===`action`){let e=W.dirname(t);X.existsSync(e)&&X.readdirSync(e).length===0&&X.rmdirSync(e)}let r=o.findIndex(e=>targetKey(e)===targetKey(n));r!==-1&&o.splice(r,1),s.success(`Deleted ${c.path(e)} (${n.kind} ${n.workspaceName})`)}}finally{o.length!==r.targets.length&&writeLock(t,{version:1,targets:o})}}const da=`renovate.json`,fa=`github>tailor-inc/renovate-config`,pa=[da,`renovate.jsonc`,`renovate.json5`,`.github/renovate.json`,`.github/renovate.jsonc`,`.github/renovate.json5`,`.gitlab/renovate.json`,`.gitlab/renovate.jsonc`,`.gitlab/renovate.json5`,`.renovaterc`,`.renovaterc.json`,`.renovaterc.jsonc`,`.renovaterc.json5`];function getPathEntry(e){try{return X.lstatSync(e)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return null;throw e}}function pathEntryExists(e){return getPathEntry(e)!==null}function extendsPreset(e){if(!(`extends`in e))return!1;let t=e.extends;return Array.isArray(t)&&t.includes(`github>tailor-inc/renovate-config`)}function readJsonConfig(e){let t=getPathEntry(e);if(t===null||!t.isFile())return null;let n;try{n=JSON.parse(X.readFileSync(e,`utf-8`))}catch{return null}return typeof n==`object`&&n&&!Array.isArray(n)?n:null}function classifyConfig(e,t,n){return n===null?{kind:`unreadable`,location:e}:extendsPreset(n)?{kind:`extends-preset`,location:e}:{kind:`appendable`,location:e,filePath:t,config:n}}function findExistingConfig(e){for(let t of pa){let n=W.join(e,t);if(pathEntryExists(n))return classifyConfig(t,n,readJsonConfig(n))}let t=W.join(e,`package.json`);if(!X.existsSync(t))return null;let n;try{n=JSON.parse(X.readFileSync(t,`utf-8`))}catch(e){throw Error(`package.json is not valid JSON; could not inspect its Renovate config.`,{cause:e})}if(typeof n==`object`&&n&&`renovate`in n){let e=n.renovate;return classifyConfig(`package.json#renovate`,t,typeof e==`object`&&e&&!Array.isArray(e)?e:null)}return null}function detectIndent(e){return/^(?<indent>[ ]+)"/m.exec(e)?.groups?.indent?.length??2}function appendPreset(e){let t=X.readFileSync(e.filePath,`utf-8`),n=`extends`in e.config?e.config.extends:void 0;if(n!==void 0&&!Array.isArray(n))throw Error(`Renovate config at "${e.location}" has a non-array "extends". No files were changed. Add "${fa}" to it manually.`);let r={...e.config,extends:[...n??[],fa]},i=e.location===`package.json#renovate`?{...JSON.parse(t),renovate:r}:r,a=t.endsWith(`
1186
- `)?`
1187
- `:``;X.writeFileSync(e.filePath,`${JSON.stringify(i,null,detectIndent(t))}${a}`,`utf-8`)}function renderRenovateConfig(){return`${JSON.stringify({$schema:`https://docs.renovatebot.com/renovate-schema.json`,extends:[fa]},null,2)}\n`}async function setupRenovate(e){P(`setup`);let t=findExistingConfig(e.outputDir);if(t!==null){if(t.kind===`extends-preset`){s.info(`Renovate is already set up at ${c.path(t.location)}.`);return}if(t.kind===`unreadable`)throw Error(`Found a Renovate config at "${t.location}" but could not parse it as JSON. Comment-containing JSON5/JSONC configs are not supported yet. No files were changed. Check its extends array for "${fa}" manually.`);appendPreset(t),s.success(`Added the Tailor preset to ${c.path(t.location)}`);return}let n=W.join(e.outputDir,da);X.writeFileSync(n,renderRenovateConfig(),`utf-8`),s.success(`Generated ${c.path(da)}`)}const ma=g({name:`check`,description:`Audit generated workflows for drift against the current config/repo (read-only).`,args:J.strictObject({ci:G(J.boolean().default(!1),{description:`Run in CI mode: skip checks that are handled by the runtime (e.g. TAILOR_PLATFORM_WORKSPACE_ID).`})}),run:async e=>{await checkGitHub({outputDir:process.cwd(),ci:e.ci})}}),ha=g({name:`coordinate`,description:`Generate a coordinator workflow that orchestrates multiple --action-generated composite actions.`,args:J.strictObject({name:G(J.string().min(1),{alias:`n`,description:`Coordinator name (used in the generated workflow file name and job names)`}),action:G(J.array(J.string().min(1)).min(1),{description:`Composite action to include. Repeat for separate deploy steps, or use commas to deploy actions as one multi-config group. tailor- prefix optional.`}),branch:G(J.string().min(1).optional(),{description:`Branch target: deploy trigger branch (defaults to the detected default branch)`}),tag:G(J.boolean().default(!1),{description:`Generate a tag target coordinator`}),environment:G(J.string().min(1).optional(),{description:`GitHub Environment for the plan/deploy jobs`}),force:G(J.boolean().default(!1),{description:`Discard hand edits and regenerate`})}),run:async e=>{let t=e.tag?`tag`:`branch`;await setupCoordinate({coordinatorName:e.name,coordinateKind:t,actions:e.action,branch:e.branch,environment:e.environment,force:e.force,outputDir:process.cwd()})}}),ga=g({name:`action`,description:`Generate a per-app composite action for use with setup coordinate (monorepo multi-app deploys).`,args:J.strictObject({name:G(J.string().min(1).optional(),{alias:`n`,description:`Name (defaults to the config 'name')`}),dir:G(J.string().min(1).default(`.`),{alias:`d`,description:`App directory`}),environment:G(J.string().min(1).optional(),{description:`GitHub Environment (defaults to the workspace name)`}),force:G(J.boolean().default(!1),{description:`Discard hand edits and regenerate`})}),run:async e=>{await setupTarget({kind:`action`,workspaceName:e.name,dir:e.dir,environment:e.environment,force:e.force,outputDir:process.cwd()})}}),_a=g({name:`branch`,description:`Generate a branch-target deploy workflow (push to branch triggers deploy).`,args:J.strictObject({name:G(J.string().min(1).optional(),{alias:`n`,description:`Name (defaults to the config 'name')`}),target:G(J.string().min(1).optional(),{hiddenAlias:`branch`,description:`Deploy trigger branch (defaults to the detected default branch)`}),environment:G(J.string().min(1).optional(),{description:`GitHub Environment for the plan/deploy jobs (defaults to the workspace name)`}),"erd-preview":G(J.boolean().default(!1),{description:`Add PR ERD viewer artifacts with current/diff previews for TailorDB namespaces`}),dir:G(J.string().min(1).default(`.`),{alias:`d`,description:`App directory (for monorepo setups)`}),force:G(J.boolean().default(!1),{description:`Discard hand edits / take over unmanaged files and regenerate`})}),notes:"`--branch` is a deprecated alias of `--target` and will be removed in v3.",run:async e=>{usedDeprecatedBranchFlag(process.argv)&&s.warn("`tailor setup branch --branch` is deprecated and will be removed in v3. Use `--target` instead."),await setupTarget({kind:`branch`,workspaceName:e.name,branch:e.target,environment:e.environment,erdPreview:e[`erd-preview`],dir:e.dir,force:e.force,outputDir:process.cwd()})}}),va=g({name:`tag`,description:`Generate a tag-target deploy workflow (tag push triggers deploy).`,args:J.strictObject({name:G(J.string().min(1).optional(),{alias:`n`,description:`Name (defaults to the config 'name')`}),"tag-pattern":G(J.string().min(1).default(`v*`),{description:`Tag glob to match (defaults to v*)`}),branch:G(J.string().min(1).optional(),{description:`Tag-reachability guard branch (no guard when omitted)`}),environment:G(J.string().min(1).optional(),{description:`GitHub Environment for the plan/deploy jobs (defaults to the workspace name)`}),dir:G(J.string().min(1).default(`.`),{alias:`d`,description:`App directory (for monorepo setups)`}),force:G(J.boolean().default(!1),{description:`Discard hand edits / take over unmanaged files and regenerate`})}),run:async e=>{await setupTarget({kind:`tag`,workspaceName:e.name,tagPattern:e[`tag-pattern`],branch:e.branch,environment:e.environment,dir:e.dir,force:e.force,outputDir:process.cwd()})}}),ya=g({name:`preview`,description:`Generate a preview workflow (PR open/sync triggers deploy to a per-PR workspace).`,args:J.strictObject({name:G(J.string().min(1).optional(),{alias:`n`,description:`Name (defaults to the config 'name')`}),branch:G(J.string().min(1).optional(),{description:`Branch to filter PRs by (defaults to the detected default branch)`}),region:G(J.string().min(1),{description:`Workspace region for preview workspace creation (e.g. us-west). Required.`}),"require-preview-label":G(J.boolean().default(!1),{description:"Deploy preview only for PRs labeled `tailor:preview` instead of all PRs."}),environment:G(J.string().min(1).optional(),{description:`GitHub Environment for the preview jobs (defaults to the workspace name)`}),dir:G(J.string().min(1).default(`.`),{alias:`d`,description:`App directory (for monorepo setups)`}),force:G(J.boolean().default(!1),{description:`Discard hand edits / take over unmanaged files and regenerate`})}),run:async e=>{await setupTarget({kind:`preview`,workspaceName:e.name,branch:e.branch,region:e.region,requirePreviewLabel:e[`require-preview-label`],environment:e.environment,dir:e.dir,force:e.force,outputDir:process.cwd()})}}),ba=[`renovate`],xa={renovate:setupRenovate},Sa=g({name:`deps`,description:`Generate a dependency update config for Tailor dependency and workflow updates.`,args:J.strictObject({provider:G(J.enum(ba).default(`renovate`),{description:`Dependency update provider to configure`})}),run:async e=>{await xa[e.provider]({outputDir:process.cwd()})}}),Ca=g({name:`delete`,description:`Delete managed workflow/action file(s) and their .github/tailor.lock entries.`,args:J.strictObject({...F,files:G(J.string().array().min(1),{positional:!0,description:`Workflow/action file(s) to delete, as generated under .github/workflows or .github/actions`})}),run:async e=>{await setupDelete({files:e.files,yes:e.yes,outputDir:process.cwd()})}});function usedDeprecatedBranchFlag(e){return e.some(e=>e===`--branch`||e.startsWith(`--branch=`))}const wa=K({name:`setup`,description:`Set up repository automation for your project. (beta)`,subCommands:{branch:_a,tag:va,preview:ya,action:ga,coordinate:ha,deps:Sa,check:ma,delete:Ca}}),Ta={[n.UNSPECIFIED]:`unspecified`,[n.PENDING]:`pending`,[n.VERIFYING]:`verifying`,[n.CERT_ISSUED]:`cert_issued`,[n.ACTIVE]:`active`,[n.FAILED]:`failed`},Ea=g({name:`get`,description:`Get details of a custom domain.`,args:J.strictObject({...N,domain:G(J.string(),{positional:!0,description:`Custom domain name`})}),run:async e=>{let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile}),i=`Custom domain "${e.domain}" not found.`;try{let{customDomain:t}=await n.getCustomDomain({workspaceId:r,domain:e.domain});if(!t)throw Error(i);let a={domain:t.domain,status:Ta[t.status]??`unknown`,trafficCnameTarget:t.trafficCnameTarget,certificateCnameTarget:t.certificateCnameTarget,errorMessage:t.errorMessage||void 0};s.out(a)}catch(e){throw e instanceof Q&&e.code===Z.NotFound?Error(i,{cause:e}):e}}}),Da=g({name:`list`,description:`List custom domains for a static website.`,args:J.strictObject({...N,name:G(J.string(),{positional:!0,description:`Static website name`})}),run:async e=>{let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile});try{let{customDomains:t}=await n.listCustomDomains({workspaceId:r,staticWebsiteName:e.name});if(t.length===0){s.info(`No custom domains found.`),s.jsonMode&&s.out([]);return}let i=t.map(e=>({domain:e.domain,status:Ta[e.status]??`unknown`,trafficCnameTarget:e.trafficCnameTarget,certificateCnameTarget:e.certificateCnameTarget}));s.out(i)}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Static website "${e.name}" not found.`,{cause:t}):t}}}),Oa=K({name:`domain`,description:`Manage custom domains for static websites.`,subCommands:{list:Da,get:Ea}}),ka=g({name:`get`,description:`Get details of a specific static website.`,args:J.strictObject({...N,name:G(J.string(),{positional:!0,description:`Static website name`})}),run:async e=>{let t=await D({profile:e.profile}),n=await H(t),r=await j({workspaceId:e[`workspace-id`],profile:e.profile}),i=`Static website "${e.name}" not found.`;try{let{staticwebsite:t}=await n.getStaticWebsite({workspaceId:r,name:e.name});if(!t)throw Error(i);let a={workspaceId:r,name:t.name,description:t.description,url:t.url,allowedIpAddresses:e.json?t.allowedIpAddresses:t.allowedIpAddresses.join(`
1188
- `)};s.out(a)}catch(e){throw e instanceof Q&&e.code===Z.NotFound?Error(i,{cause:e}):e}}});async function listStaticWebsites(e){let t=await D({profile:e?.profile}),n=await H(t),r=await j({workspaceId:e?.workspaceId,profile:e?.profile}),i=qe(e?.order);return(await On(async(e,t)=>{let{staticwebsites:a,nextPageToken:o}=await n.listStaticWebsites({workspaceId:r,pageToken:e,pageSize:t,pageDirection:i});return[a,o]},{limit:e?.limit})).map(e=>({workspaceId:r,name:e.name,description:e.description,url:e.url,allowedIpAddresses:e.allowedIpAddresses}))}const Aa=g({name:`list`,description:`List all static websites in a workspace.`,args:J.strictObject({...N,...We()}),run:async e=>{let t=s.jsonMode,n=await listStaticWebsites({workspaceId:e[`workspace-id`],profile:e.profile,order:e.order,limit:e.limit}),r=t?n:n.map(({allowedIpAddresses:e,...t})=>{if(e.length===0)return{...t,allowedIpAddresses:`No allowed IP addresses`};let n=e.length,r=n===1?`1 IP address`:`${n} IP addresses`;return{...t,allowedIpAddresses:r}});s.out(r)}}),ja=K({name:`staticwebsite`,description:`Manage static websites in your workspace.`,subCommands:{deploy:h,domain:Oa,list:Aa,get:ka},async run(){await q(Aa,[])}}),Ma=new Set(Object.values(ne));async function activateBaseline(e,t,n,r){let i=await $.realpath(e),a=W.dirname(i),o=W.basename(i),c=await $.mkdtemp(W.join(a,`.${o}-rebaseline-`)),l=`${c}-previous`,u=!1,d=!1;try{await $.cp(i,c,{recursive:!0});for(let e of await $.readdir(c,{withFileTypes:!0})){if(!e.isDirectory()||!Re.test(e.name))continue;let t=W.join(c,e.name);(await $.readdir(t)).some(e=>Ma.has(e))&&await $.rm(t,{recursive:!0,force:!0})}let e={...t,namespace:n,version:5,createdAt:new Date().toISOString(),rebaseline:r},a=await pn(e,c,0);De(a.filePath),await $.rename(i,l),u=!0;try{await $.rename(c,i),d=!0}catch(e){throw await $.rename(l,i),u=!1,e}try{await $.rm(l,{recursive:!0,force:!0})}catch(e){s.warn(`The previous migration directory remains at ${l}: ${e instanceof Error?e.message:String(e)}`)}u=!1}finally{X.existsSync(c)&&await $.rm(c,{recursive:!0,force:!0}),!d&&u&&X.existsSync(l)&&await $.rename(l,i)}}async function rebaseline(e){P(`tailordb migration`);let{config:t,plugins:n}=await B(e.configPath),r=W.dirname(t.path),i=Ce(S(t,r),e.namespace),a=Zn({command:`tailor`,args:[`tailordb`,`migration`,`generate`,`--config`,t.path]});O(i.migrationsDir,i.namespace);let o=A(i.migrationsDir);if(!o)throw Error(`No migration history found for namespace "${i.namespace}". Run ${a} first.`);let l=de(i.migrationsDir),u=A(i.migrationsDir,0)?.rebaseline?.historyId??null,d=f([i])[i.namespace],p=n.length>0?new at(n):void 0,{defineApplication:m}=await import(`../application-DFOUovmN.mjs`),h=m({config:t,pluginManager:p});for(let e of h.tailorDBServices)await e.loadTypes(),await e.processNamespacePlugins();let g=h.tailorDBServices.find(e=>e.namespace===i.namespace);if(!g)throw Error(`No TailorDB service found for namespace "${i.namespace}"`);let assertLocalTypesReady=()=>{let e=ye(g.types,i.namespace),t=bt(o,e.tables,i.namespace);if(pt(t))throw s.error(`Migration history does not reproduce the current local schema for namespace ${c.bold(i.namespace)}:`),s.log(st(t)),Error(`Refusing to re-baseline: the migration history must reproduce the current local schema. Run ${a} first.`)},localSourceFiles=()=>[t.path,...Hn(g.config,r)];assertLocalTypesReady();let _=Tt(localSourceFiles()),v=await D({profile:e.profile}),y=await H(v),b=await j({workspaceId:e.workspaceId,profile:e.profile}),x=[`--config`,t.path,`--workspace-id`,b,...e.profile?[`--profile`,e.profile]:[]],C=Zn({command:`tailor`,args:[`tailordb`,`migration`,`set`,`0`,`--namespace`,i.namespace,...x]}),w=Zn({command:`tailor`,args:[`deploy`,...x]}),assertConnectedWorkspaceReady=async(e,n)=>{let r=await E(y,R(b,`tailordb`,i.namespace)),a=r.number;if(a!==l){let e=a===null?`<unset>`:L(a);throw Error(`The connected workspace must be at the latest migration ${L(l)} before re-baselining; current checkpoint is ${e}.`)}if(r.historyIdInvalid)throw Error(`Refusing to re-baseline: the connected workspace has an invalid migration history marker.`);if(r.historyId!==e)throw Error(n===`confirmation`?`The connected workspace migration history changed while waiting for confirmation. Run the command again.`:`Refusing to re-baseline: the connected workspace does not match the local migration history.`);let o=await vt(y,b,[i],t,[At(g)]),c=o[0];if(!c||c.remoteMigrationNumber!==l||c.hasDrift||c.checkpointMissingLocal)throw c?.hasDrift&&(s.error(`Remote schema drift detected:`),s.log(ft(o))),Error(`Refusing to re-baseline: the connected workspace remote schema must match the latest migration.`)};if(await assertConnectedWorkspaceReady(u,`initial`),s.newline(),s.warn(`This will replace the migration history for ${c.bold(i.namespace)}.`),s.log(` Latest migration: ${L(l)}`),s.log(` New history: 0000/schema.json only`),s.log(` migrate.ts and db.ts files will disappear from the working tree.`),s.log(` Committed migration files will remain in Git history. Preserve any uncommitted files before continuing.`),s.log(` Every other environment must already be at the latest migration.`),s.log(` The connected workspace checkpoint will be reset to 0000.`),s.newline(),!e.yes&&!await z.confirm({message:`Re-baseline this migration history and reset the connected workspace checkpoint?`,default:!1})){s.info(`Operation cancelled.`);return}if(O(i.migrationsDir,i.namespace),f([i])[i.namespace]!==d)throw Error(`Migration files changed while waiting for confirmation. Run the command again.`);if(Tt(localSourceFiles())!==_)throw Error(`Local TailorDB table or config files changed. Run the command again.`);assertLocalTypesReady(),await assertConnectedWorkspaceReady(u,`confirmation`);let T={historyId:Xt(),replacedHistoryId:u,replacedLatestMigration:l};await activateBaseline(i.migrationsDir,o,i.namespace,T);try{await Ye(y,b,i.namespace,0,T.historyId)}catch(e){throw Error(`The local migration history was re-baselined, but the connected workspace checkpoint could not be updated. Run ${C}, or run ${w} with schema checks enabled after resolving the connection error.`,{cause:e})}s.success(`Re-baselined ${c.bold(i.namespace)} and reset the connected workspace checkpoint to 0000.`)}const Na=g({name:`rebaseline`,description:`Collapse the full migration history into a new 0000 baseline.`,notes:`Re-baselining removes migrations after 0000 from the working tree, records a new migration history ID, and resets the connected workspace checkpoint without changing its schema or data. Every environment must already have applied the latest migration before you run this command.`,args:J.strictObject({...k,...F,namespace:G(J.string().optional(),{alias:`n`,description:`Target TailorDB namespace (required if multiple namespaces exist)`})}),run:async e=>{await I({profile:e.profile}),await rebaseline({configPath:e.config,namespace:e.namespace,yes:e.yes,workspaceId:e[`workspace-id`],profile:e.profile})}});async function set(e){P(`tailordb migration`);let t=Dt(e.number),{config:n}=await B(e.configPath),r=W.dirname(n.path),i=S(n,r),a=Ce(i,e.namespace),o=a.namespace;O(a.migrationsDir,o),te(a.migrationsDir,t);let l=A(a.migrationsDir,0)?.rebaseline?.historyId,d=await D({profile:e.profile}),f=await H(d),p=await j({workspaceId:e.workspaceId,profile:e.profile}),m=R(p,`tailordb`,o),h=await E(f,m),g=h.number,_=g??0,v=h.historyIdInvalid?`<invalid>`:h.historyId??`<unset>`,y=l??`<unset>`;if(s.newline(),s.warn(`This operation will change TailorDB migration state metadata.`),s.log(`Namespace: ${c.bold(o)}`),s.log(`Current migration: ${g===null?`<unset>`:c.bold(L(g))}`),s.log(`New migration: ${c.bold(L(t))}`),s.log(`Current migration history ID: ${c.bold(v)}`),s.log(`New migration history ID: ${c.bold(y)}`),s.newline(),t<_?(s.warn(`Setting migration number backwards (${L(_)} → ${L(t)}) will cause previous migrations to be re-executed on next apply.`),s.newline()):t>_&&(s.warn(`Setting migration number forwards (${L(_)} → ${L(t)}) will skip migrations ${L(_+1)} to ${L(t)}.`),s.newline()),!e.yes){if(!await z.confirm({message:`Continue with migration checkpoint and history ID update?`,default:!1})){s.info(`Operation cancelled.`);return}s.newline()}await Xe(f,{trn:m,labels:{[ut]:Wt(t),...l?{[u]:l}:{}},remove:l?void 0:[u]}),s.success(`Migration checkpoint set to ${c.bold(L(t))} for namespace ${c.bold(o)}`)}const Pa=g({name:`set`,description:`Set migration checkpoint to a specific number.`,notes:"The migration number must be a 4-digit value (e.g. `0001`) or a bare integer (e.g. `1`) within 0–9999, and must exist in the local migration history; `0` is always accepted as the baseline, provided the local history passes validation. A gapped history is rejected.\n\nMetadata lookup failures (authentication, permission, or network errors) are reported as errors; only a not-yet-deployed namespace is treated as having no checkpoint.",args:J.strictObject({...k,...F,number:G(J.string(),{positional:!0,description:`Migration number to set (e.g., 0001 or 1)`}),namespace:G(J.string().optional(),{alias:`n`,description:`Target TailorDB namespace (required if multiple namespaces exist)`})}),run:async e=>{await I({profile:e.profile}),await set({configPath:e.config,number:e.number,namespace:e.namespace,yes:e.yes,workspaceId:e[`workspace-id`],profile:e.profile})}});function isStatusFailure(e){return e.status===`error`}async function collectMigrationStatuses(e){let{config:t}=await B(e.configPath),n=W.dirname(t.path),r=S(t,n);if(r.length===0)throw Error(`No TailorDB services with migrations configuration found`);let i=e.namespace?r.filter(t=>t.namespace===e.namespace):r;if(i.length===0)throw Error(`Namespace "${e.namespace}" not found or does not have migrations configured`);let a=new Map,o=new Map;for(let{namespace:e,migrationsDir:t}of i)try{let n=Ue(t),r=new Map,i=null;for(let e of n){if(e.type===`schema`){let t=De(e.path);e.number===0&&(i=t.rebaseline?.historyId??null);continue}try{let t=Ke(e.path);t.description&&r.set(e.number,t.description)}catch(e){if(e instanceof It)throw e}}a.set(e,{migrationFiles:n,descriptions:r,historyId:i})}catch(t){o.set(e,t instanceof Error?t.message:String(t))}if(a.size===0)return i.map(({namespace:e})=>({status:`error`,namespace:e,error:o.get(e)??`Failed to read local migration history.`}));let s=await D({profile:e.profile}),c=await H(s),l=await j({workspaceId:e.workspaceId,profile:e.profile}),u=[];for(let{namespace:e}of i){if(o.has(e)){u.push({status:`error`,namespace:e,error:o.get(e)??`Failed to read local migration history.`});continue}let t=a.get(e);if(!t){u.push({status:`error`,namespace:e,error:`Failed to read local migration history.`});continue}let{migrationFiles:n,descriptions:r,historyId:i}=t,s=R(l,`tailordb`,e),d;try{d=await E(c,s)}catch(t){u.push({status:`error`,namespace:e,error:t instanceof Error?t.message:String(t)});continue}let f=d.number??0;if(d.historyIdInvalid){u.push({status:`error`,namespace:e,error:`Remote migration history ID is invalid.`});continue}if((d.number!==null||d.historyId!==null)&&d.historyId!==i){u.push({status:`error`,namespace:e,error:`Remote migration history ID ${d.historyId??`<unset>`} does not match local migration history ID ${i??`<unset>`}.`});continue}let p=n.map(e=>e.number).filter((e,t,n)=>n.indexOf(e)===t).toSorted((e,t)=>e-t).filter(e=>e>f).map(e=>({number:e,label:L(e),...r.has(e)?{description:r.get(e)}:{}}));u.push({status:`ok`,namespace:e,currentMigration:f,currentMigrationLabel:L(f),pendingMigrations:p})}return u}function printMigrationStatuses(e){for(let t of e){if(s.newline(),s.info(`Namespace: ${c.bold(t.namespace)}`),isStatusFailure(t)){s.error(` Migration status error: ${t.error}`);continue}if(s.log(` Current migration: ${c.bold(t.currentMigrationLabel)}`),t.pendingMigrations.length>0){s.log(` Pending migrations:`);for(let e of t.pendingMigrations)e.description?s.log(` - ${e.label}: ${e.description}`):s.log(` - ${e.label}`)}else s.log(` Pending migrations: (none)`)}s.newline()}async function status(e){P(`tailordb migration`);let t=await collectMigrationStatuses(e);e.json?s.out(t):printMigrationStatuses(t);let n=t.filter(isStatusFailure);if(n.length>0){let e=n.map(e=>e.namespace).join(`, `);throw Error(`Migration status check failed for ${n.length} namespace${n.length===1?``:`s`}: ${e}`)}}const Fa=g({name:`status`,description:`Show the current migration status for TailorDB namespaces, including applied and pending migrations.`,notes:`Every local migration file is checked for a compatible format version, and deployed migration history IDs must match the local baseline. Compatibility errors, history mismatches, and metadata lookup failures are reported per namespace and make the command exit non-zero; only a not-yet-deployed namespace is treated as having no applied migrations.`,args:J.strictObject({...k,namespace:G(J.string().optional(),{alias:`n`,description:`Target TailorDB namespace (shows all namespaces if not specified)`})}),run:async e=>{await status({configPath:e.config,namespace:e.namespace,workspaceId:e[`workspace-id`],profile:e.profile,json:s.jsonMode})}});async function fetchRemoteGqlPermissions(e,t,n){return Vn(async(r,i)=>{let{permissions:a,nextPageToken:o}=await e.listTailorDBGQLPermissions({workspaceId:t,namespaceName:n,pageToken:r,pageSize:i});return[a,o]})}async function fetchRemoteTypes(e,t,n){return Tn(async(r,i)=>{try{let{tailordbTypes:a,nextPageToken:o}=await e.listTailorDBTypes({workspaceId:t,namespaceName:n,pageToken:r,pageSize:i});return[a,o]}catch(e){throw e instanceof Q&&e.code===Z.NotFound?Error(`Cannot sync: TailorDB namespace "${n}" has not been deployed yet.`,{cause:e}):e}})}async function assertMigrationsReproduceLocalTypes(e,t){let{config:n,plugins:r}=e,i=r.length>0?new at(r):void 0,{defineApplication:a,generatePluginFilesIfNeeded:o}=await import(`../application-DFOUovmN.mjs`),l=a({config:n,pluginManager:i}),u=l.tailorDBServices.find(e=>e.namespace===t.namespace);if(!u)throw Error(`No TailorDB service found for namespace "${t.namespace}"`);for(let e of l.tailorDBServices)await e.loadTypes(),await e.processNamespacePlugins();let d=o(i,l.tailorDBServices,n.path),f=l.executorService??(d.length>0?(await import(`../service-CpZELSBa.mjs`)).createExecutorService({config:{files:[]},baseDir:W.dirname(n.path)}):void 0);await f?.loadExecutors(),d.length>0&&await f?.loadPluginExecutorFiles([...d]);let p=new Set;for(let e of Object.values(f?.executors??{}))e.trigger.kind===`tailordb`&&p.add(e.trigger.tableName);let m={executorUsedTables:p,namespaceGqlOperations:u.config.gqlOperations},h=A(t.migrationsDir);if(!h)return m;let g=ye(u.types,t.namespace),_=bt(h,g.tables,t.namespace);if(!pt(_))return m;throw s.error(`Migration history does not reproduce the current local schema for namespace ${c.bold(t.namespace)}:`),s.log(st(_)),s.newline(),s.info(`This usually means one of the following:`),s.info(` - Migration files were edited and replaying them no longer matches the table definitions — fix the migration files.`,{mode:`plain`}),s.info(` - Table definitions changed without a new migration — run 'tailor tailordb migration generate' first.`,{mode:`plain`}),s.newline(),Error(`Refusing to sync: the migration history must reproduce the current local schema before it can be applied to the remote.`)}async function sync(e){P(`tailordb migration`);let t=Dt(e.number),n=await B(e.configPath),{config:r}=n,i=W.dirname(r.path),a=S(r,i),o=Ce(a,e.namespace);O(o.migrationsDir,o.namespace);let l=te(o.migrationsDir,t),d=A(o.migrationsDir,t);if(!d)throw Error(`No initial schema snapshot found in ${o.migrationsDir}. Expected 0000/schema.json.`);let f=await assertMigrationsReproduceLocalTypes(n,o),p=await D({profile:e.profile}),m=await H(p),h=await j({workspaceId:e.workspaceId,profile:e.profile}),g=R(h,`tailordb`,o.namespace),_=await Pe(m,g),v=await fetchRemoteTypes(m,h,o.namespace),b=new Set(v.map(e=>e.name)),{creates:x,updates:C,deletes:w}=je(d,b),T=await fetchRemoteGqlPermissions(m,h,o.namespace),E=new Set(T.map(e=>e.typeName)),ee=Object.entries(d.tables).flatMap(([e,t])=>t.permissions?.gql?[{typeName:e,permission:an(t.permissions.gql)}]:[]),k=new Set(ee.map(e=>e.typeName)),ne=T.filter(e=>!k.has(e.typeName));if(s.newline(),s.info(`Namespace: ${c.bold(o.namespace)}`),s.log(` Current migration: ${_===null?`<unset>`:c.bold(L(_))}`),s.log(` Target migration: ${c.bold(L(t))}`),s.log(` Tables to create: ${c.bold(String(x.length))}`),s.log(` Tables to update: ${c.bold(String(C.length))}`),s.log(` Tables to delete: ${c.bold(String(w.length))}`),s.log(` GQL permissions to set: ${c.bold(String(ee.length))}`),s.log(` GQL permissions to delete: ${c.bold(String(ne.length))}`),s.newline(),x.length+C.length+w.length+ee.length+ne.length===0?s.info(`No tables to apply; only the migration label will be updated.`):(s.warn(`This operation will overwrite remote TailorDB tables to match the selected snapshot.`),w.length>0&&s.warn(`Existing data in deleted tables will be lost.`),s.newline()),s.warn(`Sync never runs migrate.ts scripts; it only applies the schema snapshot and moves the migration label.`),s.newline(),_!==null&&t<_?(s.warn(`Migrations ${L(t+1)}–${L(_)} will become pending again and re-execute on the next deploy, including their migrate.ts scripts. Make sure those scripts are idempotent (safe to re-run).`),s.newline()):_!==null&&t>_&&(s.warn(`Moving the migration label forwards (${L(_)} → ${L(t)}): migrate.ts scripts for migrations ${L(_+1)}–${L(t)} will not run on the next deploy.`),s.newline()),!e.yes){if(!await z.confirm({message:`Continue and set migration label to ${L(t)}?`,default:!1})){s.info(`Operation cancelled.`);return}s.newline()}let re=y(d,f),manifestFor=e=>{let t=re.get(e);if(!t)throw Error(`Internal error: no manifest generated for table "${e}". No changes were applied.`);return t},ie=x.map(e=>manifestFor(e)),ae=C.map(e=>manifestFor(e));try{await Promise.all([...ie.map(e=>m.createTailorDBType({workspaceId:h,namespaceName:o.namespace,tailordbType:e})),...ae.map(e=>m.updateTailorDBType({workspaceId:h,namespaceName:o.namespace,tailordbType:e}))])}catch(e){Nt(e,[`The target snapshot marks a field as required, but existing remote records have no value for it.`,`Populate those records first (e.g. with a migration script applied via 'tailor deploy'), then re-run the sync.`])}await Promise.all(ee.map(({typeName:e,permission:t})=>{let n={workspaceId:h,namespaceName:o.namespace,typeName:e,permission:t};return E.has(e)?m.updateTailorDBGQLPermission(n):m.createTailorDBGQLPermission(n)})),await Promise.all(ne.map(e=>m.deleteTailorDBGQLPermission({workspaceId:h,namespaceName:o.namespace,typeName:e.typeName}))),await Promise.all(w.map(e=>m.deleteTailorDBType({workspaceId:h,namespaceName:o.namespace,tailordbTypeName:e}))),await Xe(m,{trn:g,labels:{[ut]:Wt(t),...d.rebaseline?.historyId?{[u]:d.rebaseline.historyId}:{}},remove:d.rebaseline?.historyId?void 0:[u]}),s.success(`Synced namespace ${c.bold(o.namespace)} to migration ${c.bold(L(t))}.`),t<l&&(s.newline(),s.info(`Run 'tailor deploy' to apply migrations ${L(t+1)}–${L(l)} from the working tree.`))}const Ia=g({name:`sync`,description:`Sync remote TailorDB schema to a specific migration snapshot (recovery from --no-schema-check drift).`,args:J.strictObject({...k,...F,number:G(J.string(),{positional:!0,description:`Migration number to sync to (e.g., 0001 or 1; 0 targets the baseline snapshot)`}),namespace:G(J.string().optional(),{alias:`n`,description:`Target TailorDB namespace (required if multiple namespaces exist)`})}),run:async e=>{await I({profile:e.profile}),await sync({configPath:e.config,number:e.number,namespace:e.namespace,yes:e.yes,workspaceId:e[`workspace-id`],profile:e.profile})}});function delay(e){return e>0?new Promise(t=>setTimeout(t,e)):Promise.resolve()}function assertSeedDataDirectory(e){let t;try{t=X.statSync(e)}catch(t){throw t.code===`ENOENT`?Error(`Seed data directory not found: ${e}. Run 'tailor generate' before testing migrations.`,{cause:t}):t}if(!t.isDirectory())throw Error(`Seed data path is not a directory: ${e}`)}function assertAssertionScript(e){let t=W.resolve(e),n;try{n=X.statSync(t)}catch(e){throw e.code===`ENOENT`?Error(`Migration assertion script not found: ${t}`,{cause:e}):e}if(!n.isFile())throw Error(`Migration assertion path is not a file: ${t}`)}function assertCloneTargetRegion(e,t){if(e!==t)throw Error(`Clone mode requires source and target workspaces in the same region (source: ${e}, target: ${t}).`)}function assertTargetWorkspaceDiffers(e,t){if(t?.toLowerCase()===e.toLowerCase())throw Error(`The migration test target workspace must differ from the source workspace.`)}function resolveAssertionNamespace(e,t){let n=t??(e.length===1?e[0]:void 0);if(!n)throw Error(`--assert-namespace is required when pending migrations span multiple namespaces.`);if(!e.includes(n))throw Error(`Assertion namespace "${n}" has no pending migrations.`);return n}async function createMigrationTestBaselineSnapshots(e){let t=new Map([...e.baselines].map(([e,t])=>[e,t.snapshot]));if(e.dataMode!==`clone`)return t;let n=e.inputs.filter(e=>!t.has(e.namespace)),r=await Promise.all(n.map(t=>ot(e.client,e.workspaceId,t.namespace)));return n.forEach((e,n)=>{t.set(e.namespace,o(r[n],`remote snapshot missing for "${e.namespace}"`))}),t}async function waitForCloneApplicationData(e,n){let r=n.pollInterval??1e3,i=n.timeout??3e5,a=Date.now()+i;for(;Date.now()<=a;){let i=await e.getCloneApplicationDataOperation({sourceWorkspaceId:n.sourceWorkspaceId,targetWorkspaceId:n.targetWorkspaceId,operationId:n.operationId});if(i.status===t.COMPLETED)return;if(i.status===t.FAILED)throw Error(`Application data clone failed: ${i.errorMessage||`unknown platform error`}`);if(i.status!==t.PENDING&&i.status!==t.PROCESSING)throw Error(`Application data clone returned unexpected status ${i.status}.`);await delay(r)}throw Error(`Application data clone timed out after ${Math.round(i/1e3)} seconds.`)}function loadSnapshotSeedData(e,t,n){let r={};for(let i of t){let t=n?.tables[i],a=W.join(e,`${i}.jsonl`),o;try{o=X.readFileSync(a,`utf8`).trim()}catch(e){if(e.code===`ENOENT`){r[i]=[];continue}throw e}r[i]=o?o.split(`
1189
- `).map((e,n)=>{let r;try{r=JSON.parse(e)}catch(e){throw Error(`Invalid JSON in ${a} at line ${n+1}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}if(typeof r!=`object`||!r||Array.isArray(r))throw Error(`Invalid seed row in ${a} at line ${n+1}: expected a JSON object`);let i=r;return t?projectSeedObject(i,t.fields,new Set([`id`])):i}):[]}return r}function projectSeedObject(e,t,n=new Set){return Object.fromEntries(Object.entries(e).flatMap(([e,r])=>{let i=t[e];return i?[[e,projectSeedValue(r,i)]]:n.has(e)?[[e,r]]:[]}))}function projectSeedValue(e,t){let n=t.fields;return n?t.array?Array.isArray(e)?e.map(e=>isJsonObject(e)?projectSeedObject(e,n):e):e:isJsonObject(e)?projectSeedObject(e,n):e:e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function sortSeedTypesForSnapshot(e){let t=Object.keys(e.tables),n=new Set(t),r=new Map,i=[];for(let[t,a]of Object.entries(e.tables)){let e=new Set;for(let r of Object.values(a.fields)){let a=r.foreignKeyType;a&&(a===t?i.push(t):n.has(a)&&e.add(a))}r.set(t,[...e])}let a=new Set,o=[],visit=e=>{if(!a.has(e)){a.add(e);for(let t of r.get(e)??[])visit(t);o.push(e)}};for(let e of t)visit(e);return{order:o,selfRefTypes:i}}function temporaryWorkspaceName(){return`migration-test-${new Date().toISOString().replace(/[-:T.Z]/g,``).slice(0,14)}-${Tr(3).toString(`hex`)}`}function stateOrThrow(e){return o(e,`migration test runtime was used before preparation`)}async function assertSourceBaselineFresh(e,t,n){let r=e.loaded,i=S(r.config,W.dirname(r.config.path)),a=r.application.tailorDBServices.map(At),o=(await vt(e.client,n,i,r.config,a)).find(e=>e.hasDrift||e.checkpointMissingLocal||e.checkpointRepair);if(o)throw Error(`Source namespace "${o.namespace}" changed after migration test preparation. Run the migration test again.`);for(let r of i){let i=t.baselines.get(r.namespace);if(!i)continue;let a=await Pe(e.client,R(n,`tailordb`,r.namespace));if(a!==i.migrationNumber)throw Error(`Source namespace "${r.namespace}" moved from migration ${i.migrationNumber} to ${a??`none`} after migration test preparation. Run the migration test again.`)}let s=a.filter(e=>!t.baselines.has(e.namespace));for(let r of s){let i=t.baselineSnapshots.get(r.namespace);if(!i)continue;let a=await ot(e.client,n,r.namespace);if(et(i,a).changes.length>0)throw Error(`Source namespace "${r.namespace}" schema changed after migration test preparation. Run the migration test again.`)}}async function deleteExistingUserProfileConfig(e,t){let n=e.loaded.application.authService;if(!n)return;let r=n.config.name;await Sn(()=>e.client.getUserProfileConfig({workspaceId:t,namespaceName:r}))&&await e.client.deleteUserProfileConfig({workspaceId:t,namespaceName:r})}function migrationConfig(e,t){return e.config.db?.[t]?.migration}function authExecutionContext(e,t,n){let r=e.loaded.application.authService;if(!r)throw Error(`Auth configuration is required to execute migration test scripts.`);let i=n??ht(migrationConfig(e.loaded,t),r.config.machineUsers?Object.keys(r.config.machineUsers):void 0);if(!i)throw Error(`No machine user is available for namespace "${t}". Pass --machine-user or configure one in auth or db.${t}.migration.`);return{authNamespace:r.config.name,machineUserName:i}}async function prepareMigrationTest(e){let t=await un({configPath:e.configPath}),n=W.dirname(t.config.path),r=S(t.config,n);if(r.length===0)throw Error(`No TailorDB services with migrations configuration found.`);for(let e of r)O(e.migrationsDir,e.namespace);let i;e.data===`seed`&&(i=await ge({configPath:t.config.path}),assertSeedDataDirectory(W.join(i.distPath,`data`))),e.assertionPath&&assertAssertionScript(e.assertionPath);let a=t.application.tailorDBServices.map(At),s=await D({profile:e.profile}),c=await p({profile:e.profile}),l=await H(s,c),u=await j({workspaceId:e.workspaceId,profile:e.profile});assertTargetWorkspaceDiffers(u,e.targetWorkspaceId);let[d,f,m]=await Promise.all([l.getWorkspace({workspaceId:u}),l.getApplication({workspaceId:u,applicationName:t.config.name}),e.data===`clone`&&e.targetWorkspaceId?l.getWorkspace({workspaceId:e.targetWorkspaceId}):Promise.resolve(void 0)]),h=o(d.workspace,`source workspace "${u}" not found`);o(f.application,`application "${t.config.name}" not found in source workspace`);let g=m?o(m.workspace,`target workspace "${e.targetWorkspaceId}" not found`):void 0,_=await vt(l,u,r,t.config,a),v=_.find(e=>e.hasDrift||e.checkpointMissingLocal);if(v)throw Error(`Source namespace "${v.namespace}" does not match its migration checkpoint. Run 'tailor tailordb migration validate' first.`);let y=_.find(e=>e.checkpointRepair);if(y)throw Error(`Source namespace "${y.namespace}" has a pending migration checkpoint repair. Run 'tailor deploy' against the source workspace first.`);let b=new Map,x=new Map,C=[];for(let e of r){let t=await Pe(l,R(u,`tailordb`,e.namespace));if(t===null)throw Error(`Source namespace "${e.namespace}" has no sdk-migration checkpoint. Deploy or set its migration checkpoint before testing.`);let n=de(e.migrationsDir);if(t>n)throw Error(`Source namespace "${e.namespace}" is at migration ${t}, but the local history ends at ${n}.`);let r=A(e.migrationsDir,t);if(!r)throw Error(`No migration baseline snapshot found for namespace "${e.namespace}".`);b.set(e.namespace,{migrationNumber:t,snapshot:r,historyId:r.rebaseline?.historyId??null});let i=A(e.migrationsDir,n);if(!i)throw Error(`No target migration snapshot found for namespace "${e.namespace}".`);x.set(e.namespace,i),t<n&&C.push(e.namespace)}if(C.length===0)throw Error(`No pending TailorDB migrations found in the source workspace.`);let w=await createMigrationTestBaselineSnapshots({client:l,workspaceId:u,dataMode:e.data,inputs:a,baselines:b}),T={sourceWorkspaceId:u,sourceApplicationName:t.config.name,temporaryWorkspace:{name:temporaryWorkspaceName(),region:h.region,...h.organizationId?{organizationId:h.organizationId}:{},...h.folderId?{folderId:h.folderId}:{}},baselines:b,baselineSnapshots:w,targetSnapshots:x,pendingNamespaces:C,...g?{designatedTarget:{id:g.id,region:g.region}}:{}};return{state:{client:l,loaded:t,options:e,...i?{seedContext:i}:{}},prepared:T}}function createMigrationTestDependencies(){let e;return{prepare:async t=>{let{state:n,prepared:r}=await prepareMigrationTest(t);return e=n,r},createWorkspace:async t=>{let n=stateOrThrow(e),r=await Ut(n.client,t.temporaryWorkspace);return s.info(`Created temporary workspace ${r.name} (${r.id}).`),{id:r.id,name:r.name}},deployBaseline:async({prepared:t,targetWorkspaceId:n})=>{let r=stateOrThrow(e);await deleteExistingUserProfileConfig(r,n),await Oe({configPath:r.loaded.config.path,profile:r.options.profile,workspaceId:n,yes:!0},t.baselines,t.baselineSnapshots);for(let[e,i]of t.baselines)await Ye(r.client,n,e,i.migrationNumber,i.historyId??void 0)},seedData:async({prepared:t,targetWorkspaceId:n})=>{let r=stateOrThrow(e),i=o(r.seedContext,`seed context missing after migration test preparation`),a=W.join(i.distPath,`data`);assertSeedDataDirectory(a);let s=new Map(r.loaded.application.tailorDBServices.map(e=>{let n=t.baselines.get(e.namespace),r=At(e);return[e.namespace,n?.snapshot??qt({version:1,namespace:e.namespace,createdAt:new Date().toISOString(),tables:r.types})]}));for(let[e,t]of s){let{order:o,selfRefTypes:s}=sortSeedTypesForSnapshot(t),c=loadSnapshotSeedData(a,o,t),l=o.filter(e=>(c[e]?.length??0)>0);if(l.length===0)continue;let u=await Te(e,l,W.dirname(r.loaded.config.path)),d=ve({data:c,order:o,codeByteSize:new TextEncoder().encode(u.bundledCode).length}),f=authExecutionContext(r,e,r.options.machineUser??i.machineUserName);for(let t of d){let i=await nn({client:r.client,workspaceId:n,name:`migration-test-seed-${e}.ts`,code:u.bundledCode,arg:{data:t.data,order:t.order,selfRefTypes:s,upsert:!1},invoker:{namespace:f.authNamespace,machineUserName:f.machineUserName}});if(!i.success)throw Error(i.error??`Seed execution failed for namespace "${e}".`);if(JSON.parse(i.result||`{}`).success!==!0)throw Error(`Seed execution reported failure for namespace "${e}".`)}}},cloneData:async({prepared:t,sourceWorkspaceId:n,targetWorkspaceId:r,applicationName:i})=>{let a=stateOrThrow(e);await assertSourceBaselineFresh(a,t,n),s.warn(`Clone mode copies TailorDB records only; IdP users and file blobs are not copied.`);let o;try{o=(await a.client.cloneApplicationData({sourceWorkspaceId:n,sourceApplicationName:i,targetWorkspaceId:r,targetApplicationName:i})).operationId}catch(e){throw e instanceof Q&&e.code===Z.Unimplemented?Error(`Application data clone is not enabled for this platform. Retry with '--data seed'.`,{cause:e}):e}if(!o)throw Error(`Application data clone returned no operation ID.`);await waitForCloneApplicationData(a.client,{sourceWorkspaceId:n,targetWorkspaceId:r,operationId:o})},deployMigrations:async({prepared:t,targetWorkspaceId:n})=>{let r=stateOrThrow(e);await d({configPath:r.loaded.config.path,profile:r.options.profile,workspaceId:n,yes:!0},t.targetSnapshots)},runAssertion:async({prepared:t,targetWorkspaceId:n,assertionPath:r,assertionNamespace:i,machineUser:a})=>{let o=stateOrThrow(e),s=resolveAssertionNamespace(t.pendingNamespaces,i),c=authExecutionContext(o,s,a),l=await ln(r,s,0,o.loaded.config.env??{},W.dirname(o.loaded.config.path)),u=await nn({client:o.client,workspaceId:n,name:`migration-test-assert-${s}.ts`,code:l.bundledCode,invoker:{namespace:c.authNamespace,machineUserName:c.machineUserName}});if(!u.success)throw Error(u.error??`Migration assertion failed for namespace "${s}".`)},deleteWorkspace:async t=>{await stateOrThrow(e).client.deleteWorkspace({workspaceId:t})}}}async function runMigrationTest(e,t=createMigrationTestDependencies()){if(e.targetWorkspaceId&&!e.yes)throw Error(`--target-workspace-id requires --yes because the target may be overwritten.`);if(e.keep&&e.targetWorkspaceId)throw Error(`--keep applies only to automatically created workspaces; a designated target is always retained.`);if(e.assertionNamespace&&!e.assertionPath)throw Error(`--assert is required when --assert-namespace is provided.`);let n=await t.prepare(e);if(assertTargetWorkspaceDiffers(n.sourceWorkspaceId,e.targetWorkspaceId),e.assertionPath&&resolveAssertionNamespace(n.pendingNamespaces,e.assertionNamespace),e.data===`clone`&&e.targetWorkspaceId){let e=o(n.designatedTarget,`designated clone target was not loaded during preparation`);assertCloneTargetRegion(n.temporaryWorkspace.region,e.region)}let r=e.targetWorkspaceId===void 0,i=r?await t.createWorkspace(n):{id:o(e.targetWorkspaceId,`designated target workspace missing`),name:void 0},a,c=!1,l=!1;try{let r={prepared:n,targetWorkspaceId:i.id};await t.deployBaseline(r);let a={...r,sourceWorkspaceId:n.sourceWorkspaceId,applicationName:n.sourceApplicationName};e.data===`clone`?await t.cloneData(a):await t.seedData(a),await t.deployMigrations(r),e.assertionPath&&await t.runAssertion({...r,assertionPath:e.assertionPath,assertionNamespace:e.assertionNamespace,machineUser:e.machineUser})}catch(e){a=e,c=!0}if(r&&e.keep)s.info(`Keeping temporary workspace ${i.name??i.id}.`);else if(r)try{await t.deleteWorkspace(i.id),l=!0}catch(e){if(!c)throw Error(`Failed to delete temporary workspace ${i.id}: ${e instanceof Error?e.message:String(e)}`,{cause:e});s.warn(`Failed to delete temporary workspace ${i.id}: ${e instanceof Error?e.message:String(e)}`)}if(c)throw a;return{success:!0,workspaceId:i.id,...i.name?{workspaceName:i.name}:{},temporary:r,deleted:l,data:e.data,pendingNamespaces:n.pendingNamespaces}}async function migrationTest(e){P(`tailordb migration`);let t=await runMigrationTest(e);if(e.json){s.out(t);return}s.success(`Pending migrations completed in workspace ${t.workspaceName??t.workspaceId}.`)}const La=g({name:`test`,description:`Test pending migrations with seed fixtures or cloned data in a temporary workspace.`,notes:`The source workspace is read-only. Without --target-workspace-id, the command creates a workspace in the source workspace's region and deletes it after success or failure; pass --keep to retain it for inspection. A designated target is retained and requires --yes. Clone mode copies TailorDB records only; it does not copy IdP users or file blobs.`,args:J.strictObject({...k,yes:G(J.boolean().default(!1),{alias:`y`,description:`Acknowledge that a designated target workspace may be overwritten`}),data:G(J.enum([`seed`,`clone`]).default(`seed`),{description:`Data source for the migration test (seed or clone)`}),"target-workspace-id":G(J.uuid().optional(),{description:`Existing throwaway workspace to retain after the test (requires --yes)`}),keep:G(J.boolean().default(!1),{description:`Keep the automatically created workspace after the test`}),assert:G(J.string().optional(),{description:`Path to a TypeScript assertion script to run after migrations`,completion:{type:`file`,extensions:[`ts`]}}),"assert-namespace":G(J.string().optional(),{description:`TailorDB namespace exposed to the assertion script`}),"machine-user":G(J.string().optional(),{description:`Machine user for seed and assertion script execution`})}),run:async e=>{await I({profile:e.profile}),await migrationTest({configPath:e.config,workspaceId:e[`workspace-id`],profile:e.profile,data:e.data,targetWorkspaceId:e[`target-workspace-id`],keep:e.keep,assertionPath:e.assert,assertionNamespace:e[`assert-namespace`],machineUser:e[`machine-user`],yes:e.yes,json:s.jsonMode})}});function assertMigrationScriptsReady(e,t,n){let r=[],i=[],a=[],o=[];for(let t of Ue(e)){if(t.type!==`diff`)continue;let n=Ke(t.path),s=se(e,t.number,`migrate`),c=X.existsSync(s);n.requiresMigrationScript&&!n.scriptSkipped&&!c&&r.push(t.number),n.scriptSkipped&&c&&i.push(t.number),c&&X.readFileSync(s,`utf8`).includes(`TODO(tailor-migration-review)`)&&a.push(t.number),n.hasWarnings&&!n.scriptSkipped&&!c&&o.push({migrationNumber:t.number,warnings:n.warnings})}if(r.length>0)throw Error(`Migration(s) ${r.map(L).join(`, `)} in namespace "${t}" require a migration script but have no migrate.ts. Add one with 'tailor tailordb migration script <number>', or record that no script is needed with 'tailor tailordb migration script <number> --no-script --reason "..."'.`);if(i.length>0){let e=i.map(e=>` ${nt({migrationNumber:e,namespace:t,configPath:n})}`).join(`
1190
- `);throw Error(`Migration(s) ${i.map(L).join(`, `)} in namespace "${t}" have both a --no-script skip acknowledgment and migrate.ts. Clear the stale acknowledgment(s):
1191
- ${e}\nOr delete migrate.ts to keep the skip.`)}if(a.length>0)throw Error(`Migration(s) ${a.map(L).join(`, `)} in namespace "${t}" contain generated normalization logic that still requires review in migrate.ts. Review each ${ke} marker, then remove the marker and its associated \`never\` annotation.`);return o}function buildValidationReports(e){let{targetNamespaces:t,migrationFileErrors:n,localResults:r,remoteResults:i,unacknowledgedWarnings:a}=e;return t.map(e=>{let t=n.get(e.namespace);if(t!==void 0)return{namespace:e.namespace,valid:!1,migrationFiles:{valid:!1,error:t}};let s=o(r.find(t=>t.namespace===e.namespace),`local schema check result missing for namespace "${e.namespace}"`),c={hasDiff:s.hasDiff,...s.diff?{diff:s.diff}:{}};if(i===void 0)return{namespace:e.namespace,valid:!1,migrationFiles:{valid:!0},localSchema:c,remoteSchema:{skipped:`check_failed`}};let l=o(i.find(t=>t.namespace===e.namespace),`remote schema check result missing for namespace "${e.namespace}"`),u=l.checkpointMissingLocal===!0,d={remoteMigrationNumber:l.remoteMigrationNumber,hasDrift:l.hasDrift,drifts:l.drifts,...l.skipped?{skipped:l.skipped}:{},...u?{checkpointMissingLocal:!0}:{},...l.checkpointRepair?{checkpointRepair:l.checkpointRepair}:{}},f=a?.get(e.namespace),p;if(f!==void 0){let e=f.filter(e=>e.migrationNumber>l.remoteMigrationNumber);p={valid:e.length===0,missing:e}}return{namespace:e.namespace,valid:!c.hasDiff&&!d.hasDrift&&!u&&p?.valid!==!1,migrationFiles:{valid:!0},localSchema:c,remoteSchema:d,...p?{warningAcknowledgments:p}:{}}})}async function collectValidationReports(e){let{config:t,plugins:n}=await B(e.configPath),r=W.dirname(t.path),i=S(t,r);if(i.length===0)throw Error(`No TailorDB services with migrations configuration found`);let a=e.namespace?i.filter(t=>t.namespace===e.namespace):i;if(a.length===0)throw Error(`Namespace "${e.namespace}" not found or does not have migrations configured`);let o=n.length>0?new at(n):void 0,{defineApplication:s}=await import(`../application-DFOUovmN.mjs`),c=s({config:t,pluginManager:o});for(let e of c.tailorDBServices)await e.loadTypes(),await e.processNamespacePlugins();zn({tailorDBServices:c.tailorDBServices});for(let{namespace:e}of a)if(!c.tailorDBServices.some(t=>t.namespace===e))throw Error(`No TailorDB service found for namespace "${e}"`);let l=c.tailorDBServices.map(At),u=new Map(l.map(e=>[e.namespace,e.types])),d=new Map,f=[],p=e.strict?new Map:void 0;for(let t of a)try{O(t.migrationsDir,t.namespace),A(t.migrationsDir);let n=assertMigrationScriptsReady(t.migrationsDir,t.namespace,e.configPath);p?.set(t.namespace,n),f.push(t)}catch(e){d.set(t.namespace,e instanceof Error?e.message:String(e))}let m={targetNamespaces:a,migrationFileErrors:d,localResults:await $t(u,f),...p?{unacknowledgedWarnings:p}:{}};if(f.length===0)return{reports:buildValidationReports(m)};let h;try{let n=await D({profile:e.profile}),r=await H(n),i=await j({workspaceId:e.workspaceId,profile:e.profile});h=await vt(r,i,f,t,l)}catch(e){return{reports:buildValidationReports(m),remoteError:e}}return{reports:buildValidationReports({...m,remoteResults:h})}}function printValidationReports(e){for(let t of e){if(s.newline(),s.info(`Namespace: ${c.bold(t.namespace)}`),!t.migrationFiles.valid){s.log(` Migration files: ${c.error(`invalid`)}`),s.log(` ${t.migrationFiles.error}`);continue}s.log(` Migration files: ${c.success(`OK`)}`);let e=t.localSchema;e?.hasDiff?e.diff?(s.log(` Local schema: ${c.error(`changes not in migration files`)}`),s.log(` ${en(e.diff)}`),s.log(st(e.diff))):s.log(` Local schema: ${c.error(`no migration snapshot found`)}`):s.log(` Local schema: ${c.success(`OK`)}`);let n=t.remoteSchema;n?.skipped===`check_failed`?s.log(` Remote schema: ${c.error(`not checked`)}`):n?.checkpointRepair?s.log(` Remote schema: ${c.success(`OK`)} (next deploy will reset the checkpoint to 0000 from ${L(n.checkpointRepair.from)})`):n?.checkpointMissingLocal?s.log(` Remote schema: ${c.error(`remote migration ${L(n.remoteMigrationNumber)} is not in the local migration history`)}`):n?.hasDrift?(s.log(` Remote schema: ${c.error(`drift detected`)} (remote migration: ${L(n.remoteMigrationNumber)})`),s.log(_e(n.drifts))):n?.skipped===`not_deployed`?s.log(` Remote schema: ${c.dim(`skipped (namespace not deployed)`)}`):n?.skipped===`no_migration_label`?s.log(` Remote schema: ${c.dim(`skipped (deployed namespace has no migration state)`)}`):n?.skipped===`no_snapshot`?s.log(` Remote schema: ${c.dim(`skipped (no local snapshot for remote migration ${L(n.remoteMigrationNumber)})`)}`):n&&s.log(` Remote schema: ${c.success(`OK`)} (remote migration: ${L(n.remoteMigrationNumber)})`);let r=t.warningAcknowledgments;if(r){if(r.valid)s.log(` Warning acknowledgments: ${c.success(`OK`)}`);else{s.log(` Warning acknowledgments: ${c.error(`missing for pending migration(s) with possible data loss`)}`);for(let e of r.missing){let t=L(e.migrationNumber);for(let n of e.warnings){let e=n.fieldName?`.${n.fieldName}`:``;s.log(` ${t}: ${n.tableName}${e}: ${n.reason}`)}}}}}s.newline()}function printResolutionHints(e,t){e.some(e=>e.localSchema?.hasDiff&&!e.localSchema.diff)&&s.info(`Run 'tailor tailordb migration generate' to create the initial snapshot.`),e.some(e=>e.localSchema?.diff)&&s.info(`Run 'tailor tailordb migration generate' to create migration files.`),e.some(e=>e.remoteSchema?.checkpointMissingLocal)&&s.info(`The remote migration checkpoint is ahead of the local history. Pull the latest migration files, or run 'tailor tailordb migration status' to compare.`),e.some(e=>e.remoteSchema?.hasDrift)&&Lt(e.map(e=>({hasDrift:e.remoteSchema?.hasDrift??!1,drifts:e.remoteSchema?.drifts??[]})));let n=e.filter(e=>e.warningAcknowledgments&&!e.warningAcknowledgments.valid);if(n.length>0){s.info(`For each migration listed, either add a data migration script with 'tailor tailordb migration script <number>' or record why none is needed:`);for(let e of n)for(let n of e.warningAcknowledgments?.missing??[])s.info(` ${nt({migrationNumber:n.migrationNumber,namespace:e.namespace,configPath:t,noScript:!0})}`,{mode:`plain`})}}async function validate(e){P(`tailordb migration`);let t=await collectValidationReports(e),{reports:n}=t,r=n.filter(e=>!e.valid).length;if(e.json?s.out(n):(printValidationReports(n),r===0&&!(`remoteError`in t)?s.success(`All migration validation checks passed.`):printResolutionHints(n,e.configPath)),`remoteError`in t)throw t.remoteError;if(r>0)throw Error(`Migration validation failed for ${r} namespace(s)`)}const Ra=g({name:`validate`,description:`Validate the full migration history, unreviewed generated migration scripts, and schema drift (local tables vs. migration snapshot, remote schema vs. migration checkpoint) without deploying. This includes the migration and schema-drift checks used by 'deploy' and exits with a non-zero code when issues are found.`,args:J.strictObject({...k,namespace:G(J.string().optional(),{alias:`n`,description:`Target TailorDB namespace (validates all namespaces if not specified)`}),strict:G(J.boolean().default(!1),{description:`Also fail when a pending migration can drop data without an acknowledgment`})}),run:async e=>{await validate({configPath:e.config,namespace:e.namespace,workspaceId:e[`workspace-id`],profile:e.profile,json:s.jsonMode,strict:e.strict})}}),za=K({name:`migration`,description:`Manage TailorDB schema migrations.`,subCommands:{generate:ae,rebaseline:Na,script:pe,set:Pa,status:Fa,sync:Ia,test:La,validate:Ra}}),Ba=K({name:`tailordb`,description:`Manage TailorDB tables and data.`,notes:"The `tailordb erd` commands are provided by the @tailor-platform/sdk-plugin-tailordb-erd CLI plugin.",subCommands:{truncate:xt,migration:za}}),Va=g({name:`upgrade`,description:`Run codemods to upgrade your project to a newer SDK version.`,args:J.strictObject({from:G(J.string(),{description:`SDK version before the upgrade (e.g., 1.33.0)`}),"dry-run":G(J.boolean().default(!1),{alias:`d`,description:`Preview changes without modifying files`}),path:G(J.string().default(`.`),{description:`Project directory to upgrade`,completion:{type:`directory`}})}),run:async e=>{let{initTelemetry:t}=await import(`../telemetry-DXHP3VVi.mjs`);await t();let{upgrade:n}=await import(`../service-DlgaUO4V.mjs`);await n({from:e.from,dryRun:e[`dry-run`],path:W.resolve(e.path)})}}),Ha=g({name:`current`,description:`Show current user.`,args:J.strictObject({}),run:async()=>{let e=await M(),t=process.env.TAILOR_PLATFORM_PROFILE,n=t?e.profiles[t]:void 0;if(t&&!n)throw Error(`Profile "${t}" not found`);let r=n?be(n):void 0,i=t?n?.user??null:e.current_user,a=s.jsonMode;if(!i)throw Error(U`
91
+ `),t&&s.out([]);return}let r=n.map(([e,t])=>{let n=o(t,`profile entry "${e}" is undefined`);return{name:e,user:n.user,workspaceId:n.workspace_id,permission:n.readonly===!0?`read`:`write`,...n.machine_user?{machineUser:n.machine_user,machineUserOverride:n.machine_user_override??`allow`}:{},...n.platform_url?{platformUrl:n.platform_url}:{},...n.oauth2_client_id?{oauth2ClientId:n.oauth2_client_id}:{},...n.console_url?{consoleUrl:n.console_url}:{}}});s.out(r)}}),ki=g({name:`update`,description:`Update profile properties.`,args:q.strictObject({name:W(q.string(),{positional:!0,description:`Profile name`}),user:W(q.string().optional(),{alias:`u`,description:`New user email address or machine user client ID`}),"workspace-id":W(q.string().optional(),{alias:`w`,description:`New workspace ID`}),permission:W(q.enum([`write`,`read`]).optional(),{description:`Profile permission. 'read' blocks all write commands; 'write' lifts the restriction.`}),"machine-user":W(q.string().optional(),{alias:`m`,description:`Default machine user name for application-data commands (query, workflow start, function run, machineuser token). Pass an empty string to clear.`}),"machine-user-override":W(q.enum([`allow`,`deny`]).optional(),{description:`Whether the command line or TAILOR_PLATFORM_MACHINE_USER_NAME may override the profile's machine user. 'deny' requires --machine-user; 'allow' lifts the restriction.`}),"platform-url":W(q.union([q.url(),q.literal(``)]).optional(),{description:`Platform API base URL for this profile. Pass an empty string to clear.`}),"oauth2-client-id":W(q.string().optional(),{description:`OAuth2 client ID for logging in to this profile's platform. Pass an empty string to clear.`}),"console-url":W(q.union([q.url(),q.literal(``)]).optional(),{description:`Console base URL for this profile. Pass an empty string to clear.`})}),run:async e=>{let t=await j(),n=t.profiles[e.name];if(!n)throw Error(`Profile "${e.name}" not found.`);if(!e.user&&!e[`workspace-id`]&&e.permission===void 0&&e[`machine-user`]===void 0&&e[`machine-user-override`]===void 0&&e[`platform-url`]===void 0&&e[`oauth2-client-id`]===void 0&&e[`console-url`]===void 0)throw Error(`Please provide at least one property to update.`);let r=n.user,i=e.user||r,a=n.workspace_id,o=e[`workspace-id`]||a,c=i,l=e[`machine-user`]===``?void 0:e[`machine-user`]??n.machine_user,u=e[`machine-user-override`]===`allow`?void 0:e[`machine-user-override`]??n.machine_user_override,d=e[`platform-url`]===``?void 0:e[`platform-url`]??n.platform_url,f=e[`oauth2-client-id`]===``?void 0:e[`oauth2-client-id`]??n.oauth2_client_id,p=e[`console-url`]===``?void 0:e[`console-url`]??n.console_url,m={...d?{platformUrl:d}:{},...f?{oauth2ClientId:f}:{},...p?{consoleUrl:p}:{}},h=Object.keys(m).length>0?m:void 0,g=e[`platform-url`]===``?A(n):h;if((e[`machine-user`]!==void 0||e[`machine-user-override`]!==void 0)&&u===`deny`&&!l)throw e[`machine-user-override`]===`deny`?Error(`--machine-user-override deny requires --machine-user.`):Error(`Cannot clear the machine user while machine-user-override is "deny". Also pass --machine-user-override allow.`);if(e.user!==void 0||e[`workspace-id`]!==void 0||e[`platform-url`]!==void 0){let e=await y(t,i,g);c=e.user;let n=await V(e.accessToken,h);if(!(await mn(async(e,t)=>{let{workspaces:r,nextPageToken:i}=await n.listWorkspaces({pageToken:e,pageSize:t});return[r,i]})).find(e=>e.id===o))throw Error(`Workspace "${o}" not found.`)}n.user=c,n.workspace_id=o,e.permission===`read`?n.readonly=!0:e.permission===`write`&&delete n.readonly,e[`machine-user`]!==void 0&&(e[`machine-user`]===``?delete n.machine_user:n.machine_user=e[`machine-user`]),e[`machine-user-override`]===`deny`?n.machine_user_override=`deny`:e[`machine-user-override`]===`allow`&&delete n.machine_user_override,e[`platform-url`]!==void 0&&(e[`platform-url`]===``?delete n.platform_url:n.platform_url=e[`platform-url`]),e[`oauth2-client-id`]!==void 0&&(e[`oauth2-client-id`]===``?delete n.oauth2_client_id:n.oauth2_client_id=e[`oauth2-client-id`]),e[`console-url`]!==void 0&&(e[`console-url`]===``?delete n.console_url:n.console_url=e[`console-url`]),z(t),e.json||s.success(`Profile "${e.name}" updated successfully`);let _={name:e.name,user:c,workspaceId:o,permission:n.readonly===!0?`read`:`write`,...n.machine_user?{machineUser:n.machine_user,machineUserOverride:n.machine_user_override??`allow`}:{},...n.platform_url?{platformUrl:n.platform_url}:{},...n.oauth2_client_id?{oauth2ClientId:n.oauth2_client_id}:{},...n.console_url?{consoleUrl:n.console_url}:{}};s.out(_)}}),Ai=G({name:`profile`,description:`Manage workspace profiles (user + workspace combinations).`,subCommands:{create:Ei,delete:Di,list:Oi,update:ki},async run(){await K(Oi,[])}}),ji={"vault-name":W(q.string(),{alias:`V`,description:`Vault name`})},Mi={...ji,name:W(q.string(),{alias:`n`,description:`Secret name`})},Ni={...Mi,value:W(q.string(),{alias:`v`,description:`Secret value`})};async function checkVaultManaged(e){let{client:t,workspaceId:n,vaultName:r}=e,i=F(n,`vault`,r),a={isManaged:!1,trn:i,existingLabels:{}},o,c;try{let{metadata:e}=await t.getMetadata({trn:i});c=e?.labels??{},o=c[yt]}catch{return a}return o?(s.warn(`Vault "${r}" is managed by defineSecretManager() in tailor.config.ts (owner: "${o}"). Changes made via CLI may conflict with the config on the next apply.`),{isManaged:!0,trn:i,existingLabels:c}):a}async function releaseVaultOwnership(e){let{client:t,trn:n}=e;await Qe(t,{trn:n,remove:[yt,gt,Mt]}),s.info(`Config ownership has been removed from this vault. Remove it from defineSecretManager() in your config to prevent the next apply from re-claiming it.`)}const Pi=g({name:`create`,description:`Create a secret in a vault.`,args:q.strictObject({...d,...Ni,...M}),run:async e=>{await N({profile:e.profile});let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile}),i=await checkVaultManaged({client:n,workspaceId:r,vaultName:e[`vault-name`]});if(!(i.isManaged&&!e.yes&&!await L.confirm({message:`Do you want to proceed?`,default:!1}))){try{await n.createSecretManagerSecret({workspaceId:r,secretmanagerVaultName:e[`vault-name`],secretmanagerSecretName:e.name,secretmanagerSecretValue:e.value})}catch(t){if(t instanceof Q){if(t.code===Z.NotFound)throw Error(`Vault "${e[`vault-name`]}" not found.`,{cause:t});if(t.code===Z.AlreadyExists)throw Error(`Secret "${e.name}" already exists.`,{cause:t})}throw t}i.isManaged&&await releaseVaultOwnership({client:n,...i}),s.success(`Secret: ${e.name} created in vault: ${e[`vault-name`]}`)}}}),Fi=g({name:`delete`,description:`Delete a secret in a vault.`,args:q.strictObject({...d,...Mi,...M}),run:async e=>{await N({profile:e.profile});let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile}),i=await checkVaultManaged({client:n,workspaceId:r,vaultName:e[`vault-name`]});if(!e.yes&&await L.text({message:`Enter the secret name to confirm deletion ("${e.name}"):`})!==e.name){s.info(`Secret deletion cancelled.`);return}try{await n.deleteSecretManagerSecret({workspaceId:r,secretmanagerVaultName:e[`vault-name`],secretmanagerSecretName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Secret "${e.name}" not found in vault "${e[`vault-name`]}".`,{cause:t}):t}i.isManaged&&await releaseVaultOwnership({client:n,...i}),s.success(`Secret: ${e.name} deleted from vault: ${e[`vault-name`]}`)}});function secretInfo(e){return{name:e.name,createdAt:e.createTime?X(e.createTime):null,updatedAt:e.updateTime?X(e.updateTime):null}}async function secretList(e){let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e.workspaceId,profile:e.profile}),i=Oe(e.order);return(await B(async(t,a)=>{let{secrets:o,nextPageToken:s}=await n.listSecretManagerSecrets({workspaceId:r,secretmanagerVaultName:e.vaultName,pageToken:t,pageSize:a,pageDirection:i});return[o,s]},{limit:e.limit})).map(secretInfo)}const Ii=g({name:`list`,description:`List all secrets in a vault.`,args:q.strictObject({...d,...ji,...Ue()}),run:async e=>{try{let t=await secretList({workspaceId:e[`workspace-id`],profile:e.profile,vaultName:e[`vault-name`],order:e.order,limit:e.limit});s.out(t)}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Vault "${e[`vault-name`]}" not found.`,{cause:t}):t}}}),Li=g({name:`update`,description:`Update a secret in a vault.`,args:q.strictObject({...d,...Ni,...M}),run:async e=>{await N({profile:e.profile});let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile}),i=await checkVaultManaged({client:n,workspaceId:r,vaultName:e[`vault-name`]});if(!(i.isManaged&&!e.yes&&!await L.confirm({message:`Do you want to proceed?`,default:!1}))){try{await n.updateSecretManagerSecret({workspaceId:r,secretmanagerVaultName:e[`vault-name`],secretmanagerSecretName:e.name,secretmanagerSecretValue:e.value})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Secret "${e.name}" not found in vault "${e[`vault-name`]}".`,{cause:t}):t}i.isManaged&&await releaseVaultOwnership({client:n,...i}),s.success(`Secret: ${e.name} updated in vault: ${e[`vault-name`]}`)}}}),Ri={name:W(q.string(),{positional:!0,description:`Vault name`})},zi=g({name:`create`,description:`Create a new Secret Manager vault.`,args:q.strictObject({...d,...Ri}),run:async e=>{await N({profile:e.profile});let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile});try{await n.createSecretManagerVault({workspaceId:r,secretmanagerVaultName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.AlreadyExists?Error(`Vault "${e.name}" already exists.`,{cause:t}):t}s.success(`Vault: ${e.name} created`)}}),Bi=g({name:`delete`,description:`Delete a Secret Manager vault.`,args:q.strictObject({...d,...Ri,...M}),run:async e=>{await N({profile:e.profile});let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile}),i=await checkVaultManaged({client:n,workspaceId:r,vaultName:e.name});if(!e.yes&&await L.text({message:`Enter the vault name to confirm deletion ("${e.name}"):`})!==e.name){s.info(`Vault deletion cancelled.`);return}try{await n.deleteSecretManagerVault({workspaceId:r,secretmanagerVaultName:e.name})}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Vault "${e.name}" not found.`,{cause:t}):t}i.isManaged&&s.info(`Remove this vault from defineSecretManager() in your config to prevent the next apply from re-creating it.`),s.success(`Vault: ${e.name} deleted`)}});function vaultInfo(e){return{name:e.name,createdAt:e.createTime?X(e.createTime):null,updatedAt:e.updateTime?X(e.updateTime):null}}async function vaultList(e){let t=await E({profile:e?.profile}),n=await V(t),r=await k({workspaceId:e?.workspaceId,profile:e?.profile}),i=Oe(e?.order);return(await B(async(e,t)=>{let{vaults:a,nextPageToken:o}=await n.listSecretManagerVaults({workspaceId:r,pageToken:e,pageSize:t,pageDirection:i});return[a,o]},{limit:e?.limit})).map(vaultInfo)}const Vi=g({name:`list`,description:`List all Secret Manager vaults in the workspace.`,args:q.strictObject({...d,...Ue()}),run:async e=>{let t=await vaultList({workspaceId:e[`workspace-id`],profile:e.profile,order:e.order,limit:e.limit});s.out(t)}}),Hi=G({name:`vault`,description:`Manage Secret Manager vaults.`,subCommands:{create:zi,delete:Bi,list:Vi},async run(){await K(Vi,[])}}),Ui=G({name:`secret`,description:`Manage Secret Manager vaults and secrets.`,subCommands:{vault:Hi,create:Pi,update:Li,list:Ii,delete:Fi},async run(){await K(Hi,[])}}),Wi={[t.UNSPECIFIED]:`unspecified`,[t.PENDING]:`pending`,[t.VERIFYING]:`verifying`,[t.CERT_ISSUED]:`cert_issued`,[t.ACTIVE]:`active`,[t.FAILED]:`failed`},Gi=g({name:`get`,description:`Get details of a custom domain.`,args:q.strictObject({...d,domain:W(q.string(),{positional:!0,description:`Custom domain name`})}),run:async e=>{let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile}),i=`Custom domain "${e.domain}" not found.`;try{let{customDomain:t}=await n.getCustomDomain({workspaceId:r,domain:e.domain});if(!t)throw Error(i);let a={domain:t.domain,status:Wi[t.status]??`unknown`,trafficCnameTarget:t.trafficCnameTarget,certificateCnameTarget:t.certificateCnameTarget,errorMessage:t.errorMessage||void 0};s.out(a)}catch(e){throw e instanceof Q&&e.code===Z.NotFound?Error(i,{cause:e}):e}}}),Ki=g({name:`list`,description:`List custom domains for a static website.`,args:q.strictObject({...d,name:W(q.string(),{positional:!0,description:`Static website name`})}),run:async e=>{let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile});try{let{customDomains:t}=await n.listCustomDomains({workspaceId:r,staticWebsiteName:e.name});if(t.length===0){s.info(`No custom domains found.`),s.jsonMode&&s.out([]);return}let i=t.map(e=>({domain:e.domain,status:Wi[e.status]??`unknown`,trafficCnameTarget:e.trafficCnameTarget,certificateCnameTarget:e.certificateCnameTarget}));s.out(i)}catch(t){throw t instanceof Q&&t.code===Z.NotFound?Error(`Static website "${e.name}" not found.`,{cause:t}):t}}}),qi=G({name:`domain`,description:`Manage custom domains for static websites.`,subCommands:{list:Ki,get:Gi}}),Ji=g({name:`get`,description:`Get details of a specific static website.`,args:q.strictObject({...d,name:W(q.string(),{positional:!0,description:`Static website name`})}),run:async e=>{let t=await E({profile:e.profile}),n=await V(t),r=await k({workspaceId:e[`workspace-id`],profile:e.profile}),i=`Static website "${e.name}" not found.`;try{let{staticwebsite:t}=await n.getStaticWebsite({workspaceId:r,name:e.name});if(!t)throw Error(i);let a={workspaceId:r,name:t.name,description:t.description,url:t.url,allowedIpAddresses:e.json?t.allowedIpAddresses:t.allowedIpAddresses.join(`
92
+ `)};s.out(a)}catch(e){throw e instanceof Q&&e.code===Z.NotFound?Error(i,{cause:e}):e}}});async function listStaticWebsites(e){let t=await E({profile:e?.profile}),n=await V(t),r=await k({workspaceId:e?.workspaceId,profile:e?.profile}),i=Oe(e?.order);return(await B(async(e,t)=>{let{staticwebsites:a,nextPageToken:o}=await n.listStaticWebsites({workspaceId:r,pageToken:e,pageSize:t,pageDirection:i});return[a,o]},{limit:e?.limit})).map(e=>({workspaceId:r,name:e.name,description:e.description,url:e.url,allowedIpAddresses:e.allowedIpAddresses}))}const Yi=g({name:`list`,description:`List all static websites in a workspace.`,args:q.strictObject({...d,...Ue()}),run:async e=>{let t=s.jsonMode,n=await listStaticWebsites({workspaceId:e[`workspace-id`],profile:e.profile,order:e.order,limit:e.limit}),r=t?n:n.map(({allowedIpAddresses:e,...t})=>{if(e.length===0)return{...t,allowedIpAddresses:`No allowed IP addresses`};let n=e.length,r=n===1?`1 IP address`:`${n} IP addresses`;return{...t,allowedIpAddresses:r}});s.out(r)}}),Xi=G({name:`staticwebsite`,description:`Manage static websites in your workspace.`,subCommands:{deploy:ze,domain:qi,list:Yi,get:Ji},async run(){await K(Yi,[])}}),Zi=new Set(Object.values(ie));async function activateBaseline(e,t,n,r){let i=await $.realpath(e),a=U.dirname(i),o=U.basename(i),c=await $.mkdtemp(U.join(a,`.${o}-rebaseline-`)),l=`${c}-previous`,u=!1,d=!1;try{await $.cp(i,c,{recursive:!0});for(let e of await $.readdir(c,{withFileTypes:!0})){if(!e.isDirectory()||!Le.test(e.name))continue;let t=U.join(c,e.name);(await $.readdir(t)).some(e=>Zi.has(e))&&await $.rm(t,{recursive:!0,force:!0})}let e={...t,namespace:n,version:5,createdAt:new Date().toISOString(),rebaseline:r},a=await dn(e,c,0);De(a.filePath),await $.rename(i,l),u=!0;try{await $.rename(c,i),d=!0}catch(e){throw await $.rename(l,i),u=!1,e}try{await $.rm(l,{recursive:!0,force:!0})}catch(e){s.warn(`The previous migration directory remains at ${l}: ${e instanceof Error?e.message:String(e)}`)}u=!1}finally{Y.existsSync(c)&&await $.rm(c,{recursive:!0,force:!0}),!d&&u&&Y.existsSync(l)&&await $.rename(l,i)}}async function rebaseline(e){h(`tailordb migration`);let{config:t,plugins:n}=await R(e.configPath),r=U.dirname(t.path),i=Ce(x(t,r),e.namespace),a=Yn({command:`tailor`,args:[`tailordb`,`migration`,`generate`,`--config`,t.path]});ee(i.migrationsDir,i.namespace);let o=D(i.migrationsDir);if(!o)throw Error(`No migration history found for namespace "${i.namespace}". Run ${a} first.`);let l=fe(i.migrationsDir),u=D(i.migrationsDir,0)?.rebaseline?.historyId??null,d=p([i])[i.namespace],f=n.length>0?new Xt(n):void 0,{defineApplication:m}=await import(`../application-o09L68wE.mjs`),g=m({config:t,pluginManager:f});for(let e of g.tailorDBServices)await e.loadTypes(),await e.processNamespacePlugins();let _=g.tailorDBServices.find(e=>e.namespace===i.namespace);if(!_)throw Error(`No TailorDB service found for namespace "${i.namespace}"`);let assertLocalTypesReady=()=>{let e=be(_.types,i.namespace),t=xt(o,e.tables,i.namespace);if(pt(t))throw s.error(`Migration history does not reproduce the current local schema for namespace ${c.bold(i.namespace)}:`),s.log(st(t)),Error(`Refusing to re-baseline: the migration history must reproduce the current local schema. Run ${a} first.`)},localSourceFiles=()=>[t.path,...Bn(_.config,r)];assertLocalTypesReady();let v=Tt(localSourceFiles()),y=await E({profile:e.profile}),b=await V(y),S=await k({workspaceId:e.workspaceId,profile:e.profile}),C=[`--config`,t.path,`--workspace-id`,S,...e.profile?[`--profile`,e.profile]:[]],w=Yn({command:`tailor`,args:[`tailordb`,`migration`,`set`,`0`,`--namespace`,i.namespace,...C]}),te=Yn({command:`tailor`,args:[`deploy`,...C]}),assertConnectedWorkspaceReady=async(e,n)=>{let r=await T(b,F(S,`tailordb`,i.namespace)),a=r.number;if(a!==l){let e=a===null?`<unset>`:P(a);throw Error(`The connected workspace must be at the latest migration ${P(l)} before re-baselining; current checkpoint is ${e}.`)}if(r.historyIdInvalid)throw Error(`Refusing to re-baseline: the connected workspace has an invalid migration history marker.`);if(r.historyId!==e)throw Error(n===`confirmation`?`The connected workspace migration history changed while waiting for confirmation. Run the command again.`:`Refusing to re-baseline: the connected workspace does not match the local migration history.`);let o=await Ze(b,S,[i],t,[ht(_)]),c=o[0];if(!c||c.remoteMigrationNumber!==l||c.hasDrift||c.checkpointMissingLocal)throw c?.hasDrift&&(s.error(`Remote schema drift detected:`),s.log(jt(o))),Error(`Refusing to re-baseline: the connected workspace remote schema must match the latest migration.`)};if(await assertConnectedWorkspaceReady(u,`initial`),s.newline(),s.warn(`This will replace the migration history for ${c.bold(i.namespace)}.`),s.log(` Latest migration: ${P(l)}`),s.log(` New history: 0000/schema.json only`),s.log(` migrate.ts and db.ts files will disappear from the working tree.`),s.log(` Committed migration files will remain in Git history. Preserve any uncommitted files before continuing.`),s.log(` Every other environment must already be at the latest migration.`),s.log(` The connected workspace checkpoint will be reset to 0000.`),s.newline(),!e.yes&&!await L.confirm({message:`Re-baseline this migration history and reset the connected workspace checkpoint?`,default:!1})){s.info(`Operation cancelled.`);return}if(ee(i.migrationsDir,i.namespace),p([i])[i.namespace]!==d)throw Error(`Migration files changed while waiting for confirmation. Run the command again.`);if(Tt(localSourceFiles())!==v)throw Error(`Local TailorDB table or config files changed. Run the command again.`);assertLocalTypesReady(),await assertConnectedWorkspaceReady(u,`confirmation`);let ne={historyId:qt(),replacedHistoryId:u,replacedLatestMigration:l};await activateBaseline(i.migrationsDir,o,i.namespace,ne);try{await cn(b,S,i.namespace,0,ne.historyId)}catch(e){throw Error(`The local migration history was re-baselined, but the connected workspace checkpoint could not be updated. Run ${w}, or run ${te} with schema checks enabled after resolving the connection error.`,{cause:e})}s.success(`Re-baselined ${c.bold(i.namespace)} and reset the connected workspace checkpoint to 0000.`)}const Qi=g({name:`rebaseline`,description:`Collapse the full migration history into a new 0000 baseline.`,notes:`Re-baselining removes migrations after 0000 from the working tree, records a new migration history ID, and resets the connected workspace checkpoint without changing its schema or data. Every environment must already have applied the latest migration before you run this command.`,args:q.strictObject({...O,...M,namespace:W(q.string().optional(),{alias:`n`,description:`Target TailorDB namespace (required if multiple namespaces exist)`})}),run:async e=>{await N({profile:e.profile}),await rebaseline({configPath:e.config,namespace:e.namespace,yes:e.yes,workspaceId:e[`workspace-id`],profile:e.profile})}});async function set(e){h(`tailordb migration`);let t=Ot(e.number),{config:n}=await R(e.configPath),r=U.dirname(n.path),i=x(n,r),a=Ce(i,e.namespace),o=a.namespace;ee(a.migrationsDir,o),re(a.migrationsDir,t);let l=D(a.migrationsDir,0)?.rebaseline?.historyId,d=await E({profile:e.profile}),f=await V(d),p=await k({workspaceId:e.workspaceId,profile:e.profile}),m=F(p,`tailordb`,o),g=await T(f,m),_=g.number,v=_??0,y=g.historyIdInvalid?`<invalid>`:g.historyId??`<unset>`,b=l??`<unset>`;if(s.newline(),s.warn(`This operation will change TailorDB migration state metadata.`),s.log(`Namespace: ${c.bold(o)}`),s.log(`Current migration: ${_===null?`<unset>`:c.bold(P(_))}`),s.log(`New migration: ${c.bold(P(t))}`),s.log(`Current migration history ID: ${c.bold(y)}`),s.log(`New migration history ID: ${c.bold(b)}`),s.newline(),t<v?(s.warn(`Setting migration number backwards (${P(v)} → ${P(t)}) will cause previous migrations to be re-executed on next apply.`),s.newline()):t>v&&(s.warn(`Setting migration number forwards (${P(v)} → ${P(t)}) will skip migrations ${P(v+1)} to ${P(t)}.`),s.newline()),!e.yes){if(!await L.confirm({message:`Continue with migration checkpoint and history ID update?`,default:!1})){s.info(`Operation cancelled.`);return}s.newline()}await Qe(f,{trn:m,labels:{[ut]:Vt(t),...l?{[u]:l}:{}},remove:l?void 0:[u]}),s.success(`Migration checkpoint set to ${c.bold(P(t))} for namespace ${c.bold(o)}`)}const $i=g({name:`set`,description:`Set migration checkpoint to a specific number.`,notes:"The migration number must be a 4-digit value (e.g. `0001`) or a bare integer (e.g. `1`) within 0–9999, and must exist in the local migration history; `0` is always accepted as the baseline, provided the local history passes validation. A gapped history is rejected.\n\nMetadata lookup failures (authentication, permission, or network errors) are reported as errors; only a not-yet-deployed namespace is treated as having no checkpoint.",args:q.strictObject({...O,...M,number:W(q.string(),{positional:!0,description:`Migration number to set (e.g., 0001 or 1)`}),namespace:W(q.string().optional(),{alias:`n`,description:`Target TailorDB namespace (required if multiple namespaces exist)`})}),run:async e=>{await N({profile:e.profile}),await set({configPath:e.config,number:e.number,namespace:e.namespace,yes:e.yes,workspaceId:e[`workspace-id`],profile:e.profile})}});function isStatusFailure(e){return e.status===`error`}async function collectMigrationStatuses(e){let{config:t}=await R(e.configPath),n=U.dirname(t.path),r=x(t,n);if(r.length===0)throw Error(`No TailorDB services with migrations configuration found`);let i=e.namespace?r.filter(t=>t.namespace===e.namespace):r;if(i.length===0)throw Error(`Namespace "${e.namespace}" not found or does not have migrations configured`);let a=new Map,o=new Map;for(let{namespace:e,migrationsDir:t}of i)try{let n=Ge(t),r=new Map,i=null;for(let e of n){if(e.type===`schema`){let t=De(e.path);e.number===0&&(i=t.rebaseline?.historyId??null);continue}try{let t=Ye(e.path);t.description&&r.set(e.number,t.description)}catch(e){if(e instanceof It)throw e}}a.set(e,{migrationFiles:n,descriptions:r,historyId:i})}catch(t){o.set(e,t instanceof Error?t.message:String(t))}if(a.size===0)return i.map(({namespace:e})=>({status:`error`,namespace:e,error:o.get(e)??`Failed to read local migration history.`}));let s=await E({profile:e.profile}),c=await V(s),l=await k({workspaceId:e.workspaceId,profile:e.profile}),u=[];for(let{namespace:e}of i){if(o.has(e)){u.push({status:`error`,namespace:e,error:o.get(e)??`Failed to read local migration history.`});continue}let t=a.get(e);if(!t){u.push({status:`error`,namespace:e,error:`Failed to read local migration history.`});continue}let{migrationFiles:n,descriptions:r,historyId:i}=t,s=F(l,`tailordb`,e),d;try{d=await T(c,s)}catch(t){u.push({status:`error`,namespace:e,error:t instanceof Error?t.message:String(t)});continue}let f=d.number??0;if(d.historyIdInvalid){u.push({status:`error`,namespace:e,error:`Remote migration history ID is invalid.`});continue}if((d.number!==null||d.historyId!==null)&&d.historyId!==i){u.push({status:`error`,namespace:e,error:`Remote migration history ID ${d.historyId??`<unset>`} does not match local migration history ID ${i??`<unset>`}.`});continue}let p=n.map(e=>e.number).filter((e,t,n)=>n.indexOf(e)===t).toSorted((e,t)=>e-t).filter(e=>e>f).map(e=>({number:e,label:P(e),...r.has(e)?{description:r.get(e)}:{}}));u.push({status:`ok`,namespace:e,currentMigration:f,currentMigrationLabel:P(f),pendingMigrations:p})}return u}function printMigrationStatuses(e){for(let t of e){if(s.newline(),s.info(`Namespace: ${c.bold(t.namespace)}`),isStatusFailure(t)){s.error(` Migration status error: ${t.error}`);continue}if(s.log(` Current migration: ${c.bold(t.currentMigrationLabel)}`),t.pendingMigrations.length>0){s.log(` Pending migrations:`);for(let e of t.pendingMigrations)e.description?s.log(` - ${e.label}: ${e.description}`):s.log(` - ${e.label}`)}else s.log(` Pending migrations: (none)`)}s.newline()}async function status(e){h(`tailordb migration`);let t=await collectMigrationStatuses(e);e.json?s.out(t):printMigrationStatuses(t);let n=t.filter(isStatusFailure);if(n.length>0){let e=n.map(e=>e.namespace).join(`, `);throw Error(`Migration status check failed for ${n.length} namespace${n.length===1?``:`s`}: ${e}`)}}const ea=g({name:`status`,description:`Show the current migration status for TailorDB namespaces, including applied and pending migrations.`,notes:`Every local migration file is checked for a compatible format version, and deployed migration history IDs must match the local baseline. Compatibility errors, history mismatches, and metadata lookup failures are reported per namespace and make the command exit non-zero; only a not-yet-deployed namespace is treated as having no applied migrations.`,args:q.strictObject({...O,namespace:W(q.string().optional(),{alias:`n`,description:`Target TailorDB namespace (shows all namespaces if not specified)`})}),run:async e=>{await status({configPath:e.config,namespace:e.namespace,workspaceId:e[`workspace-id`],profile:e.profile,json:s.jsonMode})}});async function fetchRemoteGqlPermissions(e,t,n){return wn(async(r,i)=>{let{permissions:a,nextPageToken:o}=await e.listTailorDBGQLPermissions({workspaceId:t,namespaceName:n,pageToken:r,pageSize:i});return[a,o]})}async function fetchRemoteTypes(e,t,n){return mn(async(r,i)=>{try{let{tailordbTypes:a,nextPageToken:o}=await e.listTailorDBTypes({workspaceId:t,namespaceName:n,pageToken:r,pageSize:i});return[a,o]}catch(e){throw e instanceof Q&&e.code===Z.NotFound?Error(`Cannot sync: TailorDB namespace "${n}" has not been deployed yet.`,{cause:e}):e}})}async function assertMigrationsReproduceLocalTypes(e,t){let{config:n,plugins:r}=e,i=r.length>0?new Xt(r):void 0,{defineApplication:a,generatePluginFilesIfNeeded:o}=await import(`../application-o09L68wE.mjs`),l=a({config:n,pluginManager:i}),u=l.tailorDBServices.find(e=>e.namespace===t.namespace);if(!u)throw Error(`No TailorDB service found for namespace "${t.namespace}"`);for(let e of l.tailorDBServices)await e.loadTypes(),await e.processNamespacePlugins();let d=o(i,l.tailorDBServices,n.path),f=l.executorService??(d.length>0?(await import(`../service-COC9whur.mjs`)).createExecutorService({config:{files:[]},baseDir:U.dirname(n.path)}):void 0);await f?.loadExecutors(),d.length>0&&await f?.loadPluginExecutorFiles([...d]);let p=new Set;for(let e of Object.values(f?.executors??{}))e.trigger.kind===`tailordb`&&p.add(e.trigger.tableName);let m={executorUsedTables:p,namespaceGqlOperations:u.config.gqlOperations},h=D(t.migrationsDir);if(!h)return m;let g=be(u.types,t.namespace),_=xt(h,g.tables,t.namespace);if(!pt(_))return m;throw s.error(`Migration history does not reproduce the current local schema for namespace ${c.bold(t.namespace)}:`),s.log(st(_)),s.newline(),s.info(`This usually means one of the following:`),s.info(` - Migration files were edited and replaying them no longer matches the table definitions — fix the migration files.`,{mode:`plain`}),s.info(` - Table definitions changed without a new migration — run 'tailor tailordb migration generate' first.`,{mode:`plain`}),s.newline(),Error(`Refusing to sync: the migration history must reproduce the current local schema before it can be applied to the remote.`)}async function sync(e){h(`tailordb migration`);let t=Ot(e.number),n=await R(e.configPath),{config:r}=n,i=U.dirname(r.path),a=x(r,i),o=Ce(a,e.namespace);ee(o.migrationsDir,o.namespace);let l=re(o.migrationsDir,t),d=D(o.migrationsDir,t);if(!d)throw Error(`No initial schema snapshot found in ${o.migrationsDir}. Expected 0000/schema.json.`);let f=await assertMigrationsReproduceLocalTypes(n,o),p=await E({profile:e.profile}),m=await V(p),g=await k({workspaceId:e.workspaceId,profile:e.profile}),_=F(g,`tailordb`,o.namespace),y=await Pe(m,_),b=await fetchRemoteTypes(m,g,o.namespace),S=new Set(b.map(e=>e.name)),{creates:C,updates:w,deletes:T}=je(d,S),te=await fetchRemoteGqlPermissions(m,g,o.namespace),ne=new Set(te.map(e=>e.typeName)),ie=Object.entries(d.tables).flatMap(([e,t])=>t.permissions?.gql?[{typeName:e,permission:tn(t.permissions.gql)}]:[]),ae=new Set(ie.map(e=>e.typeName)),oe=te.filter(e=>!ae.has(e.typeName));if(s.newline(),s.info(`Namespace: ${c.bold(o.namespace)}`),s.log(` Current migration: ${y===null?`<unset>`:c.bold(P(y))}`),s.log(` Target migration: ${c.bold(P(t))}`),s.log(` Tables to create: ${c.bold(String(C.length))}`),s.log(` Tables to update: ${c.bold(String(w.length))}`),s.log(` Tables to delete: ${c.bold(String(T.length))}`),s.log(` GQL permissions to set: ${c.bold(String(ie.length))}`),s.log(` GQL permissions to delete: ${c.bold(String(oe.length))}`),s.newline(),C.length+w.length+T.length+ie.length+oe.length===0?s.info(`No tables to apply; only the migration label will be updated.`):(s.warn(`This operation will overwrite remote TailorDB tables to match the selected snapshot.`),T.length>0&&s.warn(`Existing data in deleted tables will be lost.`),s.newline()),s.warn(`Sync never runs migrate.ts scripts; it only applies the schema snapshot and moves the migration label.`),s.newline(),y!==null&&t<y?(s.warn(`Migrations ${P(t+1)}–${P(y)} will become pending again and re-execute on the next deploy, including their migrate.ts scripts. Make sure those scripts are idempotent (safe to re-run).`),s.newline()):y!==null&&t>y&&(s.warn(`Moving the migration label forwards (${P(y)} → ${P(t)}): migrate.ts scripts for migrations ${P(y+1)}–${P(t)} will not run on the next deploy.`),s.newline()),!e.yes){if(!await L.confirm({message:`Continue and set migration label to ${P(t)}?`,default:!1})){s.info(`Operation cancelled.`);return}s.newline()}let se=v(d,f),manifestFor=e=>{let t=se.get(e);if(!t)throw Error(`Internal error: no manifest generated for table "${e}". No changes were applied.`);return t},ce=C.map(e=>manifestFor(e)),le=w.map(e=>manifestFor(e));try{await Promise.all([...ce.map(e=>m.createTailorDBType({workspaceId:g,namespaceName:o.namespace,tailordbType:e})),...le.map(e=>m.updateTailorDBType({workspaceId:g,namespaceName:o.namespace,tailordbType:e}))])}catch(e){Pt(e,[`The target snapshot marks a field as required, but existing remote records have no value for it.`,`Populate those records first (e.g. with a migration script applied via 'tailor deploy'), then re-run the sync.`])}await Promise.all(ie.map(({typeName:e,permission:t})=>{let n={workspaceId:g,namespaceName:o.namespace,typeName:e,permission:t};return ne.has(e)?m.updateTailorDBGQLPermission(n):m.createTailorDBGQLPermission(n)})),await Promise.all(oe.map(e=>m.deleteTailorDBGQLPermission({workspaceId:g,namespaceName:o.namespace,typeName:e.typeName}))),await Promise.all(T.map(e=>m.deleteTailorDBType({workspaceId:g,namespaceName:o.namespace,tailordbTypeName:e}))),await Qe(m,{trn:_,labels:{[ut]:Vt(t),...d.rebaseline?.historyId?{[u]:d.rebaseline.historyId}:{}},remove:d.rebaseline?.historyId?void 0:[u]}),s.success(`Synced namespace ${c.bold(o.namespace)} to migration ${c.bold(P(t))}.`),t<l&&(s.newline(),s.info(`Run 'tailor deploy' to apply migrations ${P(t+1)}–${P(l)} from the working tree.`))}const ta=g({name:`sync`,description:`Sync remote TailorDB schema to a specific migration snapshot (recovery from --no-schema-check drift).`,args:q.strictObject({...O,...M,number:W(q.string(),{positional:!0,description:`Migration number to sync to (e.g., 0001 or 1; 0 targets the baseline snapshot)`}),namespace:W(q.string().optional(),{alias:`n`,description:`Target TailorDB namespace (required if multiple namespaces exist)`})}),run:async e=>{await N({profile:e.profile}),await sync({configPath:e.config,number:e.number,namespace:e.namespace,yes:e.yes,workspaceId:e[`workspace-id`],profile:e.profile})}});function delay(e){return e>0?new Promise(t=>setTimeout(t,e)):Promise.resolve()}function assertSeedDataDirectory(e){let t;try{t=Y.statSync(e)}catch(t){throw t.code===`ENOENT`?Error(`Seed data directory not found: ${e}. Run 'tailor generate' before testing migrations.`,{cause:t}):t}if(!t.isDirectory())throw Error(`Seed data path is not a directory: ${e}`)}function assertAssertionScript(e){let t=U.resolve(e),n;try{n=Y.statSync(t)}catch(e){throw e.code===`ENOENT`?Error(`Migration assertion script not found: ${t}`,{cause:e}):e}if(!n.isFile())throw Error(`Migration assertion path is not a file: ${t}`)}function assertCloneTargetRegion(e,t){if(e!==t)throw Error(`Clone mode requires source and target workspaces in the same region (source: ${e}, target: ${t}).`)}function assertTargetWorkspaceDiffers(e,t){if(t?.toLowerCase()===e.toLowerCase())throw Error(`The migration test target workspace must differ from the source workspace.`)}function resolveAssertionNamespace(e,t){let n=t??(e.length===1?e[0]:void 0);if(!n)throw Error(`--assert-namespace is required when pending migrations span multiple namespaces.`);if(!e.includes(n))throw Error(`Assertion namespace "${n}" has no pending migrations.`);return n}async function createMigrationTestBaselineSnapshots(e){let t=new Map([...e.baselines].map(([e,t])=>[e,t.snapshot]));if(e.dataMode!==`clone`)return t;let n=e.inputs.filter(e=>!t.has(e.namespace)),r=await Promise.all(n.map(t=>Lt(e.client,e.workspaceId,t.namespace)));return n.forEach((e,n)=>{t.set(e.namespace,o(r[n],`remote snapshot missing for "${e.namespace}"`))}),t}async function waitForCloneApplicationData(e,t){let n=t.pollInterval??1e3,i=t.timeout??3e5,a=Date.now()+i;for(;Date.now()<=a;){let i=await e.getCloneApplicationDataOperation({sourceWorkspaceId:t.sourceWorkspaceId,targetWorkspaceId:t.targetWorkspaceId,operationId:t.operationId});if(i.status===r.COMPLETED)return;if(i.status===r.FAILED)throw Error(`Application data clone failed: ${i.errorMessage||`unknown platform error`}`);if(i.status!==r.PENDING&&i.status!==r.PROCESSING)throw Error(`Application data clone returned unexpected status ${i.status}.`);await delay(n)}throw Error(`Application data clone timed out after ${Math.round(i/1e3)} seconds.`)}function loadSnapshotSeedData(e,t,n){let r={};for(let i of t){let t=n?.tables[i],a=U.join(e,`${i}.jsonl`),o;try{o=Y.readFileSync(a,`utf8`).trim()}catch(e){if(e.code===`ENOENT`){r[i]=[];continue}throw e}r[i]=o?o.split(`
93
+ `).map((e,n)=>{let r;try{r=JSON.parse(e)}catch(e){throw Error(`Invalid JSON in ${a} at line ${n+1}: ${e instanceof Error?e.message:String(e)}`,{cause:e})}if(typeof r!=`object`||!r||Array.isArray(r))throw Error(`Invalid seed row in ${a} at line ${n+1}: expected a JSON object`);let i=r;return t?projectSeedObject(i,t.fields,new Set([`id`])):i}):[]}return r}function projectSeedObject(e,t,n=new Set){return Object.fromEntries(Object.entries(e).flatMap(([e,r])=>{let i=t[e];return i?[[e,projectSeedValue(r,i)]]:n.has(e)?[[e,r]]:[]}))}function projectSeedValue(e,t){let n=t.fields;return n?t.array?Array.isArray(e)?e.map(e=>isJsonObject(e)?projectSeedObject(e,n):e):e:isJsonObject(e)?projectSeedObject(e,n):e:e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function sortSeedTypesForSnapshot(e){let t=Object.keys(e.tables),n=new Set(t),r=new Map,i=[];for(let[t,a]of Object.entries(e.tables)){let e=new Set;for(let r of Object.values(a.fields)){let a=r.foreignKeyType;a&&(a===t?i.push(t):n.has(a)&&e.add(a))}r.set(t,[...e])}let a=new Set,o=[],visit=e=>{if(!a.has(e)){a.add(e);for(let t of r.get(e)??[])visit(t);o.push(e)}};for(let e of t)visit(e);return{order:o,selfRefTypes:i}}function temporaryWorkspaceName(){return`migration-test-${new Date().toISOString().replace(/[-:T.Z]/g,``).slice(0,14)}-${xr(3).toString(`hex`)}`}function stateOrThrow(e){return o(e,`migration test runtime was used before preparation`)}async function assertSourceBaselineFresh(e,t,n){let r=e.loaded,i=x(r.config,U.dirname(r.config.path)),a=r.application.tailorDBServices.map(ht),o=(await Ze(e.client,n,i,r.config,a)).find(e=>e.hasDrift||e.checkpointMissingLocal||e.checkpointRepair);if(o)throw Error(`Source namespace "${o.namespace}" changed after migration test preparation. Run the migration test again.`);for(let r of i){let i=t.baselines.get(r.namespace);if(!i)continue;let a=await Pe(e.client,F(n,`tailordb`,r.namespace));if(a!==i.migrationNumber)throw Error(`Source namespace "${r.namespace}" moved from migration ${i.migrationNumber} to ${a??`none`} after migration test preparation. Run the migration test again.`)}let s=a.filter(e=>!t.baselines.has(e.namespace));for(let r of s){let i=t.baselineSnapshots.get(r.namespace);if(!i)continue;let a=await Lt(e.client,n,r.namespace);if(nt(i,a).changes.length>0)throw Error(`Source namespace "${r.namespace}" schema changed after migration test preparation. Run the migration test again.`)}}async function deleteExistingUserProfileConfig(e,t){let n=e.loaded.application.authService;if(!n)return;let r=n.config.name;await vn(()=>e.client.getUserProfileConfig({workspaceId:t,namespaceName:r}))&&await e.client.deleteUserProfileConfig({workspaceId:t,namespaceName:r})}function migrationConfig(e,t){return e.config.db?.[t]?.migration}function authExecutionContext(e,t,n){let r=e.loaded.application.authService;if(!r)throw Error(`Auth configuration is required to execute migration test scripts.`);let i=n??$t(migrationConfig(e.loaded,t),r.config.machineUsers?Object.keys(r.config.machineUsers):void 0);if(!i)throw Error(`No machine user is available for namespace "${t}". Pass --machine-user or configure one in auth or db.${t}.migration.`);return{authNamespace:r.config.name,machineUserName:i}}async function prepareMigrationTest(e){let t=await sn({configPath:e.configPath}),n=U.dirname(t.config.path),r=x(t.config,n);if(r.length===0)throw Error(`No TailorDB services with migrations configuration found.`);for(let e of r)ee(e.migrationsDir,e.namespace);let i;e.data===`seed`&&(i=await ge({configPath:t.config.path}),assertSeedDataDirectory(U.join(i.distPath,`data`))),e.assertionPath&&assertAssertionScript(e.assertionPath);let a=t.application.tailorDBServices.map(ht),s=await E({profile:e.profile}),c=await m({profile:e.profile}),l=await V(s,c),u=await k({workspaceId:e.workspaceId,profile:e.profile});assertTargetWorkspaceDiffers(u,e.targetWorkspaceId);let[d,f,p]=await Promise.all([l.getWorkspace({workspaceId:u}),l.getApplication({workspaceId:u,applicationName:t.config.name}),e.data===`clone`&&e.targetWorkspaceId?l.getWorkspace({workspaceId:e.targetWorkspaceId}):Promise.resolve(void 0)]),h=o(d.workspace,`source workspace "${u}" not found`);o(f.application,`application "${t.config.name}" not found in source workspace`);let g=p?o(p.workspace,`target workspace "${e.targetWorkspaceId}" not found`):void 0,_=await Ze(l,u,r,t.config,a),v=_.find(e=>e.hasDrift||e.checkpointMissingLocal);if(v)throw Error(`Source namespace "${v.namespace}" does not match its migration checkpoint. Run 'tailor tailordb migration validate' first.`);let y=_.find(e=>e.checkpointRepair);if(y)throw Error(`Source namespace "${y.namespace}" has a pending migration checkpoint repair. Run 'tailor deploy' against the source workspace first.`);let b=new Map,S=new Map,C=[];for(let e of r){let t=await Pe(l,F(u,`tailordb`,e.namespace));if(t===null)throw Error(`Source namespace "${e.namespace}" has no sdk-migration checkpoint. Deploy or set its migration checkpoint before testing.`);let n=fe(e.migrationsDir);if(t>n)throw Error(`Source namespace "${e.namespace}" is at migration ${t}, but the local history ends at ${n}.`);let r=D(e.migrationsDir,t);if(!r)throw Error(`No migration baseline snapshot found for namespace "${e.namespace}".`);b.set(e.namespace,{migrationNumber:t,snapshot:r,historyId:r.rebaseline?.historyId??null});let i=D(e.migrationsDir,n);if(!i)throw Error(`No target migration snapshot found for namespace "${e.namespace}".`);S.set(e.namespace,i),t<n&&C.push(e.namespace)}if(C.length===0)throw Error(`No pending TailorDB migrations found in the source workspace.`);let w=await createMigrationTestBaselineSnapshots({client:l,workspaceId:u,dataMode:e.data,inputs:a,baselines:b}),T={sourceWorkspaceId:u,sourceApplicationName:t.config.name,temporaryWorkspace:{name:temporaryWorkspaceName(),region:h.region,...h.organizationId?{organizationId:h.organizationId}:{},...h.folderId?{folderId:h.folderId}:{}},baselines:b,baselineSnapshots:w,targetSnapshots:S,pendingNamespaces:C,...g?{designatedTarget:{id:g.id,region:g.region}}:{}};return{state:{client:l,loaded:t,options:e,...i?{seedContext:i}:{}},prepared:T}}function createMigrationTestDependencies(){let e;return{prepare:async t=>{let{state:n,prepared:r}=await prepareMigrationTest(t);return e=n,r},createWorkspace:async t=>{let n=stateOrThrow(e),r=await tt(n.client,t.temporaryWorkspace);return s.info(`Created temporary workspace ${r.name} (${r.id}).`),{id:r.id,name:r.name}},deployBaseline:async({prepared:t,targetWorkspaceId:n})=>{let r=stateOrThrow(e);await deleteExistingUserProfileConfig(r,n),await lt({configPath:r.loaded.config.path,profile:r.options.profile,workspaceId:n,yes:!0},t.baselines,t.baselineSnapshots);for(let[e,i]of t.baselines)await cn(r.client,n,e,i.migrationNumber,i.historyId??void 0)},seedData:async({prepared:t,targetWorkspaceId:n})=>{let r=stateOrThrow(e),i=o(r.seedContext,`seed context missing after migration test preparation`),a=U.join(i.distPath,`data`);assertSeedDataDirectory(a);let s=new Map(r.loaded.application.tailorDBServices.map(e=>{let n=t.baselines.get(e.namespace),r=ht(e);return[e.namespace,n?.snapshot??I({version:1,namespace:e.namespace,createdAt:new Date().toISOString(),tables:r.types})]}));for(let[e,t]of s){let{order:o,selfRefTypes:s}=sortSeedTypesForSnapshot(t),c=loadSnapshotSeedData(a,o,t),l=o.filter(e=>(c[e]?.length??0)>0);if(l.length===0)continue;let u=await Te(e,l,U.dirname(r.loaded.config.path)),d=ye({data:c,order:o,codeByteSize:new TextEncoder().encode(u.bundledCode).length}),f=authExecutionContext(r,e,r.options.machineUser??i.machineUserName);for(let t of d){let i=await Ie({client:r.client,workspaceId:n,name:`migration-test-seed-${e}.ts`,code:u.bundledCode,arg:{data:t.data,order:t.order,selfRefTypes:s,upsert:!1},invoker:{namespace:f.authNamespace,machineUserName:f.machineUserName}});if(!i.success)throw Error(i.error??`Seed execution failed for namespace "${e}".`);if(JSON.parse(i.result||`{}`).success!==!0)throw Error(`Seed execution reported failure for namespace "${e}".`)}}},cloneData:async({prepared:t,sourceWorkspaceId:n,targetWorkspaceId:r,applicationName:i})=>{let a=stateOrThrow(e);await assertSourceBaselineFresh(a,t,n),s.warn(`Clone mode copies TailorDB records only; IdP users and file blobs are not copied.`);let o;try{o=(await a.client.cloneApplicationData({sourceWorkspaceId:n,sourceApplicationName:i,targetWorkspaceId:r,targetApplicationName:i})).operationId}catch(e){throw e instanceof Q&&e.code===Z.Unimplemented?Error(`Application data clone is not enabled for this platform. Retry with '--data seed'.`,{cause:e}):e}if(!o)throw Error(`Application data clone returned no operation ID.`);await waitForCloneApplicationData(a.client,{sourceWorkspaceId:n,targetWorkspaceId:r,operationId:o})},deployMigrations:async({prepared:t,targetWorkspaceId:n})=>{let r=stateOrThrow(e);await Kt({configPath:r.loaded.config.path,profile:r.options.profile,workspaceId:n,yes:!0},t.targetSnapshots)},runAssertion:async({prepared:t,targetWorkspaceId:n,assertionPath:r,assertionNamespace:i,machineUser:a})=>{let o=stateOrThrow(e),s=resolveAssertionNamespace(t.pendingNamespaces,i),c=authExecutionContext(o,s,a),l=await on(r,s,0,o.loaded.config.env??{},U.dirname(o.loaded.config.path)),u=await Ie({client:o.client,workspaceId:n,name:`migration-test-assert-${s}.ts`,code:l.bundledCode,invoker:{namespace:c.authNamespace,machineUserName:c.machineUserName}});if(!u.success)throw Error(u.error??`Migration assertion failed for namespace "${s}".`)},deleteWorkspace:async t=>{await stateOrThrow(e).client.deleteWorkspace({workspaceId:t})}}}async function runMigrationTest(e,t=createMigrationTestDependencies()){if(e.targetWorkspaceId&&!e.yes)throw Error(`--target-workspace-id requires --yes because the target may be overwritten.`);if(e.keep&&e.targetWorkspaceId)throw Error(`--keep applies only to automatically created workspaces; a designated target is always retained.`);if(e.assertionNamespace&&!e.assertionPath)throw Error(`--assert is required when --assert-namespace is provided.`);let n=await t.prepare(e);if(assertTargetWorkspaceDiffers(n.sourceWorkspaceId,e.targetWorkspaceId),e.assertionPath&&resolveAssertionNamespace(n.pendingNamespaces,e.assertionNamespace),e.data===`clone`&&e.targetWorkspaceId){let e=o(n.designatedTarget,`designated clone target was not loaded during preparation`);assertCloneTargetRegion(n.temporaryWorkspace.region,e.region)}let r=e.targetWorkspaceId===void 0,i=r?await t.createWorkspace(n):{id:o(e.targetWorkspaceId,`designated target workspace missing`),name:void 0},a,c=!1,l=!1;try{let r={prepared:n,targetWorkspaceId:i.id};await t.deployBaseline(r);let a={...r,sourceWorkspaceId:n.sourceWorkspaceId,applicationName:n.sourceApplicationName};e.data===`clone`?await t.cloneData(a):await t.seedData(a),await t.deployMigrations(r),e.assertionPath&&await t.runAssertion({...r,assertionPath:e.assertionPath,assertionNamespace:e.assertionNamespace,machineUser:e.machineUser})}catch(e){a=e,c=!0}if(r&&e.keep)s.info(`Keeping temporary workspace ${i.name??i.id}.`);else if(r)try{await t.deleteWorkspace(i.id),l=!0}catch(e){if(!c)throw Error(`Failed to delete temporary workspace ${i.id}: ${e instanceof Error?e.message:String(e)}`,{cause:e});s.warn(`Failed to delete temporary workspace ${i.id}: ${e instanceof Error?e.message:String(e)}`)}if(c)throw a;return{success:!0,workspaceId:i.id,...i.name?{workspaceName:i.name}:{},temporary:r,deleted:l,data:e.data,pendingNamespaces:n.pendingNamespaces}}async function migrationTest(e){h(`tailordb migration`);let t=await runMigrationTest(e);if(e.json){s.out(t);return}s.success(`Pending migrations completed in workspace ${t.workspaceName??t.workspaceId}.`)}const na=g({name:`test`,description:`Test pending migrations with seed fixtures or cloned data in a temporary workspace.`,notes:`The source workspace is read-only. Without --target-workspace-id, the command creates a workspace in the source workspace's region and deletes it after success or failure; pass --keep to retain it for inspection. A designated target is retained and requires --yes. Clone mode copies TailorDB records only; it does not copy IdP users or file blobs.`,args:q.strictObject({...O,yes:W(q.boolean().default(!1),{alias:`y`,description:`Acknowledge that a designated target workspace may be overwritten`}),data:W(q.enum([`seed`,`clone`]).default(`seed`),{description:`Data source for the migration test (seed or clone)`}),"target-workspace-id":W(q.uuid().optional(),{description:`Existing throwaway workspace to retain after the test (requires --yes)`}),keep:W(q.boolean().default(!1),{description:`Keep the automatically created workspace after the test`}),assert:W(q.string().optional(),{description:`Path to a TypeScript assertion script to run after migrations`,completion:{type:`file`,extensions:[`ts`]}}),"assert-namespace":W(q.string().optional(),{description:`TailorDB namespace exposed to the assertion script`}),"machine-user":W(q.string().optional(),{description:`Machine user for seed and assertion script execution`})}),run:async e=>{await N({profile:e.profile}),await migrationTest({configPath:e.config,workspaceId:e[`workspace-id`],profile:e.profile,data:e.data,targetWorkspaceId:e[`target-workspace-id`],keep:e.keep,assertionPath:e.assert,assertionNamespace:e[`assert-namespace`],machineUser:e[`machine-user`],yes:e.yes,json:s.jsonMode})}});function assertMigrationScriptsReady(e,t,n){let r=[],i=[],a=[],o=[];for(let t of Ge(e)){if(t.type!==`diff`)continue;let n=Ye(t.path),s=le(e,t.number,`migrate`),c=Y.existsSync(s);n.requiresMigrationScript&&!n.scriptSkipped&&!c&&r.push(t.number),n.scriptSkipped&&c&&i.push(t.number),c&&Y.readFileSync(s,`utf8`).includes(`TODO(tailor-migration-review)`)&&a.push(t.number),n.hasWarnings&&!n.scriptSkipped&&!c&&o.push({migrationNumber:t.number,warnings:n.warnings})}if(r.length>0)throw Error(`Migration(s) ${r.map(P).join(`, `)} in namespace "${t}" require a migration script but have no migrate.ts. Add one with 'tailor tailordb migration script <number>', or record that no script is needed with 'tailor tailordb migration script <number> --no-script --reason "..."'.`);if(i.length>0){let e=i.map(e=>` ${it({migrationNumber:e,namespace:t,configPath:n})}`).join(`
94
+ `);throw Error(`Migration(s) ${i.map(P).join(`, `)} in namespace "${t}" have both a --no-script skip acknowledgment and migrate.ts. Clear the stale acknowledgment(s):
95
+ ${e}\nOr delete migrate.ts to keep the skip.`)}if(a.length>0)throw Error(`Migration(s) ${a.map(P).join(`, `)} in namespace "${t}" contain generated normalization logic that still requires review in migrate.ts. Review each ${ke} marker, then remove the marker and its associated \`never\` annotation.`);return o}function buildValidationReports(e){let{targetNamespaces:t,migrationFileErrors:n,localResults:r,remoteResults:i,unacknowledgedWarnings:a}=e;return t.map(e=>{let t=n.get(e.namespace);if(t!==void 0)return{namespace:e.namespace,valid:!1,migrationFiles:{valid:!1,error:t}};let s=o(r.find(t=>t.namespace===e.namespace),`local schema check result missing for namespace "${e.namespace}"`),c={hasDiff:s.hasDiff,...s.diff?{diff:s.diff}:{}};if(i===void 0)return{namespace:e.namespace,valid:!1,migrationFiles:{valid:!0},localSchema:c,remoteSchema:{skipped:`check_failed`}};let l=o(i.find(t=>t.namespace===e.namespace),`remote schema check result missing for namespace "${e.namespace}"`),u=l.checkpointMissingLocal===!0,d={remoteMigrationNumber:l.remoteMigrationNumber,hasDrift:l.hasDrift,drifts:l.drifts,...l.skipped?{skipped:l.skipped}:{},...u?{checkpointMissingLocal:!0}:{},...l.checkpointRepair?{checkpointRepair:l.checkpointRepair}:{}},f=a?.get(e.namespace),p;if(f!==void 0){let e=f.filter(e=>e.migrationNumber>l.remoteMigrationNumber);p={valid:e.length===0,missing:e}}return{namespace:e.namespace,valid:!c.hasDiff&&!d.hasDrift&&!u&&p?.valid!==!1,migrationFiles:{valid:!0},localSchema:c,remoteSchema:d,...p?{warningAcknowledgments:p}:{}}})}async function collectValidationReports(e){let{config:t,plugins:n}=await R(e.configPath),r=U.dirname(t.path),i=x(t,r);if(i.length===0)throw Error(`No TailorDB services with migrations configuration found`);let a=e.namespace?i.filter(t=>t.namespace===e.namespace):i;if(a.length===0)throw Error(`Namespace "${e.namespace}" not found or does not have migrations configured`);let o=n.length>0?new Xt(n):void 0,{defineApplication:s}=await import(`../application-o09L68wE.mjs`),c=s({config:t,pluginManager:o});for(let e of c.tailorDBServices)await e.loadTypes(),await e.processNamespacePlugins();Rn({tailorDBServices:c.tailorDBServices});for(let{namespace:e}of a)if(!c.tailorDBServices.some(t=>t.namespace===e))throw Error(`No TailorDB service found for namespace "${e}"`);let l=c.tailorDBServices.map(ht),u=new Map(l.map(e=>[e.namespace,e.types])),d=new Map,f=[],p=e.strict?new Map:void 0;for(let t of a)try{ee(t.migrationsDir,t.namespace),D(t.migrationsDir);let n=assertMigrationScriptsReady(t.migrationsDir,t.namespace,e.configPath);p?.set(t.namespace,n),f.push(t)}catch(e){d.set(t.namespace,e instanceof Error?e.message:String(e))}let m={targetNamespaces:a,migrationFileErrors:d,localResults:await ft(u,f),...p?{unacknowledgedWarnings:p}:{}};if(f.length===0)return{reports:buildValidationReports(m)};let h;try{let n=await E({profile:e.profile}),r=await V(n),i=await k({workspaceId:e.workspaceId,profile:e.profile});h=await Ze(r,i,f,t,l)}catch(e){return{reports:buildValidationReports(m),remoteError:e}}return{reports:buildValidationReports({...m,remoteResults:h})}}function printValidationReports(e){for(let t of e){if(s.newline(),s.info(`Namespace: ${c.bold(t.namespace)}`),!t.migrationFiles.valid){s.log(` Migration files: ${c.error(`invalid`)}`),s.log(` ${t.migrationFiles.error}`);continue}s.log(` Migration files: ${c.success(`OK`)}`);let e=t.localSchema;e?.hasDiff?e.diff?(s.log(` Local schema: ${c.error(`changes not in migration files`)}`),s.log(` ${Zt(e.diff)}`),s.log(st(e.diff))):s.log(` Local schema: ${c.error(`no migration snapshot found`)}`):s.log(` Local schema: ${c.success(`OK`)}`);let n=t.remoteSchema;n?.skipped===`check_failed`?s.log(` Remote schema: ${c.error(`not checked`)}`):n?.checkpointRepair?s.log(` Remote schema: ${c.success(`OK`)} (next deploy will reset the checkpoint to 0000 from ${P(n.checkpointRepair.from)})`):n?.checkpointMissingLocal?s.log(` Remote schema: ${c.error(`remote migration ${P(n.remoteMigrationNumber)} is not in the local migration history`)}`):n?.hasDrift?(s.log(` Remote schema: ${c.error(`drift detected`)} (remote migration: ${P(n.remoteMigrationNumber)})`),s.log(_e(n.drifts))):n?.skipped===`not_deployed`?s.log(` Remote schema: ${c.dim(`skipped (namespace not deployed)`)}`):n?.skipped===`no_migration_label`?s.log(` Remote schema: ${c.dim(`skipped (deployed namespace has no migration state)`)}`):n?.skipped===`no_snapshot`?s.log(` Remote schema: ${c.dim(`skipped (no local snapshot for remote migration ${P(n.remoteMigrationNumber)})`)}`):n&&s.log(` Remote schema: ${c.success(`OK`)} (remote migration: ${P(n.remoteMigrationNumber)})`);let r=t.warningAcknowledgments;if(r){if(r.valid)s.log(` Warning acknowledgments: ${c.success(`OK`)}`);else{s.log(` Warning acknowledgments: ${c.error(`missing for pending migration(s) with possible data loss`)}`);for(let e of r.missing){let t=P(e.migrationNumber);for(let n of e.warnings){let e=n.fieldName?`.${n.fieldName}`:``;s.log(` ${t}: ${n.tableName}${e}: ${n.reason}`)}}}}}s.newline()}function printResolutionHints(e,t){e.some(e=>e.localSchema?.hasDiff&&!e.localSchema.diff)&&s.info(`Run 'tailor tailordb migration generate' to create the initial snapshot.`),e.some(e=>e.localSchema?.diff)&&s.info(`Run 'tailor tailordb migration generate' to create migration files.`),e.some(e=>e.remoteSchema?.checkpointMissingLocal)&&s.info(`The remote migration checkpoint is ahead of the local history. Pull the latest migration files, or run 'tailor tailordb migration status' to compare.`),e.some(e=>e.remoteSchema?.hasDrift)&&vt(e.map(e=>({hasDrift:e.remoteSchema?.hasDrift??!1,drifts:e.remoteSchema?.drifts??[]})));let n=e.filter(e=>e.warningAcknowledgments&&!e.warningAcknowledgments.valid);if(n.length>0){s.info(`For each migration listed, either add a data migration script with 'tailor tailordb migration script <number>' or record why none is needed:`);for(let e of n)for(let n of e.warningAcknowledgments?.missing??[])s.info(` ${it({migrationNumber:n.migrationNumber,namespace:e.namespace,configPath:t,noScript:!0})}`,{mode:`plain`})}}async function validate(e){h(`tailordb migration`);let t=await collectValidationReports(e),{reports:n}=t,r=n.filter(e=>!e.valid).length;if(e.json?s.out(n):(printValidationReports(n),r===0&&!(`remoteError`in t)?s.success(`All migration validation checks passed.`):printResolutionHints(n,e.configPath)),`remoteError`in t)throw t.remoteError;if(r>0)throw Error(`Migration validation failed for ${r} namespace(s)`)}const ra=g({name:`validate`,description:`Validate the full migration history, unreviewed generated migration scripts, and schema drift (local tables vs. migration snapshot, remote schema vs. migration checkpoint) without deploying. This includes the migration and schema-drift checks used by 'deploy' and exits with a non-zero code when issues are found.`,args:q.strictObject({...O,namespace:W(q.string().optional(),{alias:`n`,description:`Target TailorDB namespace (validates all namespaces if not specified)`}),strict:W(q.boolean().default(!1),{description:`Also fail when a pending migration can drop data without an acknowledgment`})}),run:async e=>{await validate({configPath:e.config,namespace:e.namespace,workspaceId:e[`workspace-id`],profile:e.profile,json:s.jsonMode,strict:e.strict})}}),ia=G({name:`migration`,description:`Manage TailorDB schema migrations.`,subCommands:{generate:se,rebaseline:Qi,script:me,set:$i,status:ea,sync:ta,test:na,validate:ra}}),aa=G({name:`tailordb`,description:`Manage TailorDB tables and data.`,notes:"The `tailordb erd` commands are provided by the @tailor-platform/sdk-plugin-tailordb-erd CLI plugin.",subCommands:{truncate:St,migration:ia}}),oa=g({name:`upgrade`,description:`Run codemods to upgrade your project to a newer SDK version.`,args:q.strictObject({from:W(q.string(),{description:`SDK version before the upgrade (e.g., 1.33.0)`}),"dry-run":W(q.boolean().default(!1),{alias:`d`,description:`Preview changes without modifying files`}),path:W(q.string().default(`.`),{description:`Project directory to upgrade`,completion:{type:`directory`}})}),run:async e=>{let{initTelemetry:t}=await import(`../telemetry-DXHP3VVi.mjs`);await t();let{upgrade:n}=await import(`../service-CqbQXFDp.mjs`);await n({from:e.from,dryRun:e[`dry-run`],path:U.resolve(e.path)})}}),sa=g({name:`current`,description:`Show current user.`,args:q.strictObject({}),run:async()=>{let e=await j(),t=process.env.TAILOR_PLATFORM_PROFILE,n=t?e.profiles[t]:void 0;if(t&&!n)throw Error(`Profile "${t}" not found`);let r=n?A(n):void 0,i=t?n?.user??null:e.current_user,a=s.jsonMode;if(!i)throw Error(H`
1192
96
  Current user not set.
1193
97
  Please login first using 'tailor login' command to register a user.
1194
- `);if(!Fe(e,i,r))throw Error(U`
98
+ `);if(!Fe(e,i,r))throw Error(H`
1195
99
  Current user '${i}' not found in registered users.
1196
100
  Please login again using 'tailor login' command to register the user.
1197
- `);if(a){s.out({user:i});return}s.out(i)}});function activeCurrentUserKey(e){let t=process.env.TAILOR_PLATFORM_PROFILE;if(!t)return e.current_user?me(e,e.current_user):null;let n=e.profiles[t];return n?me(e,n.user,be(n)):null}function toUserListInfo(e,t){let n=e.indexOf(`|`),r=n===-1?null:e.slice(0,n);return{user:n===-1?e:e.slice(n+1),platformUrl:r,current:t===e}}function formatUserListInfo(e){return`${e.user}${e.platformUrl?` [${e.platformUrl}]`:``}${e.current?` (current)`:``}`}const Ua=g({name:`list`,description:`List all users.`,args:J.strictObject({}),run:async()=>{let e=await M(),t=s.jsonMode,n=Object.keys(e.users);if(n.length===0){s.info(U`
101
+ `);if(a){s.out({user:i});return}s.out(i)}});function activeCurrentUserKey(e){let t=process.env.TAILOR_PLATFORM_PROFILE;if(!t)return e.current_user?he(e,e.current_user):null;let n=e.profiles[t];return n?he(e,n.user,A(n)):null}function toUserListInfo(e,t){let n=e.indexOf(`|`),r=n===-1?null:e.slice(0,n);return{user:n===-1?e:e.slice(n+1),platformUrl:r,current:t===e}}function formatUserListInfo(e){return`${e.user}${e.platformUrl?` [${e.platformUrl}]`:``}${e.current?` (current)`:``}`}const ca=g({name:`list`,description:`List all users.`,args:q.strictObject({}),run:async()=>{let e=await j(),t=s.jsonMode,n=Object.keys(e.users);if(n.length===0){s.info(H`
1198
102
  No users found.
1199
103
  Please login first using 'tailor login' command to register a user.
1200
- `),t&&s.out([]);return}let r=activeCurrentUserKey(e),i=n.map(e=>toUserListInfo(e,r));if(t){s.out([...new Set(i.map(e=>e.user))]);return}i.forEach(e=>{e.current?s.success(formatUserListInfo(e),{mode:`plain`}):s.log(formatUserListInfo(e))})}});function patScopeToString(e){switch(e){case a.PAT_SCOPE_READ:return`read`;case a.PAT_SCOPE_WRITE:return`write`;default:return`unknown`}}function transformPersonalAccessToken(e){return{name:e.name,scopes:e.scopes.map(patScopeToString)}}function getScopesFromWriteFlag(e){return e?[a.PAT_SCOPE_READ,a.PAT_SCOPE_WRITE]:[a.PAT_SCOPE_READ]}function getScopeStringsFromWriteFlag(e){return e?[`read`,`write`]:[`read`]}function printCreatedToken(e,t,n,r){let i=getScopeStringsFromWriteFlag(n);s.jsonMode?s.out({name:e,scopes:i,token:t}):s.log(U`
104
+ `),t&&s.out([]);return}let r=activeCurrentUserKey(e),i=n.map(e=>toUserListInfo(e,r));if(t){s.out([...new Set(i.map(e=>e.user))]);return}i.forEach(e=>{e.current?s.success(formatUserListInfo(e),{mode:`plain`}):s.log(formatUserListInfo(e))})}});function patScopeToString(e){switch(e){case n.PAT_SCOPE_READ:return`read`;case n.PAT_SCOPE_WRITE:return`write`;default:return`unknown`}}function transformPersonalAccessToken(e){return{name:e.name,scopes:e.scopes.map(patScopeToString)}}function getScopesFromWriteFlag(e){return e?[n.PAT_SCOPE_READ,n.PAT_SCOPE_WRITE]:[n.PAT_SCOPE_READ]}function getScopeStringsFromWriteFlag(e){return e?[`read`,`write`]:[`read`]}function printCreatedToken(e,t,n,r){let i=getScopeStringsFromWriteFlag(n);s.jsonMode?s.out({name:e,scopes:i,token:t}):s.log(H`
1201
105
  Personal access token ${r} successfully.
1202
106
 
1203
107
  name: ${e}
@@ -1205,13 +109,14 @@ ${e}\nOr delete migrate.ts to keep the skip.`)}if(a.length>0)throw Error(`Migrat
1205
109
  token: ${t}
1206
110
 
1207
111
  Please save this token in a secure location. You won't be able to see it again.
1208
- `)}function resolvePatUser(e){let t=process.env.TAILOR_PLATFORM_PROFILE;return t?e.profiles[t]?.user??null:e.current_user}async function createPatOperatorClient(){let e=await M(),t=process.env.TAILOR_PLATFORM_PROFILE,n=t?e.profiles[t]:void 0;if(t&&!n)throw Error(`Profile "${t}" not found`);let r=n?be(n):void 0,i=resolvePatUser(e);if(!i)throw Error(`No user logged in.
1209
- Please login first using 'tailor login' command.`);let{accessToken:a}=await b(e,i,r);return await H(a,r)}const Wa=g({name:`create`,description:`Create a new personal access token.`,args:J.strictObject({name:G(J.string(),{positional:!0,description:`Token name`}),write:G(J.boolean().default(!1),{alias:`W`,description:`Grant write permission (default: read-only)`})}),run:async e=>{await I();let t=await createPatOperatorClient(),n=getScopesFromWriteFlag(e.write),r=await t.createPersonalAccessToken({name:e.name,scopes:n});if(!r.accessToken)throw Error(`Failed to create personal access token`);printCreatedToken(e.name,r.accessToken,e.write,`created`)}}),Ga=g({name:`delete`,description:`Delete a personal access token.`,args:J.strictObject({name:G(J.string(),{positional:!0,description:`Token name`})}),run:async e=>{await I(),await(await createPatOperatorClient()).deletePersonalAccessToken({name:e.name}),s.success(`Personal access token "${e.name}" deleted successfully.`)}}),Ka=g({name:`list`,description:`List all personal access tokens.`,args:J.strictObject({...We()}),run:async e=>{let t=s.jsonMode,n=await createPatOperatorClient(),r=qe(e.order),i=await On(async(e,t)=>{let{personalAccessTokens:i,nextPageToken:a}=await n.listPersonalAccessTokens({pageToken:e,pageSize:t,pageDirection:r});return[i,a]},{limit:e.limit});if(i.length===0&&(s.info(U`
112
+ `)}function resolvePatUser(e){let t=process.env.TAILOR_PLATFORM_PROFILE;return t?e.profiles[t]?.user??null:e.current_user}async function createPatOperatorClient(){let e=await j(),t=process.env.TAILOR_PLATFORM_PROFILE,n=t?e.profiles[t]:void 0;if(t&&!n)throw Error(`Profile "${t}" not found`);let r=n?A(n):void 0,i=resolvePatUser(e);if(!i)throw Error(`No user logged in.
113
+ Please login first using 'tailor login' command.`);let{accessToken:a}=await y(e,i,r);return await V(a,r)}const la=g({name:`create`,description:`Create a new personal access token.`,args:q.strictObject({name:W(q.string(),{positional:!0,description:`Token name`}),write:W(q.boolean().default(!1),{alias:`W`,description:`Grant write permission (default: read-only)`})}),run:async e=>{await N();let t=await createPatOperatorClient(),n=getScopesFromWriteFlag(e.write),r=await t.createPersonalAccessToken({name:e.name,scopes:n});if(!r.accessToken)throw Error(`Failed to create personal access token`);printCreatedToken(e.name,r.accessToken,e.write,`created`)}}),ua=g({name:`delete`,description:`Delete a personal access token.`,args:q.strictObject({name:W(q.string(),{positional:!0,description:`Token name`})}),run:async e=>{await N(),await(await createPatOperatorClient()).deletePersonalAccessToken({name:e.name}),s.success(`Personal access token "${e.name}" deleted successfully.`)}}),da=g({name:`list`,description:`List all personal access tokens.`,args:q.strictObject({...Ue()}),run:async e=>{let t=s.jsonMode,n=await createPatOperatorClient(),r=Oe(e.order),i=await B(async(e,t)=>{let{personalAccessTokens:i,nextPageToken:a}=await n.listPersonalAccessTokens({pageToken:e,pageSize:t,pageDirection:r});return[i,a]},{limit:e.limit});if(i.length===0&&(s.info(H`
1210
114
  No personal access tokens found.
1211
115
  Please create a token using 'tailor user pat create' command.
1212
- `),!t))return;let a=i.map(transformPersonalAccessToken);if(t){s.out(a);return}let o=Math.max(...i.map(e=>e.name.length));i.forEach(e=>{let t=transformPersonalAccessToken(e),n=t.name.padStart(o);s.log(`${n}: ${t.scopes.join(`/`)}`)})}}),qa=g({name:`update`,description:`Update a personal access token (delete and recreate).`,args:J.strictObject({name:G(J.string(),{positional:!0,description:`Token name`}),write:G(J.boolean().default(!1),{alias:`W`,description:`Grant write permission (if not specified, keeps read-only)`})}),run:async e=>{await I();let t=await createPatOperatorClient();await t.deletePersonalAccessToken({name:e.name});let n=getScopesFromWriteFlag(e.write),r=await t.createPersonalAccessToken({name:e.name,scopes:n});if(!r.accessToken)throw Error(`Failed to create personal access token`);printCreatedToken(e.name,r.accessToken,e.write,`updated`)}}),Ja=K({name:`pat`,description:`Manage personal access tokens.`,subCommands:{list:Ka,create:Wa,delete:Ga,update:qa},async run(){await q(Ka,[])}}),Ya=g({name:`switch`,description:`Set current user.`,args:J.strictObject({user:G(J.string(),{positional:!0,description:`User email address or machine user client ID`})}),run:async e=>{let t=await M(),n=process.env.TAILOR_PLATFORM_PROFILE,r=n?t.profiles[n]:void 0;if(n&&!r)throw Error(`Profile "${n}" not found`);let i=r?be(r):void 0;if(e.user.includes(`|`))throw Error(`User "${e.user}" looks like a platform-scoped token key. Pass the user name without the platform URL and select the platform with TAILOR_PLATFORM_URL or a profile.`);let a=oe(t,e.user,i);if(!a)throw Error(U`
116
+ `),!t))return;let a=i.map(transformPersonalAccessToken);if(t){s.out(a);return}let o=Math.max(...i.map(e=>e.name.length));i.forEach(e=>{let t=transformPersonalAccessToken(e),n=t.name.padStart(o);s.log(`${n}: ${t.scopes.join(`/`)}`)})}}),fa=g({name:`update`,description:`Update a personal access token (delete and recreate).`,args:q.strictObject({name:W(q.string(),{positional:!0,description:`Token name`}),write:W(q.boolean().default(!1),{alias:`W`,description:`Grant write permission (if not specified, keeps read-only)`})}),run:async e=>{await N();let t=await createPatOperatorClient();await t.deletePersonalAccessToken({name:e.name});let n=getScopesFromWriteFlag(e.write),r=await t.createPersonalAccessToken({name:e.name,scopes:n});if(!r.accessToken)throw Error(`Failed to create personal access token`);printCreatedToken(e.name,r.accessToken,e.write,`updated`)}}),pa=G({name:`pat`,description:`Manage personal access tokens.`,subCommands:{list:da,create:la,delete:ua,update:fa},async run(){await K(da,[])}}),ma=g({name:`switch`,description:`Set current user.`,args:q.strictObject({user:W(q.string(),{positional:!0,description:`User email address or machine user client ID`})}),run:async e=>{let t=await j(),n=process.env.TAILOR_PLATFORM_PROFILE,r=n?t.profiles[n]:void 0;if(n&&!r)throw Error(`Profile "${n}" not found`);let i=r?A(r):void 0;if(e.user.includes(`|`))throw Error(`User "${e.user}" looks like a platform-scoped token key. Pass the user name without the platform URL and select the platform with TAILOR_PLATFORM_URL or a profile.`);let a=ce(t,e.user,i);if(!a)throw Error(H`
1213
117
  User "${e.user}" not found.
1214
118
  Please login first using 'tailor login' command to register this user.
1215
- `);r?r.user=a:t.current_user=a,V(t),s.success(`Current user set to "${a}" successfully.`)}}),Xa=K({name:`user`,description:`Manage Tailor Platform users.`,subCommands:{current:Ha,list:Ua,switch:Ya,pat:Ja},async run(){await q(Ua,[])}}),Za=K({name:`workflow`,description:`Manage workflows and workflow executions.`,subCommands:{list:Se,get:ie,start:_,wait:rn,executions:Be,resume:T},async run(){await q(Se,[])}}),Qa=K({name:`app`,description:`Manage workspace applications`,subCommands:{health:v,list:cn},async run(){await q(cn,[])}}),$a=K({name:`user`,description:`Manage workspace users`,subCommands:{invite:dt,list:Qt,remove:it,update:Pt},async run(){await q(Qt,[])}}),eo=K({name:`workspace`,description:`Manage Tailor Platform workspaces.`,subCommands:{app:Qa,create:Mt,delete:tn,get:mt,list:lt,restore:kt,user:$a},async run(){await q(lt,[])}});await Yt(new URL(`./ts-hook.mjs`,import.meta.url)),ir();const to=await Gn(),no=Object.keys(to.bin??{})[0]||`tailor`,ro=to.name??`@tailor-platform/sdk`,io=await ur(import.meta.url),ao=lr(cr(io),`agent-skills`);function defaultSkillsRunToAdd(e){let t=(e.subCommands??{}).add;return{...e,async run(){let e=await q(t,[]);if(!e.success)throw e.error}}}const oo=hr(K({name:no,description:to.description||`Tailor CLI for managing Tailor Platform SDK applications`,notes:`CLI plugins (beta): an unknown subcommand is dispatched to an external plugin executable named \`${no}-<name>\` (found on your PATH or in node_modules/.bin), similar to \`gh\` extensions.
1216
- Run \`${no} plugin list\` to see which plugins are installed and where they resolve from.`,subCommands:{api:Ur,auth:Gr,authconnection:Qr,crashreport:ti,deploy:ni,executor:ri,function:pi,generate:mi,init:hi,login:vi,logout:yi,machineuser:bi,oauth2client:xi,open:Si,organization:wi,plugin:ki,profile:Pi,query:Qe,remove:ue,secret:qi,setup:wa,show:Le,staticwebsite:ja,tailordb:Ba,upgrade:Va,user:Xa,workflow:Za,workspace:eo}}),{sourceDir:ao,package:ro,mode:`copy`,descriptionAppend:!1,globalArgs:J.object(re),commandMap:{add:[`add`],remove:[`remove`]},unknownKeys:`strict`,descriptions:{skills:`Manage Tailor SDK agent skills.`,add:`Install Tailor SDK agent skills.`,list:`List Tailor SDK agent skills.`,remove:`Remove installed Tailor SDK agent skills.`,sync:`Remove and reinstall Tailor SDK agent skills.`}}),so=mr({...oo,subCommands:{...oo.subCommands,skills:defaultSkillsRunToAdd(oo.subCommands.skills)}});fr(so,{version:to.version,globalArgs:J.object(re),displayErrors:!1,onUnknownSubcommand:({commandPath:e,name:t,args:n})=>dispatchPluginWithInstallHint({commandPath:e,name:t,args:n,cliName:no,profile:process.env.TAILOR_PLATFORM_PROFILE}),cleanup:async({error:e})=>{if(e){if(s.jsonMode)s.log(Ht(e,{includeStack:fe()}));else if(Jn(e))s.log(e.format()),fe()&&e.stack&&s.debug(`\nStack trace:\n${e.stack}`);else if(e instanceof Error){s.error(e.message);let t=Xn(e);t&&s.log(` ${c.info(`Suggestion:`)} ${t}`),fe()&&e.stack&&s.debug(`\nStack trace:\n${e.stack}`)}else s.error(`Unknown error: ${e}`);if(!Jn(e)&&(!(e instanceof Error)||e instanceof TypeError||e instanceof RangeError)){let{reportCrash:t}=await import(`../crashreport-BmsRIdpy.mjs`);await t(e,`handledError`)}}let{shutdownTelemetry:t}=await import(`../telemetry-DXHP3VVi.mjs`);await t()}});export{so as mainCommand};
119
+ `);r?r.user=a:t.current_user=a,z(t),s.success(`Current user set to "${a}" successfully.`)}}),ha=G({name:`user`,description:`Manage Tailor Platform users.`,subCommands:{current:sa,list:ca,switch:ma,pat:pa},async run(){await K(ca,[])}}),ga=G({name:`workflow`,description:`Manage workflows and workflow executions.`,subCommands:{list:Se,get:Ve,start:oe,wait:en,executions:pe,resume:w},async run(){await K(Se,[])}}),_a=G({name:`app`,description:`Manage workspace applications`,subCommands:{health:_,list:an},async run(){await K(an,[])}}),va=G({name:`user`,description:`Manage workspace users`,subCommands:{invite:dt,list:Yt,remove:ot,update:Ft},async run(){await K(Yt,[])}}),ya=G({name:`workspace`,description:`Manage Tailor Platform workspaces.`,subCommands:{app:_a,create:bt,delete:Qt,get:mt,list:Nt,restore:At,user:va},async run(){await K(Nt,[])}});await Gt(new URL(`./ts-hook.mjs`,import.meta.url)),nr();const ba=await Un(),xa=Object.keys(ba.bin??{})[0]||`tailor`,Sa=ba.name??`@tailor-platform/sdk`,Ca=await cr(import.meta.url),wa=sr(or(Ca),`agent-skills`);function defaultSkillsRunToAdd(e){let t=(e.subCommands??{}).add;return{...e,async run(){let e=await K(t,[]);if(!e.success)throw e.error}}}const Ta=pr(G({name:xa,description:ba.description||`Tailor CLI for managing Tailor Platform SDK applications`,notes:`CLI plugins (beta): an unknown subcommand is dispatched to an external plugin executable named \`${xa}-<name>\` (found on your PATH or in node_modules/.bin), similar to \`gh\` extensions.
120
+ Run \`${xa} plugin list\` to see which plugins are installed and where they resolve from.
121
+ The \`setup\` commands are provided by the @tailor-platform/sdk-plugin-setup CLI plugin.`,subCommands:{api:zr,auth:Vr,authconnection:Jr,crashreport:Zr,deploy:Qr,executor:$r,function:li,generate:ui,init:di,login:mi,logout:hi,machineuser:gi,oauth2client:_i,open:vi,organization:bi,plugin:Ti,profile:Ai,query:et,remove:de,secret:Ui,show:Be,staticwebsite:Xi,tailordb:aa,upgrade:oa,user:ha,workflow:ga,workspace:ya}}),{sourceDir:wa,package:Sa,mode:`copy`,descriptionAppend:!1,globalArgs:q.object(ae),commandMap:{add:[`add`],remove:[`remove`]},unknownKeys:`strict`,descriptions:{skills:`Manage Tailor SDK agent skills.`,add:`Install Tailor SDK agent skills.`,list:`List Tailor SDK agent skills.`,remove:`Remove installed Tailor SDK agent skills.`,sync:`Remove and reinstall Tailor SDK agent skills.`}}),Ea=fr({...Ta,subCommands:{...Ta.subCommands,skills:defaultSkillsRunToAdd(Ta.subCommands.skills)}});ur(Ea,{version:ba.version,globalArgs:q.object(ae),displayErrors:!1,onUnknownSubcommand:({commandPath:e,name:t,args:n})=>dispatchPluginWithInstallHint({commandPath:e,name:t,args:n,cliName:xa,profile:process.env.TAILOR_PLATFORM_PROFILE}),cleanup:async({error:e})=>{if(e){if(s.jsonMode)s.log(Bt(e,{includeStack:s.verbose}));else if(Kn(e))s.log(e.format()),s.verbose&&e.stack&&s.debug(`\nStack trace:\n${e.stack}`);else if(e instanceof Error){s.error(e.message);let t=Jn(e);t&&s.log(` ${c.info(`Suggestion:`)} ${t}`),s.verbose&&e.stack&&s.debug(`\nStack trace:\n${e.stack}`)}else s.error(`Unknown error: ${e}`);if(!Kn(e)&&(!(e instanceof Error)||e instanceof TypeError||e instanceof RangeError)){let{reportCrash:t}=await import(`../crashreport-By23O2k-.mjs`);await t(e,`handledError`)}}let{shutdownTelemetry:t}=await import(`../telemetry-DXHP3VVi.mjs`);await t()}});export{Ea as mainCommand};
1217
122
  //# sourceMappingURL=main.mjs.map