@tailor-platform/sdk 2.15.0 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/dist/application-Dw3t9p2f.mjs +1 -0
- package/dist/{application-BpoMu4Af.mjs → application-wYQ-ivDg.mjs} +27 -27
- package/dist/application-wYQ-ivDg.mjs.map +1 -0
- package/dist/cli/commands/executor/jobs.d.mts +1 -0
- package/dist/cli/commands/generate/seed/bundler.d.mts +18 -0
- package/dist/cli/commands/tailordb/migrate/config.d.mts +1 -0
- package/dist/cli/commands/workflow/waiter.d.mts +1 -0
- package/dist/cli/commands/workspace/create.d.mts +16 -1
- package/dist/cli/commands/workspace/expiry.d.mts +5 -0
- package/dist/cli/commands/workspace/get.d.mts +6 -1
- package/dist/cli/commands/workspace/list.d.mts +1 -0
- package/dist/cli/lib.d.mts +3 -2
- package/dist/cli/lib.mjs +1 -1
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.mjs +50 -52
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/shared/command.d.mts +1 -1
- package/dist/cli/shared/error-json.d.mts +2 -1
- package/dist/cli/shared/errors.d.mts +1 -0
- package/dist/cli/shared/github-actions.d.mts +13 -0
- package/dist/completion/zsh-worker.zsh +91 -3
- package/dist/crashreport-DF8YMIE5.mjs +1 -0
- package/dist/{crashreport-BN28xp5B.mjs → crashreport-Doz2Kuuq.mjs} +2 -2
- package/dist/{crashreport-BN28xp5B.mjs.map → crashreport-Doz2Kuuq.mjs.map} +1 -1
- package/dist/errors-BtTxkzgy.mjs +7 -0
- package/dist/errors-BtTxkzgy.mjs.map +1 -0
- package/dist/guards-ForsrxnH.mjs +2 -0
- package/dist/guards-ForsrxnH.mjs.map +1 -0
- package/dist/{logger-CCjs1DuH.mjs → logger-CEAxByN5.mjs} +3 -3
- package/dist/{logger-CCjs1DuH.mjs.map → logger-CEAxByN5.mjs.map} +1 -1
- package/dist/manager-E3ffRcCt.mjs +2 -0
- package/dist/manager-E3ffRcCt.mjs.map +1 -0
- package/dist/node-builtins-DYfhPBnz.mjs +2 -0
- package/dist/node-builtins-DYfhPBnz.mjs.map +1 -0
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/builtin/seed/seed-type-processor.d.mts +17 -0
- package/dist/plugin/get-generated-table.d.mts +13 -0
- package/dist/plugin/index.d.mts +2 -2
- package/dist/plugin/index.mjs +1 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/register-ts-hook-DrHS-J1k.mjs +878 -0
- package/dist/register-ts-hook-DrHS-J1k.mjs.map +1 -0
- package/dist/{seed-CCc9Xk66.mjs → seed-C3P_T_Eh.mjs} +28 -9
- package/dist/seed-C3P_T_Eh.mjs.map +1 -0
- package/dist/service-Cw7hb5HK.mjs +2 -0
- package/dist/service-Cw7hb5HK.mjs.map +1 -0
- package/dist/service-DaoW0kzo.mjs +7 -0
- package/dist/service-DaoW0kzo.mjs.map +1 -0
- package/dist/service-dn9jxC8c.mjs +1 -0
- package/dist/utils/test/index.d.mts +7 -5
- package/dist/utils/test/index.mjs +1 -1
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/index.mjs +1 -1
- package/docs/cli/tailordb.md +1 -1
- package/docs/cli/workspace.md +133 -20
- package/docs/cli-reference.md +94 -25
- package/docs/plugin/custom.md +36 -4
- package/docs/services/tailordb-migration.md +6 -4
- package/package.json +4 -4
- package/dist/application-BpoMu4Af.mjs.map +0 -1
- package/dist/application-fIhVKX78.mjs +0 -1
- package/dist/crashreport-By23O2k-.mjs +0 -1
- package/dist/errors-BlX4gUw5.mjs +0 -4
- package/dist/errors-BlX4gUw5.mjs.map +0 -1
- package/dist/node-builtins-TQHhwNzG.mjs +0 -2
- package/dist/node-builtins-TQHhwNzG.mjs.map +0 -1
- package/dist/register-ts-hook-CAUcxCt4.mjs +0 -711
- package/dist/register-ts-hook-CAUcxCt4.mjs.map +0 -1
- package/dist/seed-CCc9Xk66.mjs.map +0 -1
- package/dist/service-7SCy2bhm.mjs +0 -7
- package/dist/service-7SCy2bhm.mjs.map +0 -1
- package/dist/service-CWFQ8EVo.mjs +0 -1
- package/dist/service-CqbQXFDp.mjs +0 -2
- package/dist/service-CqbQXFDp.mjs.map +0 -1
package/dist/vitest/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e,t}from"../registry-HlEaGvl5.mjs";import{a as n,c as r,i,o as a,s as o,u as s}from"../wait-point-invoker-eiP-IIux.mjs";import{t as c}from"../assert-WeXvmG4j.mjs";import{i as l,n as u}from"../node-builtins-TQHhwNzG.mjs";import{t as d}from"../platform-serialize-DkiTdHOt.mjs";import{i as f,n as p,r as m,t as h}from"../secretmanager-5olfnI1b.mjs";import{createRequire as g}from"node:module";import{isEqual as _}from"es-toolkit";import{fileURLToPath as v}from"node:url";import{ColumnNode as y,CompiledQuery as b,InsertQueryNode as x,Kysely as S,PostgresAdapter as C,PostgresIntrospector as w,PostgresQueryCompiler as T,PrimitiveValueListNode as E,ReferenceNode as D,UpdateQueryNode as O,ValueListNode as k,ValueNode as A,ValuesNode as j}from"kysely";import{dirname as M,isAbsolute as N,matchesGlob as P,relative as F,resolve as I}from"node:path";import{vi as L}from"vitest";function isBlockedModule(e){return l(e)}function getBlockedMessage(e){return u(e)}const R=[`**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}`],z=new Set([`ImportDeclaration`,`ExportNamedDeclaration`,`ExportAllDeclaration`]),B=new Set(`break.case.catch.class.const.continue.debugger.default.delete.do.else.enum.export.extends.false.finally.for.function.if.import.in.instanceof.new.null.return.super.switch.this.throw.true.try.typeof.var.void.while.with.yield.let.static.implements.interface.package.private.protected.public.await.arguments.eval`.split(`.`)),V=/^[A-Za-z_$]/,H=/^[A-Za-z0-9_$]*$/;function isSafeBindingName(e){if(B.has(e)||e.length===0)return!1;let t=e[0];return t!==void 0&&V.test(t)&&H.test(e.slice(1))}function buildBlockedReplacement(e,t){let n=JSON.stringify(t),r=`throw new Error(${n});`,i=`(() => { throw new Error(${n}); })()`;if(e.type===`ExportNamedDeclaration`){let t=e.specifiers??[],n=[];for(let e of t){let t=e.exported?.name;if(typeof t==`string`){if(t==="default"){n.push(`export default ${i};`);continue}if(!isSafeBindingName(t))return r;n.push(`export const ${t} = ${i};`)}}return n.length>0?n.join(` `):r}if(e.type===`ExportAllDeclaration`){let t=e.exported?.name;return typeof t==`string`&&isSafeBindingName(t)?`export const ${t} = ${i};`:r}return r}const toFileList=e=>Array.isArray(e)?e:e?[e]:[];let U;function supportsDefaultProjectInheritance(){if(U===void 0)try{let{version:e}=g(import.meta.url)(`vitest/package.json`);U=Number.parseInt(e,10)>=5}catch{U=!1}return U}function createBlockPlugin(){let isTestFile=()=>!1,isUserSourceFile=()=>!1;return{name:`tailor-runtime-block-node`,configResolved(e){let t=e.test,n=t?.root??e.root,toAbsolutePaths=(e,t)=>toFileList(e).map(e=>I(t,e)),r=new Set([...toAbsolutePaths(t?.setupFiles,n),...toAbsolutePaths(t?.globalSetup,n)]),i=[{root:n,patterns:t?.include??R}];for(let e of t?.projects??[]){let t=e.test;if(!t)continue;let a=t.root??n;for(let e of toAbsolutePaths(t.setupFiles,a))r.add(e);for(let e of toAbsolutePaths(t.globalSetup,a))r.add(e);i.push({root:a,patterns:t.include??R})}isTestFile=e=>r.has(e)?!0:i.some(({root:t,patterns:n})=>{let r=N(e)?F(t,e):e;return n.some(e=>P(r,e))}),isUserSourceFile=e=>{if(!N(e))return!1;let t=F(n,e);return t!==``&&!t.startsWith(`..`)&&!N(t)}},transform(e,t){let n=t.search(/[?#]/),r=n===-1?t:t.slice(0,n);if(isTestFile(r)||r.includes(`node_modules`)||!isUserSourceFile(r))return;let i;try{i=this.parse(e)}catch{return}let a=[];for(let e of i.body){if(!z.has(e.type))continue;let t=e.source?.value;typeof t==`string`&&isBlockedModule(t)&&a.push({start:e.start,end:e.end,replacement:buildBlockedReplacement(e,getBlockedMessage(t))})}if(a.length===0)return;let o=e;for(let e of a.toSorted((e,t)=>t.start-e.start))o=o.slice(0,e.start)+e.replacement+o.slice(e.end);return{code:o,map:null}}}}function setConfigEnv(e,t){e.env={...e.env,__TAILOR_RUNTIME_CONFIG:t}}function createEnvironmentPlugin(e){let t=M(v(import.meta.url)),n=I(t,`environment.mjs`),r=I(t,`setup.mjs`),selectsTailorRuntime=e=>e===`tailor-runtime`||e===n;return{name:`tailor-runtime-environment`,config(t){let i=t.test,a=!!i&&selectsTailorRuntime(i.environment);if(i&&a&&(i.environment=n),i?.projects)for(let o of i.projects){if(typeof o==`string`)continue;let i=o.test??={};if(!(i.environment===void 0&&a&&(o.extends===!0||o.extends===void 0&&supportsDefaultProjectInheritance()))&&!selectsTailorRuntime(i.environment)){e?.config&&setConfigEnv(i,``);continue}i.environment=n;let s=toFileList(i.setupFiles);if(s.includes(r)||(i.setupFiles=[...s,r]),e?.config){let n=o.root??i.root??t.root??process.cwd();setConfigEnv(i,I(n,e.config))}}if(e?.config&&i){let n=i.root??t.root??process.cwd();setConfigEnv(i,a?I(n,e.config):``)}let o=toFileList(i?.setupFiles);return i&&typeof i.setupFiles==`string`&&(i.setupFiles=o),!a||o.includes(r)?{}:{test:{setupFiles:[r]}}}}}function mockAigateway(e={}){let t=p(),n=t.aigateway,r={...e.urls};async function defaultGet(e){let t=r[e];if(t===void 0)throw Error(`No AI Gateway registered for "${e}". Acquire mockAigateway() and call setUrls(...).`);return{url:t}}let i=L.fn(defaultGet);return t.aigateway={get:i},f({get:i,setUrls(e){r=e},setUrl(e,t){r={...r,[e]:t}},get calls(){return i.mock.calls.map(([e])=>({name:e}))},clear(){i.mockClear()},reset(){r={},i.mockReset(),i.mockImplementation(defaultGet)}},()=>{t.aigateway=n})}function mockAuthconnection(e={}){let t=p(),n=t.authconnection,r={...e.tokens};async function defaultGetConnectionToken(t){let n=r[t];if(n)return n;if(e.onUnhandled===`error`)throw Error(`No AuthConnection token configured for "${t}"`);return{access_token:`mock-token`}}let i=L.fn(defaultGetConnectionToken);return t.authconnection={getConnectionToken:i},f({getConnectionToken:i,setTokens(e){r=e},setToken(e,t){r={...r,[e]:t}},get calls(){return i.mock.calls.map(([e])=>({connectionName:e}))},clear(){i.mockClear()},reset(){r={},i.mockReset(),i.mockImplementation(defaultGetConnectionToken)}},()=>{t.authconnection=n})}const W=[`upload`,`download`,`downloadAsBase64`,`delete`,`getMetadata`,`downloadStream`,`uploadStream`],G={upload:{metadata:{fileSize:0,sha256sum:``}},download:{data:new Uint8Array,metadata:{contentType:``,fileSize:0,sha256sum:``,lastUploadedAt:``}},downloadAsBase64:{data:``,metadata:{contentType:``,fileSize:0,sha256sum:``,lastUploadedAt:``}},getMetadata:{contentType:``,fileSize:0,sha256sum:``,urlPath:``},downloadStream:null,uploadStream:{metadata:{fileSize:0,sha256sum:``}}};function mockFile(e={}){let t=m(),n=t.file,{onUnhandled:r=`fallback`}=e,i=[],a=[],resolver=()=>null;function handle(e,t,n,a,o){if(i.length>0)return i.shift();let s=resolver(e,{method:e,namespace:t,tableName:n,fieldName:a,recordId:o});if(s!=null)return s;if(r===`error`)throw Error(`No File mock configured for "${e}"`);let c=G[e];return c===void 0?void 0:structuredClone(c)}let o=L.fn(async(...e)=>{let[t,n,r,i]=e;return handle(`upload`,t,n,r,i)}),s=L.fn(async(...e)=>handle(`download`,...e)),c=L.fn(async(...e)=>handle(`downloadAsBase64`,...e)),l=L.fn(async(...e)=>{handle(`delete`,...e)}),u=L.fn(async(...e)=>handle(`getMetadata`,...e)),d=L.fn(async(...e)=>handle(`downloadStream`,...e)??{body:new ReadableStream({start(e){e.close()}}),metadata:{contentType:``,fileSize:0,sha256sum:``,lastUploadedAt:``}}),p=L.fn(async(...e)=>{let[t,n,r,i]=e;return handle(`uploadStream`,t,n,r,i)}),h={upload:o,download:s,downloadAsBase64:c,delete:l,getMetadata:u,downloadStream:d,uploadStream:p};function track(e,t){return function(...n){return a.push({method:e,namespace:n[0],tableName:n[1],fieldName:n[2],recordId:n[3]}),t.apply(this,n)}}t.file={upload:track(`upload`,o),download:track(`download`,s),downloadAsBase64:track(`downloadAsBase64`,c),delete:track(`delete`,l),getMetadata:track(`getMetadata`,u),downloadStream:track(`downloadStream`,d),uploadStream:track(`uploadStream`,p)};function allMocks(){return W.map(e=>h[e])}let g={...h,setResolver(e){resolver=e},enqueueResult(e){i.push(e)},enqueueResults(...e){i.push(...e)},get calls(){return a},clear(){a.length=0;for(let e of allMocks())e.mockClear()},reset(){i.length=0,a.length=0,resolver=()=>null;for(let e of allMocks())e.mockReset()}};return f(g,()=>{t.file=n})}function isUtf8(e){return e===`UTF8`||e===`UTF-8`}function defaultIconvResult(e,t){switch(e){case`convert`:case`convertBuffer`:return isUtf8(t[2])?``:new Uint8Array;case`decode`:return``;case`encode`:return isUtf8(t[1])?``:new Uint8Array;case`encodings`:return[]}}function mockIconv(e={}){let t=p(),n=t.iconv,r=null,i=[];function resolve(t,n){if(r){let e=r(t,n);if(e!=null)return e}if(e.onUnhandled===`error`)throw Error(`No Iconv mock behavior configured for "${t}"`);return defaultIconvResult(t,n)}function defaultConvert(e,t,n){return resolve(`convert`,[e,t,n])}function defaultConvertBuffer(e,t,n){return resolve(`convertBuffer`,[e,t,n])}function defaultDecode(e,t){return resolve(`decode`,[e,t])}function defaultEncode(e,t){return resolve(`encode`,[e,t])}function defaultEncodings(){return resolve(`encodings`,[])}let a=L.fn(defaultConvert),o=L.fn(defaultConvertBuffer),s=L.fn(defaultDecode),c=L.fn(defaultEncode),l=L.fn(defaultEncodings);function track(e,t){return function(...n){return i.push({method:e,args:[...n]}),t.apply(this,n)}}let u=track(`convert`,a),d=track(`convertBuffer`,o),m=track(`decode`,s),h=track(`encode`,c),g=track(`encodings`,l);class MockIconv{#e;#t;constructor(e,t){this.#e=e,this.#t=t}convert(e){return u.call(this,e,this.#e,this.#t)}}t.iconv={convert:u,convertBuffer:d,decode:m,encode:h,encodings:g,Iconv:MockIconv};function clear(){i.length=0,a.mockClear(),o.mockClear(),s.mockClear(),c.mockClear(),l.mockClear()}return f({convert:a,convertBuffer:o,decode:s,encode:c,encodings:l,setResolver(e){r=e},get calls(){return i},clear,reset(){r=null,i.length=0,a.mockReset(),a.mockImplementation(defaultConvert),o.mockReset(),o.mockImplementation(defaultConvertBuffer),s.mockReset(),s.mockImplementation(defaultDecode),c.mockReset(),c.mockImplementation(defaultEncode),l.mockReset(),l.mockImplementation(defaultEncodings)}},()=>{t.iconv=n})}const K=[`users`,`user`,`userByName`,`createUser`,`updateUser`,`deleteUser`,`sendPasswordResetEmail`,`unenrollMfa`],q={id:`mock-id`,name:`mock-user`,disabled:!1,mfaEnrolled:!1,mfaFactorIds:[]},J={users:{users:[],nextPageToken:null,totalCount:0},user:q,userByName:q,createUser:q,updateUser:q,deleteUser:!0,sendPasswordResetEmail:!0,unenrollMfa:!0};function mockIdp(e={}){let t=p(),n=t.idp,{onUnhandled:r=`fallback`}=e,i=[],a=[],resolver=()=>null,o=new Map;function compatibilityArgs(e,t){return e===`users`&&t.length===0?[void 0]:t}function handle(e,t,n){if(i.length>0)return i.shift();let a=resolver(e,compatibilityArgs(e,t),n);if(a!=null)return a;if(r===`error`)throw Error(`No IdP mock configured for "${n}.${e}"`);return structuredClone(J[e])}function createNamespaceMocks(e){return{users:L.fn(async(...t)=>handle(`users`,t,e)),user:L.fn(async(...t)=>handle(`user`,t,e)),userByName:L.fn(async(...t)=>handle(`userByName`,t,e)),createUser:L.fn(async(...t)=>handle(`createUser`,t,e)),updateUser:L.fn(async(...t)=>handle(`updateUser`,t,e)),deleteUser:L.fn(async(...t)=>handle(`deleteUser`,t,e)),sendPasswordResetEmail:L.fn(async(...t)=>handle(`sendPasswordResetEmail`,t,e)),unenrollMfa:L.fn(async(...t)=>handle(`unenrollMfa`,t,e))}}function namespace(e){let t=o.get(e);if(t)return t;let n=createNamespaceMocks(e);return o.set(e,n),n}function track(e,t,n){return function(...r){return a.push({method:e,args:[...compatibilityArgs(e,r)],namespace:n}),t.apply(this,r)}}let defaultClient=function(e){let t=namespace(e.namespace);this.users=track(`users`,t.users,e.namespace),this.user=track(`user`,t.user,e.namespace),this.userByName=track(`userByName`,t.userByName,e.namespace),this.createUser=track(`createUser`,t.createUser,e.namespace),this.updateUser=track(`updateUser`,t.updateUser,e.namespace),this.deleteUser=track(`deleteUser`,t.deleteUser,e.namespace),this.sendPasswordResetEmail=track(`sendPasswordResetEmail`,t.sendPasswordResetEmail,e.namespace),this.unenrollMfa=track(`unenrollMfa`,t.unenrollMfa,e.namespace)},s=L.fn(defaultClient);t.idp={Client:s};function allMocks(){return[...o.values()].flatMap(e=>K.map(t=>e[t]))}return f({Client:s,namespace,setResolver(e){resolver=e},enqueueResult(e){i.push(e)},enqueueResults(...e){i.push(...e)},get calls(){return a},clear(){a.length=0,s.mockClear();for(let e of allMocks())e.mockClear()},reset(){i.length=0,a.length=0,resolver=()=>null,s.mockReset(),s.mockImplementation(defaultClient);for(let e of allMocks())e.mockReset()}},()=>{t.idp=n})}function mockLogger(e={}){let t=p(),n=t.logger,r=L.fn((e,t)=>{}),i=L.fn((e,t)=>{}),a=L.fn((e,t)=>{}),o=L.fn((e,t)=>{}),s=L.fn(e=>{});t.logger={debug:r,info:i,warn:a,error:o,setAttributes:s};let c={debug:r,info:i,warn:a,error:o};return f({debug:r,info:i,warn:a,error:o,setAttributes:s,get calls(){return Object.entries(c).flatMap(([e,t])=>t.mock.calls.map((n,r)=>({order:t.mock.invocationCallOrder[r]??0,call:{severity:e,message:n[0],attributes:n[1]}}))).toSorted((e,t)=>e.order-t.order).map(e=>e.call)},clear(){r.mockClear(),i.mockClear(),a.mockClear(),o.mockClear(),s.mockClear()},reset(){r.mockReset(),i.mockReset(),a.mockReset(),o.mockReset(),s.mockReset()}},()=>{t.logger=n})}function testRegex(e,t){let n=e.lastIndex;e.lastIndex=0;try{return e.test(t)}finally{e.lastIndex=n}}var MockQueryResult=class{command;rowCount;rows;constructor(e){this.command=``,this.rowCount=e.length,this.rows=e}};function mockTailordb(e={}){let t=m(),n=t.Client,r=[],i;function matchesQuery(e,t,n){if(typeof e==`function`)return e(t,n);if(typeof e==`string`)return t===e;if(e instanceof RegExp)return testRegex(e,t);let r;if(r=typeof e.sql==`string`?t===e.sql:testRegex(e.sql,t),!r||e.params===void 0)return r;if(typeof e.params==`function`)return e.params(n);let i=e.params;return n.length===i.length&&n.every((e,t)=>_(e,i[t]))}function queryResponse(e){if(e.type===`error`)throw e.error;return new MockQueryResult(e.rows)}async function defaultQuery(t,n=[]){for(let e=r.length-1;e>=0;--e){let i=r[e];if(!i||!matchesQuery(i.matcher,t,n))continue;let a=i.once.shift();if(a)return queryResponse(a);if(i.fallback)return queryResponse(i.fallback)}if(i)return new MockQueryResult(i(t,n)??[]);if(e.onUnhandled===`error`)throw Error(`No TailorDB query behavior matched: ${t}`);return new MockQueryResult([])}let a=L.fn(defaultQuery),defaultConnect=async()=>{},o=L.fn(defaultConnect),s=[];function enqueueRowsList(e){for(let t of e)a.mockImplementationOnce(async()=>new MockQueryResult(t))}let defaultClient=function(e){let t={namespace:e?.namespace,ended:!1};s.push(t),this.connect=o,this.end=L.fn(async()=>{t.ended=!0}),this.queryObject=a,this.createTransaction=e=>{if(!e)throw Error(`Transaction name must be a non-empty string`);return{begin:async()=>{},commit:async()=>{},rollback:async()=>{},queryObject:a}}},c=L.fn(defaultClient);return t.Client=c,f({Client:c,queryObject:a,setQueryResolver(e){i=e,a.mockImplementation(defaultQuery)},onQuery(e){let t={matcher:e,once:[]};r.push(t);let n={returnsRows(e){return t.fallback={type:`rows`,rows:e},n},returnsRowsOnce(e){return t.once.push({type:`rows`,rows:e}),n},rejects(e){return t.fallback={type:`error`,error:e},n},rejectsOnce(e){return t.once.push({type:`error`,error:e}),n}};return n},enqueueResult(...e){enqueueRowsList([e])},enqueueResults(...e){enqueueRowsList(e)},enqueueRows(...e){enqueueRowsList(e)},get executedQueries(){return a.mock.calls.map(([e,t])=>({query:e,params:t??[]}))},get createdClients(){return s},clear(){a.mockClear(),o.mockClear(),c.mockClear(),s.length=0},reset(){a.mockReset(),a.mockImplementation(defaultQuery),o.mockReset(),o.mockImplementation(defaultConnect),c.mockReset(),c.mockImplementation(defaultClient),s.length=0,r.length=0,i=void 0}},()=>{t.Client=n})}const Y=new WeakMap,X=new WeakMap,Z=new WeakMap;function replaceProcedure(e,t,n){let r=Z.get(n)??n,i=L.fn(function(...e){return Reflect.apply(r,this,e)});Z.set(i,r);let a=e;return a[t]=i,{mock:i,scoped:{mockClear:()=>i.mockClear(),mockReset:()=>i.mockReset(),restore:()=>{a[t]===i&&(a[t]=n)}}}}function replaceStart(e){return replaceProcedure(e,`start`,e.start)}function mockWorkflow(){let e=p(),a=e.workflow,c=r(),l=new Map,u=new Map,m=new Map,h=new Map,g=new Set,installKeyDispatcher=e=>{let t=h.get(e);if(t)return t;let n=i(e);if(!n)throw Error(`waitPointWith expects a wait point definition created by createWaitPoint or createWaitPoints.`);let r=n,a=n.wait,o=n.resolve,s=Y.get(a)??a,c=X.get(o)??o,l={perKey:new Map,originalWait:(e,t)=>s.call(n,e,t),originalResolve:(e,t,r)=>c.call(n,e,t,r)},dispatchWait=(e,t)=>{let n=l.perKey.get(e);return n?t===void 0?n.wait():n.wait(t):l.originalWait(e,t)},dispatchResolve=async(e,t,n)=>{let r=l.perKey.get(e);if(!r)return l.originalResolve(e,t,n);await r.resolve(t,n)};Y.set(dispatchWait,s),X.set(dispatchResolve,c),r.wait=dispatchWait,r.resolve=dispatchResolve;let eachSpy=e=>{for(let t of l.perKey.values()){let n=t;e(n.wait),e(n.resolve)}};return g.add({mockClear:()=>eachSpy(e=>e.mockClear()),mockReset:()=>eachSpy(e=>e.mockReset()),restore:()=>{r.wait=a,r.resolve=o,h.delete(e)}}),h.set(e,l),l},defaultExecJob=(e,t,n)=>{throw Error(`No workflow job mock for "${e}". Call mockWorkflow().setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`)},defaultStartWorkflow=async(e,n,r)=>t,defaultResumeWorkflowExecution=async e=>e,_=L.fn(defaultExecJob),v=L.fn(defaultStartWorkflow),y=L.fn(defaultResumeWorkflowExecution),b=L.fn((e,t)=>null),x=L.fn(async(e,t,n)=>{});return e.workflow={execJobFunction:(...e)=>{let t=e.length>=3?_(e[0],d(e[1]),e[2]):_(e[0],d(e[1]));return t instanceof Promise?t.then(e=>d(e)):d(t)},startWorkflow:(...e)=>e.length>=3?v(e[0],d(e[1]),e[2]):v(e[0],d(e[1])),resumeWorkflowExecution:e=>y(e),wait:(e,t)=>b(e,d(t)),resolve:(e,t,n)=>x(e,t,e=>{let t=n(e);return t instanceof Promise?t.then(e=>d(e)):d(t)})},f({execJobFunction:_,startWorkflow:v,resumeWorkflowExecution:y,wait:b,resolve:x,job(e){let t=l.get(e);if(t)return t;let{mock:n,scoped:r}=replaceStart(e);return g.add(r),l.set(e,n),n},workflow(e){let t=u.get(e);if(t)return t;let{mock:n,scoped:r}=replaceStart(e);return u.set(e,n),g.add(r),n},waitPoint(e){let t=m.get(e);if(t)return t;let n=replaceProcedure(e,`wait`,e.wait),r=replaceProcedure(e,`resolve`,e.resolve),i=n.mock,a=r.mock;g.add(n.scoped),g.add(r.scoped);let o={wait:i,resolve:a,setResolvePayload(e){a.mockImplementation(async(t,n)=>{let r=await n(d(e));d(r)})}};return m.set(e,o),o},waitPointWith(e,t){let r=n(e.with(t));if(r===void 0)throw Error(`waitPointWith expects a wait point declared with $params. Use waitPoint() for a wait point with a fixed key.`);let i=installKeyDispatcher(e),a=i.perKey.get(r);if(a)return a;let o=L.fn(e=>Promise.resolve(i.originalWait(r,e))),s=L.fn((e,t)=>i.originalResolve(r,e,t)),c={wait:o,resolve:s,setResolvePayload(e){s.mockImplementation(async(t,n)=>{let r=await n(d(e));d(r)})}};return i.perKey.set(r,c),c},setJobHandler(e){_.mockImplementation((t,n,r)=>e(t,n,r))},enqueueResult(e){_.mockImplementationOnce(()=>e)},enqueueResults(...e){for(let t of e)_.mockImplementationOnce(()=>t)},get startedJobs(){return _.mock.calls.map(([e,t,n])=>({jobName:e,args:t,...n!==void 0&&{options:n}}))},setStartHandler(e){v.mockImplementation(typeof e==`function`?async(t,n,r)=>e(t,n,r):async()=>e)},setResumeHandler(e){y.mockImplementation(typeof e==`function`?async t=>e(t):async()=>e)},setWaitHandler:e=>{b.mockImplementation(typeof e==`function`?(t,n)=>e(t,n):()=>e)},setEnv(e){s({...e})},setResolveHandler(e){x.mockImplementation(async(t,n,r)=>{await e(t,n,r)})},get waitCalls(){return b.mock.calls.map(([e,t])=>({key:e,payload:t}))},get resolveCalls(){return x.mock.calls.map(([e,t])=>({executionId:e,key:t}))},clear(){_.mockClear(),v.mockClear(),y.mockClear(),b.mockClear(),x.mockClear();for(let e of g)e.mockClear()},reset(){_.mockReset(),_.mockImplementation(defaultExecJob),v.mockReset(),v.mockImplementation(defaultStartWorkflow),y.mockReset(),y.mockImplementation(defaultResumeWorkflowExecution),b.mockReset(),b.mockImplementation(()=>null),x.mockReset(),x.mockImplementation(async()=>{});for(let e of g)e.mockReset();o()}},()=>{for(let e of g)e.restore();e.workflow=a,c===void 0?o():s(c)})}var TransactionLock=class{#e=null;#t=[];holds(e){return this.#e===e}async acquire(e){for(;this.#e!==null;)await new Promise(e=>this.#t.push(e));this.#e=e}release(e){this.#e===e&&(this.#e=null,this.#t.shift()?.())}};const Q=/^\s*(?:begin|start\s+transaction)\b/i,$=/^\s*(?:commit\b|rollback\b(?!(?:\s+(?:work|transaction))?\s+to\b))/i;function toQueryObjectResult(e){return{command:e.command??(e.affectedRows?`UPDATE`:`SELECT`),rowCount:e.rowCount??(e.affectedRows||e.rows.length),rows:e.rows}}function mockTailordbWithPGlite(e){let t=m(),n=t.Client,r=[],i=[],a=new Map,o=new Set,assertNoOpenTransaction=e=>{if(o.size>0)throw Error(`mockTailordbWithPGlite: ${e}() cannot run while a transaction is open; commit, roll back, or end() its client first`)},defaultClient=function(t){let n=t?.namespace,s=n!==void 0&&Object.hasOwn(e.namespaces,n)?e.namespaces[n]:void 0;if(n===void 0||!s)throw Error(`mockTailordbWithPGlite: no PGlite instance registered for namespace "${n}"`);let c=a.get(s)??new TransactionLock;a.set(s,c);let l={namespace:n,ended:!1};i.push(l);let u=this,run=async(e,t)=>(r.push({namespace:n,query:e,params:t??[]}),toQueryObjectResult(await s.query(e,t??[]))),throwEnded=()=>{throw Error(`mockTailordbWithPGlite: query after end() on this client`)},acquire=async()=>{await c.acquire(u),l.ended&&(c.release(u),throwEnded())},queryObject=async(e,t)=>{if(l.ended&&throwEnded(),Q.test(e)){if(c.holds(u))throw Error(`mockTailordbWithPGlite: transaction already open on this client — run nested statements on the transaction callback's trx`);await acquire();try{let n=await run(e,t);return o.add(l),n}catch(e){throw c.release(u),e}}if($.test(e)){if(c.holds(u))try{return await run(e,t)}finally{o.delete(l),c.release(u)}await acquire();try{return await run(e,t)}finally{c.release(u)}}if(c.holds(u))return await run(e,t);await acquire();try{return await run(e,t)}finally{c.release(u)}};this.connect=async()=>{},this.end=async()=>{if(l.ended=!0,c.holds(u))try{await run(`rollback`)}finally{o.delete(l),c.release(u)}},this.queryObject=queryObject,this.createTransaction=e=>{if(!e)throw Error(`Transaction name must be a non-empty string`);return{begin:()=>queryObject(`begin`),commit:()=>queryObject(`commit`),rollback:()=>queryObject(`rollback`),queryObject}}},s=L.fn(defaultClient);return t.Client=s,f({Client:s,get executedQueries(){return r},get createdClients(){return i},clear(){assertNoOpenTransaction(`clear`),s.mockClear(),r.length=0,i.length=0},reset(){assertNoOpenTransaction(`reset`),s.mockReset(),s.mockImplementation(defaultClient),r.length=0,i.length=0}},()=>{t.Client=n})}var PendingStart=class{jobName;args;constructor(e,t){this.jobName=e,this.args=t}};async function runWorkflowLocally(e,t,n){let i=globalThis,a=i.tailor,c=r(),l=c!==void 0,u=createLocalJobRunner();n?.env!==void 0&&s({...n.env}),i.tailor={...a,workflow:createLocalWorkflowRuntime(a?.workflow,u.execJobFunction)};try{return await u.runJob(e.mainJob.name,t)}finally{a?i.tailor=a:delete i.tailor,n?.env!==void 0&&(l?s(c):o())}}function createLocalJobRunner(){let t,execJobFunction=(e,n)=>{if(!t)throw Error(`Cannot start workflow job "${e}" outside runWorkflowLocally() job execution.`);if(t.pending)throw t.pending;let r=d(n),i=t.cursor;t.cursor+=1;let a=t.records[i];if(a){if(assertSameStart(a,e,r),a.status===`rejected`)throw a.error;return d(a.result)}let o=new PendingStart(e,r);throw t.pending=o,o},runJob=async(n,r)=>{let i=e(n);if(!i)return null;let o=[];for(;;){let e={records:o,cursor:0},s=t;t=e;try{let t=await i(d(r),a());if(e.pending){await settlePendingStart(o,e.pending,runJob);continue}if(e.cursor!==o.length)throw Error(`Workflow job start sequence changed while replaying "${n}". Expected ${o.length} start(s), but replay reached ${e.cursor}.`);return d(t)}catch(t){let n=t instanceof PendingStart?t:e.pending;if(n){await settlePendingStart(o,n,runJob);continue}throw t}finally{t=s}}};return{runJob,execJobFunction}}async function settlePendingStart(e,t,n){try{e.push({jobName:t.jobName,args:t.args,status:`fulfilled`,result:await n(t.jobName,t.args)})}catch(n){e.push({jobName:t.jobName,args:t.args,status:`rejected`,error:n})}}function assertSameStart(e,t,n){if(e.jobName!==t||JSON.stringify(e.args)!==JSON.stringify(n))throw Error(`Workflow job start sequence changed while replaying. Expected ${e.jobName}(${JSON.stringify(e.args)}), but got ${t}(${JSON.stringify(n)}).`)}function createLocalWorkflowRuntime(e,n){return{execJobFunction:n,startWorkflow:async(n,r,i)=>e?await e.startWorkflow(n,r,i):(d(r),t),resumeWorkflowExecution:async t=>e?await e.resumeWorkflowExecution(t):t,wait:(t,n)=>{if(e)return e.wait(t,n);throw Error(`No wait handler for "${t}". Acquire mockWorkflow() and call setWaitHandler(...).`)},resolve:async(t,n,r)=>{if(e){await e.resolve(t,n,r);return}throw Error(`No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).`)}}}function unwrapValue(e){return A.is(e)?e.value:e}function insertRows(e){if(!x.is(e))throw Error(`insertRows: expected InsertQueryNode, got ${e.kind}`);let t=e.columns,n=e.values;if(t===void 0||n===void 0||!j.is(n))throw Error(`insertRows: unsupported insert shape; inspect query.node instead`);return n.values.map(e=>{if(!E.is(e)&&!k.is(e))throw Error(`insertRows: unsupported insert shape; inspect query.node instead`);let n=E.is(e)?e.values:e.values.map(unwrapValue),r={};return t.forEach((e,t)=>{r[e.column.name]=n[t]}),r})}function insertValues(e){let t=insertRows(e);if(t.length!==1)throw Error(`insertValues: query inserts ${t.length} rows; use insertRows() for multi-row inserts`);return c(t[0],`insertValues: first row missing`)}function updateValues(e){if(!O.is(e))throw Error(`updateValues: expected UpdateQueryNode, got ${e.kind}`);if(e.updates===void 0)throw Error(`updateValues: unsupported update shape; inspect query.node instead`);let t={};for(let n of e.updates){let e=n.column,r=y.is(e)?e.column.name:D.is(e)&&y.is(e.column)?e.column.column.name:void 0;if(r===void 0)throw Error(`updateValues: unsupported update shape; inspect query.node instead`);t[r]=unwrapValue(n.value)}return t}function toExecutedQuery(e){let t=e.query;return{kind:t.kind,sql:e.sql,parameters:e.parameters,node:t,insertRows:()=>insertRows(t),insertValues:()=>insertValues(t),updateValues:()=>updateValues(t)}}function toStagedResult(e){return Array.isArray(e)?{rows:e,numAffectedRows:void 0}:{rows:e.rows??[],numAffectedRows:e.numAffectedRows===void 0?void 0:BigInt(e.numAffectedRows)}}var MockState=class{executed=[];queue=[];resolver;enqueue(...e){this.queue.push(...e)}setResolver(e){this.resolver=e}next(e){let t=this.resolver?.(e);if(t!==void 0)return toStagedResult(t);let n=this.queue.shift();return n===void 0?{rows:[],numAffectedRows:void 0}:toStagedResult(n)}reset(){this.executed.length=0,this.queue.length=0,this.resolver=void 0}},MockConnection=class{state;constructor(e){this.state=e}async executeQuery(e){let t=toExecutedQuery(e);this.state.executed.push(t);let{rows:n,numAffectedRows:r}=this.state.next(t);return{rows:n,numAffectedRows:r??BigInt(n.length)}}streamQuery(){throw Error(`createKyselyMock: streaming is not supported`)}},MockDriver=class{state;constructor(e){this.state=e}async init(){}async acquireConnection(){return new MockConnection(this.state)}async beginTransaction(){}async commitTransaction(){}async rollbackTransaction(){}async releaseConnection(){}async destroy(){}};function byKind(e,t){return e.executed.filter(e=>e.kind===t)}function createKyselyMock(){let e=new MockState,t=new S({dialect:{createDriver:()=>new MockDriver(e),createQueryCompiler:()=>new T,createAdapter:()=>new C,createIntrospector:e=>new w(e)}});return{db:t,get executedQueries(){return e.executed},get selects(){return byKind(e,`SelectQueryNode`)},get inserts(){return byKind(e,`InsertQueryNode`)},get updates(){return byKind(e,`UpdateQueryNode`)},get deletes(){return byKind(e,`DeleteQueryNode`)},enqueueResult:t=>e.enqueue(t),enqueueResults:(...t)=>e.enqueue(...t),setQueryResolver:t=>e.setResolver(t),withTx:e=>t.transaction().execute(e),reset:()=>e.reset(),[Symbol.dispose]:()=>e.reset()}}var PGliteConnection=class{#e;constructor(e){this.#e=e}async executeQuery(e){let t=await this.#e.query(e.sql,[...e.parameters]);return{rows:t.rows,numAffectedRows:BigInt(t.affectedRows??0)}}streamQuery(){throw Error(`createKyselyPGlite: streaming is not supported`)}},PGliteDriver=class{#e;constructor(e){this.#e=e}async init(){}async acquireConnection(){return new PGliteConnection(this.#e)}async beginTransaction(e,t){let n=t.isolationLevel?[`start transaction`,`isolation level ${t.isolationLevel}`]:[`begin`];t.accessMode&&n.push(t.accessMode),await e.executeQuery(b.raw(n.join(` `)))}async commitTransaction(e){await e.executeQuery(b.raw(`commit`))}async rollbackTransaction(e){await e.executeQuery(b.raw(`rollback`))}async releaseConnection(){}async destroy(){await this.#e.close()}};function createKyselyPGlite(e){return new S({dialect:{createAdapter:()=>new C,createDriver:()=>new PGliteDriver(e),createIntrospector:e=>new w(e),createQueryCompiler:()=>new T}})}function tailorRuntime(e){return[createBlockPlugin(),createEnvironmentPlugin(e)]}export{createKyselyMock,createKyselyPGlite,mockAigateway,mockAuthconnection,mockFile,mockIconv,mockIdp,mockLogger,h as mockSecretmanager,mockTailordb,mockTailordbWithPGlite,mockWorkflow,runWorkflowLocally,tailorRuntime};
|
|
1
|
+
import{i as e,t}from"../registry-HlEaGvl5.mjs";import{a as n,c as r,i,o as a,s as o,u as s}from"../wait-point-invoker-eiP-IIux.mjs";import{t as c}from"../assert-WeXvmG4j.mjs";import{n as l,r as u}from"../node-builtins-DYfhPBnz.mjs";import{t as d}from"../platform-serialize-DkiTdHOt.mjs";import{i as f,n as p,r as m,t as h}from"../secretmanager-5olfnI1b.mjs";import{createRequire as g}from"node:module";import{isEqual as _}from"es-toolkit";import{fileURLToPath as v}from"node:url";import{ColumnNode as y,CompiledQuery as b,InsertQueryNode as x,Kysely as S,PostgresAdapter as C,PostgresIntrospector as w,PostgresQueryCompiler as T,PrimitiveValueListNode as E,ReferenceNode as D,UpdateQueryNode as O,ValueListNode as k,ValueNode as A,ValuesNode as j}from"kysely";import{dirname as M,isAbsolute as N,matchesGlob as P,relative as F,resolve as I}from"node:path";import{vi as L}from"vitest";function isBlockedModule(e){return u(e)}function getBlockedMessage(e){return l(e)}const R=[`**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}`],z=new Set([`ImportDeclaration`,`ExportNamedDeclaration`,`ExportAllDeclaration`]),B=new Set(`break.case.catch.class.const.continue.debugger.default.delete.do.else.enum.export.extends.false.finally.for.function.if.import.in.instanceof.new.null.return.super.switch.this.throw.true.try.typeof.var.void.while.with.yield.let.static.implements.interface.package.private.protected.public.await.arguments.eval`.split(`.`)),V=/^[A-Za-z_$]/,H=/^[A-Za-z0-9_$]*$/;function isSafeBindingName(e){if(B.has(e)||e.length===0)return!1;let t=e[0];return t!==void 0&&V.test(t)&&H.test(e.slice(1))}function buildBlockedReplacement(e,t){let n=JSON.stringify(t),r=`throw new Error(${n});`,i=`(() => { throw new Error(${n}); })()`;if(e.type===`ExportNamedDeclaration`){let t=e.specifiers??[],n=[];for(let e of t){let t=e.exported?.name;if(typeof t==`string`){if(t==="default"){n.push(`export default ${i};`);continue}if(!isSafeBindingName(t))return r;n.push(`export const ${t} = ${i};`)}}return n.length>0?n.join(` `):r}if(e.type===`ExportAllDeclaration`){let t=e.exported?.name;return typeof t==`string`&&isSafeBindingName(t)?`export const ${t} = ${i};`:r}return r}const toFileList=e=>Array.isArray(e)?e:e?[e]:[];let U;function supportsDefaultProjectInheritance(){if(U===void 0)try{let{version:e}=g(import.meta.url)(`vitest/package.json`);U=Number.parseInt(e,10)>=5}catch{U=!1}return U}function createBlockPlugin(){let isTestFile=()=>!1,isUserSourceFile=()=>!1;return{name:`tailor-runtime-block-node`,configResolved(e){let t=e.test,n=t?.root??e.root,toAbsolutePaths=(e,t)=>toFileList(e).map(e=>I(t,e)),r=new Set([...toAbsolutePaths(t?.setupFiles,n),...toAbsolutePaths(t?.globalSetup,n)]),i=[{root:n,patterns:t?.include??R}];for(let e of t?.projects??[]){let t=e.test;if(!t)continue;let a=t.root??n;for(let e of toAbsolutePaths(t.setupFiles,a))r.add(e);for(let e of toAbsolutePaths(t.globalSetup,a))r.add(e);i.push({root:a,patterns:t.include??R})}isTestFile=e=>r.has(e)?!0:i.some(({root:t,patterns:n})=>{let r=N(e)?F(t,e):e;return n.some(e=>P(r,e))}),isUserSourceFile=e=>{if(!N(e))return!1;let t=F(n,e);return t!==``&&!t.startsWith(`..`)&&!N(t)}},transform(e,t){let n=t.search(/[?#]/),r=n===-1?t:t.slice(0,n);if(isTestFile(r)||r.includes(`node_modules`)||!isUserSourceFile(r))return;let i;try{i=this.parse(e)}catch{return}let a=[];for(let e of i.body){if(!z.has(e.type))continue;let t=e.source?.value;typeof t==`string`&&isBlockedModule(t)&&a.push({start:e.start,end:e.end,replacement:buildBlockedReplacement(e,getBlockedMessage(t))})}if(a.length===0)return;let o=e;for(let e of a.toSorted((e,t)=>t.start-e.start))o=o.slice(0,e.start)+e.replacement+o.slice(e.end);return{code:o,map:null}}}}function setConfigEnv(e,t){e.env={...e.env,__TAILOR_RUNTIME_CONFIG:t}}function createEnvironmentPlugin(e){let t=M(v(import.meta.url)),n=I(t,`environment.mjs`),r=I(t,`setup.mjs`),selectsTailorRuntime=e=>e===`tailor-runtime`||e===n;return{name:`tailor-runtime-environment`,config(t){let i=t.test,a=!!i&&selectsTailorRuntime(i.environment);if(i&&a&&(i.environment=n),i?.projects)for(let o of i.projects){if(typeof o==`string`)continue;let i=o.test??={};if(!(i.environment===void 0&&a&&(o.extends===!0||o.extends===void 0&&supportsDefaultProjectInheritance()))&&!selectsTailorRuntime(i.environment)){e?.config&&setConfigEnv(i,``);continue}i.environment=n;let s=toFileList(i.setupFiles);if(s.includes(r)||(i.setupFiles=[...s,r]),e?.config){let n=o.root??i.root??t.root??process.cwd();setConfigEnv(i,I(n,e.config))}}if(e?.config&&i){let n=i.root??t.root??process.cwd();setConfigEnv(i,a?I(n,e.config):``)}let o=toFileList(i?.setupFiles);return i&&typeof i.setupFiles==`string`&&(i.setupFiles=o),!a||o.includes(r)?{}:{test:{setupFiles:[r]}}}}}function mockAigateway(e={}){let t=p(),n=t.aigateway,r={...e.urls};async function defaultGet(e){let t=r[e];if(t===void 0)throw Error(`No AI Gateway registered for "${e}". Acquire mockAigateway() and call setUrls(...).`);return{url:t}}let i=L.fn(defaultGet);return t.aigateway={get:i},f({get:i,setUrls(e){r=e},setUrl(e,t){r={...r,[e]:t}},get calls(){return i.mock.calls.map(([e])=>({name:e}))},clear(){i.mockClear()},reset(){r={},i.mockReset(),i.mockImplementation(defaultGet)}},()=>{t.aigateway=n})}function mockAuthconnection(e={}){let t=p(),n=t.authconnection,r={...e.tokens};async function defaultGetConnectionToken(t){let n=r[t];if(n)return n;if(e.onUnhandled===`error`)throw Error(`No AuthConnection token configured for "${t}"`);return{access_token:`mock-token`}}let i=L.fn(defaultGetConnectionToken);return t.authconnection={getConnectionToken:i},f({getConnectionToken:i,setTokens(e){r=e},setToken(e,t){r={...r,[e]:t}},get calls(){return i.mock.calls.map(([e])=>({connectionName:e}))},clear(){i.mockClear()},reset(){r={},i.mockReset(),i.mockImplementation(defaultGetConnectionToken)}},()=>{t.authconnection=n})}const W=[`upload`,`download`,`downloadAsBase64`,`delete`,`getMetadata`,`downloadStream`,`uploadStream`],G={upload:{metadata:{fileSize:0,sha256sum:``}},download:{data:new Uint8Array,metadata:{contentType:``,fileSize:0,sha256sum:``,lastUploadedAt:``}},downloadAsBase64:{data:``,metadata:{contentType:``,fileSize:0,sha256sum:``,lastUploadedAt:``}},getMetadata:{contentType:``,fileSize:0,sha256sum:``,urlPath:``},downloadStream:null,uploadStream:{metadata:{fileSize:0,sha256sum:``}}};function mockFile(e={}){let t=m(),n=t.file,{onUnhandled:r=`fallback`}=e,i=[],a=[],resolver=()=>null;function handle(e,t,n,a,o){if(i.length>0)return i.shift();let s=resolver(e,{method:e,namespace:t,tableName:n,fieldName:a,recordId:o});if(s!=null)return s;if(r===`error`)throw Error(`No File mock configured for "${e}"`);let c=G[e];return c===void 0?void 0:structuredClone(c)}let o=L.fn(async(...e)=>{let[t,n,r,i]=e;return handle(`upload`,t,n,r,i)}),s=L.fn(async(...e)=>handle(`download`,...e)),c=L.fn(async(...e)=>handle(`downloadAsBase64`,...e)),l=L.fn(async(...e)=>{handle(`delete`,...e)}),u=L.fn(async(...e)=>handle(`getMetadata`,...e)),d=L.fn(async(...e)=>handle(`downloadStream`,...e)??{body:new ReadableStream({start(e){e.close()}}),metadata:{contentType:``,fileSize:0,sha256sum:``,lastUploadedAt:``}}),p=L.fn(async(...e)=>{let[t,n,r,i]=e;return handle(`uploadStream`,t,n,r,i)}),h={upload:o,download:s,downloadAsBase64:c,delete:l,getMetadata:u,downloadStream:d,uploadStream:p};function track(e,t){return function(...n){return a.push({method:e,namespace:n[0],tableName:n[1],fieldName:n[2],recordId:n[3]}),t.apply(this,n)}}t.file={upload:track(`upload`,o),download:track(`download`,s),downloadAsBase64:track(`downloadAsBase64`,c),delete:track(`delete`,l),getMetadata:track(`getMetadata`,u),downloadStream:track(`downloadStream`,d),uploadStream:track(`uploadStream`,p)};function allMocks(){return W.map(e=>h[e])}let g={...h,setResolver(e){resolver=e},enqueueResult(e){i.push(e)},enqueueResults(...e){i.push(...e)},get calls(){return a},clear(){a.length=0;for(let e of allMocks())e.mockClear()},reset(){i.length=0,a.length=0,resolver=()=>null;for(let e of allMocks())e.mockReset()}};return f(g,()=>{t.file=n})}function isUtf8(e){return e===`UTF8`||e===`UTF-8`}function defaultIconvResult(e,t){switch(e){case`convert`:case`convertBuffer`:return isUtf8(t[2])?``:new Uint8Array;case`decode`:return``;case`encode`:return isUtf8(t[1])?``:new Uint8Array;case`encodings`:return[]}}function mockIconv(e={}){let t=p(),n=t.iconv,r=null,i=[];function resolve(t,n){if(r){let e=r(t,n);if(e!=null)return e}if(e.onUnhandled===`error`)throw Error(`No Iconv mock behavior configured for "${t}"`);return defaultIconvResult(t,n)}function defaultConvert(e,t,n){return resolve(`convert`,[e,t,n])}function defaultConvertBuffer(e,t,n){return resolve(`convertBuffer`,[e,t,n])}function defaultDecode(e,t){return resolve(`decode`,[e,t])}function defaultEncode(e,t){return resolve(`encode`,[e,t])}function defaultEncodings(){return resolve(`encodings`,[])}let a=L.fn(defaultConvert),o=L.fn(defaultConvertBuffer),s=L.fn(defaultDecode),c=L.fn(defaultEncode),l=L.fn(defaultEncodings);function track(e,t){return function(...n){return i.push({method:e,args:[...n]}),t.apply(this,n)}}let u=track(`convert`,a),d=track(`convertBuffer`,o),m=track(`decode`,s),h=track(`encode`,c),g=track(`encodings`,l);class MockIconv{#e;#t;constructor(e,t){this.#e=e,this.#t=t}convert(e){return u.call(this,e,this.#e,this.#t)}}t.iconv={convert:u,convertBuffer:d,decode:m,encode:h,encodings:g,Iconv:MockIconv};function clear(){i.length=0,a.mockClear(),o.mockClear(),s.mockClear(),c.mockClear(),l.mockClear()}return f({convert:a,convertBuffer:o,decode:s,encode:c,encodings:l,setResolver(e){r=e},get calls(){return i},clear,reset(){r=null,i.length=0,a.mockReset(),a.mockImplementation(defaultConvert),o.mockReset(),o.mockImplementation(defaultConvertBuffer),s.mockReset(),s.mockImplementation(defaultDecode),c.mockReset(),c.mockImplementation(defaultEncode),l.mockReset(),l.mockImplementation(defaultEncodings)}},()=>{t.iconv=n})}const K=[`users`,`user`,`userByName`,`createUser`,`updateUser`,`deleteUser`,`sendPasswordResetEmail`,`unenrollMfa`],q={id:`mock-id`,name:`mock-user`,disabled:!1,mfaEnrolled:!1,mfaFactorIds:[]},J={users:{users:[],nextPageToken:null,totalCount:0},user:q,userByName:q,createUser:q,updateUser:q,deleteUser:!0,sendPasswordResetEmail:!0,unenrollMfa:!0};function mockIdp(e={}){let t=p(),n=t.idp,{onUnhandled:r=`fallback`}=e,i=[],a=[],resolver=()=>null,o=new Map;function compatibilityArgs(e,t){return e===`users`&&t.length===0?[void 0]:t}function handle(e,t,n){if(i.length>0)return i.shift();let a=resolver(e,compatibilityArgs(e,t),n);if(a!=null)return a;if(r===`error`)throw Error(`No IdP mock configured for "${n}.${e}"`);return structuredClone(J[e])}function createNamespaceMocks(e){return{users:L.fn(async(...t)=>handle(`users`,t,e)),user:L.fn(async(...t)=>handle(`user`,t,e)),userByName:L.fn(async(...t)=>handle(`userByName`,t,e)),createUser:L.fn(async(...t)=>handle(`createUser`,t,e)),updateUser:L.fn(async(...t)=>handle(`updateUser`,t,e)),deleteUser:L.fn(async(...t)=>handle(`deleteUser`,t,e)),sendPasswordResetEmail:L.fn(async(...t)=>handle(`sendPasswordResetEmail`,t,e)),unenrollMfa:L.fn(async(...t)=>handle(`unenrollMfa`,t,e))}}function namespace(e){let t=o.get(e);if(t)return t;let n=createNamespaceMocks(e);return o.set(e,n),n}function track(e,t,n){return function(...r){return a.push({method:e,args:[...compatibilityArgs(e,r)],namespace:n}),t.apply(this,r)}}let defaultClient=function(e){let t=namespace(e.namespace);this.users=track(`users`,t.users,e.namespace),this.user=track(`user`,t.user,e.namespace),this.userByName=track(`userByName`,t.userByName,e.namespace),this.createUser=track(`createUser`,t.createUser,e.namespace),this.updateUser=track(`updateUser`,t.updateUser,e.namespace),this.deleteUser=track(`deleteUser`,t.deleteUser,e.namespace),this.sendPasswordResetEmail=track(`sendPasswordResetEmail`,t.sendPasswordResetEmail,e.namespace),this.unenrollMfa=track(`unenrollMfa`,t.unenrollMfa,e.namespace)},s=L.fn(defaultClient);t.idp={Client:s};function allMocks(){return[...o.values()].flatMap(e=>K.map(t=>e[t]))}return f({Client:s,namespace,setResolver(e){resolver=e},enqueueResult(e){i.push(e)},enqueueResults(...e){i.push(...e)},get calls(){return a},clear(){a.length=0,s.mockClear();for(let e of allMocks())e.mockClear()},reset(){i.length=0,a.length=0,resolver=()=>null,s.mockReset(),s.mockImplementation(defaultClient);for(let e of allMocks())e.mockReset()}},()=>{t.idp=n})}function mockLogger(e={}){let t=p(),n=t.logger,r=L.fn((e,t)=>{}),i=L.fn((e,t)=>{}),a=L.fn((e,t)=>{}),o=L.fn((e,t)=>{}),s=L.fn(e=>{});t.logger={debug:r,info:i,warn:a,error:o,setAttributes:s};let c={debug:r,info:i,warn:a,error:o};return f({debug:r,info:i,warn:a,error:o,setAttributes:s,get calls(){return Object.entries(c).flatMap(([e,t])=>t.mock.calls.map((n,r)=>({order:t.mock.invocationCallOrder[r]??0,call:{severity:e,message:n[0],attributes:n[1]}}))).toSorted((e,t)=>e.order-t.order).map(e=>e.call)},clear(){r.mockClear(),i.mockClear(),a.mockClear(),o.mockClear(),s.mockClear()},reset(){r.mockReset(),i.mockReset(),a.mockReset(),o.mockReset(),s.mockReset()}},()=>{t.logger=n})}function testRegex(e,t){let n=e.lastIndex;e.lastIndex=0;try{return e.test(t)}finally{e.lastIndex=n}}var MockQueryResult=class{command;rowCount;rows;constructor(e){this.command=``,this.rowCount=e.length,this.rows=e}};function mockTailordb(e={}){let t=m(),n=t.Client,r=[],i;function matchesQuery(e,t,n){if(typeof e==`function`)return e(t,n);if(typeof e==`string`)return t===e;if(e instanceof RegExp)return testRegex(e,t);let r;if(r=typeof e.sql==`string`?t===e.sql:testRegex(e.sql,t),!r||e.params===void 0)return r;if(typeof e.params==`function`)return e.params(n);let i=e.params;return n.length===i.length&&n.every((e,t)=>_(e,i[t]))}function queryResponse(e){if(e.type===`error`)throw e.error;return new MockQueryResult(e.rows)}async function defaultQuery(t,n=[]){for(let e=r.length-1;e>=0;--e){let i=r[e];if(!i||!matchesQuery(i.matcher,t,n))continue;let a=i.once.shift();if(a)return queryResponse(a);if(i.fallback)return queryResponse(i.fallback)}if(i)return new MockQueryResult(i(t,n)??[]);if(e.onUnhandled===`error`)throw Error(`No TailorDB query behavior matched: ${t}`);return new MockQueryResult([])}let a=L.fn(defaultQuery),defaultConnect=async()=>{},o=L.fn(defaultConnect),s=[];function enqueueRowsList(e){for(let t of e)a.mockImplementationOnce(async()=>new MockQueryResult(t))}let defaultClient=function(e){let t={namespace:e?.namespace,ended:!1};s.push(t),this.connect=o,this.end=L.fn(async()=>{t.ended=!0}),this.queryObject=a,this.createTransaction=e=>{if(!e)throw Error(`Transaction name must be a non-empty string`);return{begin:async()=>{},commit:async()=>{},rollback:async()=>{},queryObject:a}}},c=L.fn(defaultClient);return t.Client=c,f({Client:c,queryObject:a,setQueryResolver(e){i=e,a.mockImplementation(defaultQuery)},onQuery(e){let t={matcher:e,once:[]};r.push(t);let n={returnsRows(e){return t.fallback={type:`rows`,rows:e},n},returnsRowsOnce(e){return t.once.push({type:`rows`,rows:e}),n},rejects(e){return t.fallback={type:`error`,error:e},n},rejectsOnce(e){return t.once.push({type:`error`,error:e}),n}};return n},enqueueResult(...e){enqueueRowsList([e])},enqueueResults(...e){enqueueRowsList(e)},enqueueRows(...e){enqueueRowsList(e)},get executedQueries(){return a.mock.calls.map(([e,t])=>({query:e,params:t??[]}))},get createdClients(){return s},clear(){a.mockClear(),o.mockClear(),c.mockClear(),s.length=0},reset(){a.mockReset(),a.mockImplementation(defaultQuery),o.mockReset(),o.mockImplementation(defaultConnect),c.mockReset(),c.mockImplementation(defaultClient),s.length=0,r.length=0,i=void 0}},()=>{t.Client=n})}const Y=new WeakMap,X=new WeakMap,Z=new WeakMap;function replaceProcedure(e,t,n){let r=Z.get(n)??n,i=L.fn(function(...e){return Reflect.apply(r,this,e)});Z.set(i,r);let a=e;return a[t]=i,{mock:i,scoped:{mockClear:()=>i.mockClear(),mockReset:()=>i.mockReset(),restore:()=>{a[t]===i&&(a[t]=n)}}}}function replaceStart(e){return replaceProcedure(e,`start`,e.start)}function mockWorkflow(){let e=p(),a=e.workflow,c=r(),l=new Map,u=new Map,m=new Map,h=new Map,g=new Set,installKeyDispatcher=e=>{let t=h.get(e);if(t)return t;let n=i(e);if(!n)throw Error(`waitPointWith expects a wait point definition created by createWaitPoint or createWaitPoints.`);let r=n,a=n.wait,o=n.resolve,s=Y.get(a)??a,c=X.get(o)??o,l={perKey:new Map,originalWait:(e,t)=>s.call(n,e,t),originalResolve:(e,t,r)=>c.call(n,e,t,r)},dispatchWait=(e,t)=>{let n=l.perKey.get(e);return n?t===void 0?n.wait():n.wait(t):l.originalWait(e,t)},dispatchResolve=async(e,t,n)=>{let r=l.perKey.get(e);if(!r)return l.originalResolve(e,t,n);await r.resolve(t,n)};Y.set(dispatchWait,s),X.set(dispatchResolve,c),r.wait=dispatchWait,r.resolve=dispatchResolve;let eachSpy=e=>{for(let t of l.perKey.values()){let n=t;e(n.wait),e(n.resolve)}};return g.add({mockClear:()=>eachSpy(e=>e.mockClear()),mockReset:()=>eachSpy(e=>e.mockReset()),restore:()=>{r.wait=a,r.resolve=o,h.delete(e)}}),h.set(e,l),l},defaultExecJob=(e,t,n)=>{throw Error(`No workflow job mock for "${e}". Call mockWorkflow().setJobHandler(...) or enqueueResult(...), or use runWorkflowLocally() for local workflow execution.`)},defaultStartWorkflow=async(e,n,r)=>t,defaultResumeWorkflowExecution=async e=>e,_=L.fn(defaultExecJob),v=L.fn(defaultStartWorkflow),y=L.fn(defaultResumeWorkflowExecution),b=L.fn((e,t)=>null),x=L.fn(async(e,t,n)=>{});return e.workflow={execJobFunction:(...e)=>{let t=e.length>=3?_(e[0],d(e[1]),e[2]):_(e[0],d(e[1]));return t instanceof Promise?t.then(e=>d(e)):d(t)},startWorkflow:(...e)=>e.length>=3?v(e[0],d(e[1]),e[2]):v(e[0],d(e[1])),resumeWorkflowExecution:e=>y(e),wait:(e,t)=>b(e,d(t)),resolve:(e,t,n)=>x(e,t,e=>{let t=n(e);return t instanceof Promise?t.then(e=>d(e)):d(t)})},f({execJobFunction:_,startWorkflow:v,resumeWorkflowExecution:y,wait:b,resolve:x,job(e){let t=l.get(e);if(t)return t;let{mock:n,scoped:r}=replaceStart(e);return g.add(r),l.set(e,n),n},workflow(e){let t=u.get(e);if(t)return t;let{mock:n,scoped:r}=replaceStart(e);return u.set(e,n),g.add(r),n},waitPoint(e){let t=m.get(e);if(t)return t;let n=replaceProcedure(e,`wait`,e.wait),r=replaceProcedure(e,`resolve`,e.resolve),i=n.mock,a=r.mock;g.add(n.scoped),g.add(r.scoped);let o={wait:i,resolve:a,setResolvePayload(e){a.mockImplementation(async(t,n)=>{let r=await n(d(e));d(r)})}};return m.set(e,o),o},waitPointWith(e,t){let r=n(e.with(t));if(r===void 0)throw Error(`waitPointWith expects a wait point declared with $params. Use waitPoint() for a wait point with a fixed key.`);let i=installKeyDispatcher(e),a=i.perKey.get(r);if(a)return a;let o=L.fn(e=>Promise.resolve(i.originalWait(r,e))),s=L.fn((e,t)=>i.originalResolve(r,e,t)),c={wait:o,resolve:s,setResolvePayload(e){s.mockImplementation(async(t,n)=>{let r=await n(d(e));d(r)})}};return i.perKey.set(r,c),c},setJobHandler(e){_.mockImplementation((t,n,r)=>e(t,n,r))},enqueueResult(e){_.mockImplementationOnce(()=>e)},enqueueResults(...e){for(let t of e)_.mockImplementationOnce(()=>t)},get startedJobs(){return _.mock.calls.map(([e,t,n])=>({jobName:e,args:t,...n!==void 0&&{options:n}}))},setStartHandler(e){v.mockImplementation(typeof e==`function`?async(t,n,r)=>e(t,n,r):async()=>e)},setResumeHandler(e){y.mockImplementation(typeof e==`function`?async t=>e(t):async()=>e)},setWaitHandler:e=>{b.mockImplementation(typeof e==`function`?(t,n)=>e(t,n):()=>e)},setEnv(e){s({...e})},setResolveHandler(e){x.mockImplementation(async(t,n,r)=>{await e(t,n,r)})},get waitCalls(){return b.mock.calls.map(([e,t])=>({key:e,payload:t}))},get resolveCalls(){return x.mock.calls.map(([e,t])=>({executionId:e,key:t}))},clear(){_.mockClear(),v.mockClear(),y.mockClear(),b.mockClear(),x.mockClear();for(let e of g)e.mockClear()},reset(){_.mockReset(),_.mockImplementation(defaultExecJob),v.mockReset(),v.mockImplementation(defaultStartWorkflow),y.mockReset(),y.mockImplementation(defaultResumeWorkflowExecution),b.mockReset(),b.mockImplementation(()=>null),x.mockReset(),x.mockImplementation(async()=>{});for(let e of g)e.mockReset();o()}},()=>{for(let e of g)e.restore();e.workflow=a,c===void 0?o():s(c)})}var TransactionLock=class{#e=null;#t=[];holds(e){return this.#e===e}async acquire(e){for(;this.#e!==null;)await new Promise(e=>this.#t.push(e));this.#e=e}release(e){this.#e===e&&(this.#e=null,this.#t.shift()?.())}};const Q=/^\s*(?:begin|start\s+transaction)\b/i,$=/^\s*(?:commit\b|rollback\b(?!(?:\s+(?:work|transaction))?\s+to\b))/i;function toQueryObjectResult(e){return{command:e.command??(e.affectedRows?`UPDATE`:`SELECT`),rowCount:e.rowCount??(e.affectedRows||e.rows.length),rows:e.rows}}function mockTailordbWithPGlite(e){let t=m(),n=t.Client,r=[],i=[],a=new Map,o=new Set,assertNoOpenTransaction=e=>{if(o.size>0)throw Error(`mockTailordbWithPGlite: ${e}() cannot run while a transaction is open; commit, roll back, or end() its client first`)},defaultClient=function(t){let n=t?.namespace,s=n!==void 0&&Object.hasOwn(e.namespaces,n)?e.namespaces[n]:void 0;if(n===void 0||!s)throw Error(`mockTailordbWithPGlite: no PGlite instance registered for namespace "${n}"`);let c=a.get(s)??new TransactionLock;a.set(s,c);let l={namespace:n,ended:!1};i.push(l);let u=this,run=async(e,t)=>(r.push({namespace:n,query:e,params:t??[]}),toQueryObjectResult(await s.query(e,t??[]))),throwEnded=()=>{throw Error(`mockTailordbWithPGlite: query after end() on this client`)},acquire=async()=>{await c.acquire(u),l.ended&&(c.release(u),throwEnded())},queryObject=async(e,t)=>{if(l.ended&&throwEnded(),Q.test(e)){if(c.holds(u))throw Error(`mockTailordbWithPGlite: transaction already open on this client — run nested statements on the transaction callback's trx`);await acquire();try{let n=await run(e,t);return o.add(l),n}catch(e){throw c.release(u),e}}if($.test(e)){if(c.holds(u))try{return await run(e,t)}finally{o.delete(l),c.release(u)}await acquire();try{return await run(e,t)}finally{c.release(u)}}if(c.holds(u))return await run(e,t);await acquire();try{return await run(e,t)}finally{c.release(u)}};this.connect=async()=>{},this.end=async()=>{if(l.ended=!0,c.holds(u))try{await run(`rollback`)}finally{o.delete(l),c.release(u)}},this.queryObject=queryObject,this.createTransaction=e=>{if(!e)throw Error(`Transaction name must be a non-empty string`);return{begin:()=>queryObject(`begin`),commit:()=>queryObject(`commit`),rollback:()=>queryObject(`rollback`),queryObject}}},s=L.fn(defaultClient);return t.Client=s,f({Client:s,get executedQueries(){return r},get createdClients(){return i},clear(){assertNoOpenTransaction(`clear`),s.mockClear(),r.length=0,i.length=0},reset(){assertNoOpenTransaction(`reset`),s.mockReset(),s.mockImplementation(defaultClient),r.length=0,i.length=0}},()=>{t.Client=n})}var PendingStart=class{jobName;args;constructor(e,t){this.jobName=e,this.args=t}};async function runWorkflowLocally(e,t,n){let i=globalThis,a=i.tailor,c=r(),l=c!==void 0,u=createLocalJobRunner();n?.env!==void 0&&s({...n.env}),i.tailor={...a,workflow:createLocalWorkflowRuntime(a?.workflow,u.execJobFunction)};try{return await u.runJob(e.mainJob.name,t)}finally{a?i.tailor=a:delete i.tailor,n?.env!==void 0&&(l?s(c):o())}}function createLocalJobRunner(){let t,execJobFunction=(e,n)=>{if(!t)throw Error(`Cannot start workflow job "${e}" outside runWorkflowLocally() job execution.`);if(t.pending)throw t.pending;let r=d(n),i=t.cursor;t.cursor+=1;let a=t.records[i];if(a){if(assertSameStart(a,e,r),a.status===`rejected`)throw a.error;return d(a.result)}let o=new PendingStart(e,r);throw t.pending=o,o},runJob=async(n,r)=>{let i=e(n);if(!i)return null;let o=[];for(;;){let e={records:o,cursor:0},s=t;t=e;try{let t=await i(d(r),a());if(e.pending){await settlePendingStart(o,e.pending,runJob);continue}if(e.cursor!==o.length)throw Error(`Workflow job start sequence changed while replaying "${n}". Expected ${o.length} start(s), but replay reached ${e.cursor}.`);return d(t)}catch(t){let n=t instanceof PendingStart?t:e.pending;if(n){await settlePendingStart(o,n,runJob);continue}throw t}finally{t=s}}};return{runJob,execJobFunction}}async function settlePendingStart(e,t,n){try{e.push({jobName:t.jobName,args:t.args,status:`fulfilled`,result:await n(t.jobName,t.args)})}catch(n){e.push({jobName:t.jobName,args:t.args,status:`rejected`,error:n})}}function assertSameStart(e,t,n){if(e.jobName!==t||JSON.stringify(e.args)!==JSON.stringify(n))throw Error(`Workflow job start sequence changed while replaying. Expected ${e.jobName}(${JSON.stringify(e.args)}), but got ${t}(${JSON.stringify(n)}).`)}function createLocalWorkflowRuntime(e,n){return{execJobFunction:n,startWorkflow:async(n,r,i)=>e?await e.startWorkflow(n,r,i):(d(r),t),resumeWorkflowExecution:async t=>e?await e.resumeWorkflowExecution(t):t,wait:(t,n)=>{if(e)return e.wait(t,n);throw Error(`No wait handler for "${t}". Acquire mockWorkflow() and call setWaitHandler(...).`)},resolve:async(t,n,r)=>{if(e){await e.resolve(t,n,r);return}throw Error(`No resolve handler. Acquire mockWorkflow() and call setResolveHandler(...).`)}}}function unwrapValue(e){return A.is(e)?e.value:e}function insertRows(e){if(!x.is(e))throw Error(`insertRows: expected InsertQueryNode, got ${e.kind}`);let t=e.columns,n=e.values;if(t===void 0||n===void 0||!j.is(n))throw Error(`insertRows: unsupported insert shape; inspect query.node instead`);return n.values.map(e=>{if(!E.is(e)&&!k.is(e))throw Error(`insertRows: unsupported insert shape; inspect query.node instead`);let n=E.is(e)?e.values:e.values.map(unwrapValue),r={};return t.forEach((e,t)=>{r[e.column.name]=n[t]}),r})}function insertValues(e){let t=insertRows(e);if(t.length!==1)throw Error(`insertValues: query inserts ${t.length} rows; use insertRows() for multi-row inserts`);return c(t[0],`insertValues: first row missing`)}function updateValues(e){if(!O.is(e))throw Error(`updateValues: expected UpdateQueryNode, got ${e.kind}`);if(e.updates===void 0)throw Error(`updateValues: unsupported update shape; inspect query.node instead`);let t={};for(let n of e.updates){let e=n.column,r=y.is(e)?e.column.name:D.is(e)&&y.is(e.column)?e.column.column.name:void 0;if(r===void 0)throw Error(`updateValues: unsupported update shape; inspect query.node instead`);t[r]=unwrapValue(n.value)}return t}function toExecutedQuery(e){let t=e.query;return{kind:t.kind,sql:e.sql,parameters:e.parameters,node:t,insertRows:()=>insertRows(t),insertValues:()=>insertValues(t),updateValues:()=>updateValues(t)}}function toStagedResult(e){return Array.isArray(e)?{rows:e,numAffectedRows:void 0}:{rows:e.rows??[],numAffectedRows:e.numAffectedRows===void 0?void 0:BigInt(e.numAffectedRows)}}var MockState=class{executed=[];queue=[];resolver;enqueue(...e){this.queue.push(...e)}setResolver(e){this.resolver=e}next(e){let t=this.resolver?.(e);if(t!==void 0)return toStagedResult(t);let n=this.queue.shift();return n===void 0?{rows:[],numAffectedRows:void 0}:toStagedResult(n)}reset(){this.executed.length=0,this.queue.length=0,this.resolver=void 0}},MockConnection=class{state;constructor(e){this.state=e}async executeQuery(e){let t=toExecutedQuery(e);this.state.executed.push(t);let{rows:n,numAffectedRows:r}=this.state.next(t);return{rows:n,numAffectedRows:r??BigInt(n.length)}}streamQuery(){throw Error(`createKyselyMock: streaming is not supported`)}},MockDriver=class{state;constructor(e){this.state=e}async init(){}async acquireConnection(){return new MockConnection(this.state)}async beginTransaction(){}async commitTransaction(){}async rollbackTransaction(){}async releaseConnection(){}async destroy(){}};function byKind(e,t){return e.executed.filter(e=>e.kind===t)}function createKyselyMock(){let e=new MockState,t=new S({dialect:{createDriver:()=>new MockDriver(e),createQueryCompiler:()=>new T,createAdapter:()=>new C,createIntrospector:e=>new w(e)}});return{db:t,get executedQueries(){return e.executed},get selects(){return byKind(e,`SelectQueryNode`)},get inserts(){return byKind(e,`InsertQueryNode`)},get updates(){return byKind(e,`UpdateQueryNode`)},get deletes(){return byKind(e,`DeleteQueryNode`)},enqueueResult:t=>e.enqueue(t),enqueueResults:(...t)=>e.enqueue(...t),setQueryResolver:t=>e.setResolver(t),withTx:e=>t.transaction().execute(e),reset:()=>e.reset(),[Symbol.dispose]:()=>e.reset()}}var PGliteConnection=class{#e;constructor(e){this.#e=e}async executeQuery(e){let t=await this.#e.query(e.sql,[...e.parameters]);return{rows:t.rows,numAffectedRows:BigInt(t.affectedRows??0)}}streamQuery(){throw Error(`createKyselyPGlite: streaming is not supported`)}},PGliteDriver=class{#e;constructor(e){this.#e=e}async init(){}async acquireConnection(){return new PGliteConnection(this.#e)}async beginTransaction(e,t){let n=t.isolationLevel?[`start transaction`,`isolation level ${t.isolationLevel}`]:[`begin`];t.accessMode&&n.push(t.accessMode),await e.executeQuery(b.raw(n.join(` `)))}async commitTransaction(e){await e.executeQuery(b.raw(`commit`))}async rollbackTransaction(e){await e.executeQuery(b.raw(`rollback`))}async releaseConnection(){}async destroy(){await this.#e.close()}};function createKyselyPGlite(e){return new S({dialect:{createAdapter:()=>new C,createDriver:()=>new PGliteDriver(e),createIntrospector:e=>new w(e),createQueryCompiler:()=>new T}})}function tailorRuntime(e){return[createBlockPlugin(),createEnvironmentPlugin(e)]}export{createKyselyMock,createKyselyPGlite,mockAigateway,mockAuthconnection,mockFile,mockIconv,mockIdp,mockLogger,h as mockSecretmanager,mockTailordb,mockTailordbWithPGlite,mockWorkflow,runWorkflowLocally,tailorRuntime};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/docs/cli/tailordb.md
CHANGED
|
@@ -129,7 +129,7 @@ tailor tailordb migration generate [options]
|
|
|
129
129
|
| `--namespace <NAMESPACE>` | - | Target TailorDB namespace for --data-only (required if multiple namespaces exist) | No | - | - |
|
|
130
130
|
| `--rename <RENAME>` | - | Record a field, table, or nested member rename instead of remove + add (format: "Table.oldField:newField", "OldTable:NewTable", or "Table.field.oldMember:newMember"; repeatable). Renames require a migration script that copies the data. | No | - | - |
|
|
131
131
|
| `--drop <DROP>` | - | Confirm that a removed field, table, or nested member is a genuine removal, not a rename (format: "Table.field", "Table", or "Table.field.member"; repeatable). Required in non-interactive runs for a removal with rename candidates. | No | - | - |
|
|
132
|
-
| `--expand-contract <EXPAND_CONTRACT>` | - | Convert a field type through a temporary field (format: "Table.field"; repeatable). Generates two migrations.
|
|
132
|
+
| `--expand-contract <EXPAND_CONTRACT>` | - | Convert a field type, or a single value into an array, through a temporary field (format: "Table.field"; repeatable). Generates two migrations. | No | - | - |
|
|
133
133
|
|
|
134
134
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
135
135
|
|
package/docs/cli/workspace.md
CHANGED
|
@@ -16,15 +16,17 @@ See [Global Options](../cli-reference.md#global-options) for options available t
|
|
|
16
16
|
|
|
17
17
|
**Commands**
|
|
18
18
|
|
|
19
|
-
| Command | Description
|
|
20
|
-
| ----------------------------------------- |
|
|
21
|
-
| [`workspace app`](#workspace-app) | Manage workspace applications
|
|
22
|
-
| [`workspace create`](#workspace-create) | Create a new Tailor Platform workspace.
|
|
23
|
-
| [`workspace delete`](#workspace-delete) | Delete a Tailor Platform workspace.
|
|
24
|
-
| [`workspace get`](#workspace-get) | Show detailed information about a workspace
|
|
25
|
-
| [`workspace list`](#workspace-list) | List all Tailor Platform workspaces.
|
|
26
|
-
| [`workspace
|
|
27
|
-
| [`workspace
|
|
19
|
+
| Command | Description |
|
|
20
|
+
| ----------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
21
|
+
| [`workspace app`](#workspace-app) | Manage workspace applications |
|
|
22
|
+
| [`workspace create`](#workspace-create) | Create a new Tailor Platform workspace. |
|
|
23
|
+
| [`workspace delete`](#workspace-delete) | Delete a Tailor Platform workspace. |
|
|
24
|
+
| [`workspace get`](#workspace-get) | Show detailed information about a workspace |
|
|
25
|
+
| [`workspace list`](#workspace-list) | List all Tailor Platform workspaces. |
|
|
26
|
+
| [`workspace prune`](#workspace-prune) | Delete stale temporary workspaces, by name and age or by the expiry each recorded at creation. |
|
|
27
|
+
| [`workspace restore`](#workspace-restore) | Restore a deleted workspace |
|
|
28
|
+
| [`workspace ttl`](#workspace-ttl) | Manage when a workspace becomes prunable. |
|
|
29
|
+
| [`workspace user`](#workspace-user) | Manage workspace users |
|
|
28
30
|
|
|
29
31
|
### workspace app
|
|
30
32
|
|
|
@@ -98,17 +100,18 @@ tailor workspace create [options]
|
|
|
98
100
|
|
|
99
101
|
**Options**
|
|
100
102
|
|
|
101
|
-
| Option | Alias | Description
|
|
102
|
-
| ------------------------------------- | ----- |
|
|
103
|
-
| `--name <NAME>` | `-n` | Workspace name
|
|
104
|
-
| `--region <REGION>` | `-r` | Workspace region (us-west, asia-northeast)
|
|
105
|
-
| `--delete-protection` | `-d` | Enable delete protection
|
|
106
|
-
| `--organization-id <ORGANIZATION_ID>` | `-o` | Organization ID to workspace associate with
|
|
107
|
-
| `--folder-id <FOLDER_ID>` | `-f` | Folder ID to workspace associate with
|
|
108
|
-
| `--
|
|
109
|
-
| `--profile <
|
|
110
|
-
| `--profile
|
|
111
|
-
| `--
|
|
103
|
+
| Option | Alias | Description | Required | Default | Env |
|
|
104
|
+
| ------------------------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- | --------------------------------- |
|
|
105
|
+
| `--name <NAME>` | `-n` | Workspace name | Yes | - | - |
|
|
106
|
+
| `--region <REGION>` | `-r` | Workspace region (us-west, asia-northeast) | Yes | - | - |
|
|
107
|
+
| `--delete-protection` | `-d` | Enable delete protection | No | `false` | - |
|
|
108
|
+
| `--organization-id <ORGANIZATION_ID>` | `-o` | Organization ID to workspace associate with | No | - | `TAILOR_PLATFORM_ORGANIZATION_ID` |
|
|
109
|
+
| `--folder-id <FOLDER_ID>` | `-f` | Folder ID to workspace associate with | No | - | `TAILOR_PLATFORM_FOLDER_ID` |
|
|
110
|
+
| `--ttl <TTL>` | - | Record on the workspace itself when it becomes prunable, such as 30m, 24h, or 7d. `workspace prune --expired` deletes it once that has passed | No | - | - |
|
|
111
|
+
| `--profile-name <PROFILE_NAME>` | `-p` | Profile name to create | No | - | - |
|
|
112
|
+
| `--profile <PROFILE>` | - | Workspace profile used for authentication and Platform selection | No | - | `TAILOR_PLATFORM_PROFILE` |
|
|
113
|
+
| `--profile-user <PROFILE_USER>` | - | User email address or machine user client ID for the profile (defaults to current user) | No | - | - |
|
|
114
|
+
| `--permission <PERMISSION>` | - | Profile permission (requires --profile-name). 'read' blocks all write commands while the profile is active. | No | `"write"` | - |
|
|
112
115
|
|
|
113
116
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
114
117
|
|
|
@@ -170,6 +173,48 @@ tailor workspace list [options]
|
|
|
170
173
|
|
|
171
174
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
172
175
|
|
|
176
|
+
### workspace prune
|
|
177
|
+
|
|
178
|
+
Delete stale temporary workspaces, by name and age or by the expiry each recorded at creation.
|
|
179
|
+
|
|
180
|
+
**Usage**
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
tailor workspace prune [options]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Options**
|
|
187
|
+
|
|
188
|
+
| Option | Alias | Description | Required | Default | Env |
|
|
189
|
+
| --------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------- | ------------------------- |
|
|
190
|
+
| `--name <NAME>` | - | Select workspaces whose whole name matches this regular expression (repeatable) | No | - | - |
|
|
191
|
+
| `--older-than <OLDER_THAN>` | - | Minimum age since creation, such as 30m, 24h, or 7d. 0s disables the age check and requires a location. Required unless --expired is given | No | - | - |
|
|
192
|
+
| `--expired` | - | Select workspaces whose own --ttl expiry has passed, instead of by name and age. Requires --organization-root, --folder-id, or --personal | No | `false` | - |
|
|
193
|
+
| `--organization-root <ORGANIZATION_ID>` | - | Consider the workspaces directly under this organization, excluding those in its folders (repeatable) | No | - | - |
|
|
194
|
+
| `--folder-id <FOLDER_ID>` | - | Consider the workspaces in this folder (repeatable) | No | - | - |
|
|
195
|
+
| `--personal` | - | Consider the workspaces belonging to no organization and no folder | No | `false` | - |
|
|
196
|
+
| `--exclude <EXCLUDE>` | - | Keep a workspace with this exact name even when it matches (repeatable) | No | - | - |
|
|
197
|
+
| `--limit <LIMIT>` | - | Abort when more workspaces match than this, without deleting anything. 0 removes the cap | No | `20` | - |
|
|
198
|
+
| `--dry-run` | - | List the workspaces that would be deleted without deleting them | No | `false` | - |
|
|
199
|
+
| `--profile <PROFILE>` | - | Workspace profile used for authentication and Platform selection | No | - | `TAILOR_PLATFORM_PROFILE` |
|
|
200
|
+
| `--yes` | `-y` | Skip confirmation prompts | No | `false` | - |
|
|
201
|
+
|
|
202
|
+
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
203
|
+
|
|
204
|
+
**Notes**
|
|
205
|
+
|
|
206
|
+
Use this to reclaim workspaces left behind by CI runs, preview deployments, or interrupted local test runs. A workspace is deleted only when its whole name matches a --name pattern, it was created at least --older-than ago, and it is not excluded, delete-protected, or outside the requested locations. Run with --dry-run first to see what would be deleted.
|
|
207
|
+
|
|
208
|
+
With --expired the workspaces select themselves instead: each one is deleted only once the --ttl expiry it recorded at creation has passed, so callers need no --name or --older-than. A workspace that records no expiry is never deleted this way, and neither is one whose recorded expiry cannot be read. Because that expiry is recorded on the workspace rather than derived from its name, anything able to write the workspace's metadata can bring its deletion forward -- and writing a workspace's metadata is a lesser permission than deleting it. --expired therefore requires at least one location, and --name still applies on top.
|
|
209
|
+
|
|
210
|
+
Every workspace lives in exactly one location, and the location options name them explicitly: --organization-root selects the workspaces directly under an organization and none inside its folders, --folder-id selects the workspaces in one folder, and --personal selects the workspaces belonging to no organization and no folder. Each option can be given more than once, they combine as a union, and none of them is read from the environment -- a sweep covers exactly the locations spelled out on the command line. Selecting --personal is a deliberate choice to accept, for every organization-less workspace visible to this login, the expiry that anyone able to write a workspace's metadata may have recorded. Without any location option, a --name / --older-than sweep considers every visible workspace.
|
|
211
|
+
|
|
212
|
+
Restoring a workspace does not clear its recorded expiry, so a workspace restored after expiring is deleted again by the next --expired run. Restore it, then run `workspace ttl set` or `workspace ttl clear` before the next run — or keep it out of that run with --exclude.
|
|
213
|
+
|
|
214
|
+
Safety guards: the command aborts without deleting anything when more workspaces match than --limit allows (--dry-run still lists them all), both --expired and --older-than 0s (no age check) are only accepted together with at least one location option, and a location option that resolves to an empty value (an unset CI secret) is rejected instead of silently widening the sweep -- even when another location is given alongside it. Each workspace is re-read immediately before it is deleted and skipped when it no longer matches the name, location, exclusion, or delete-protection criteria that selected it. Unlike `workspace delete`, a single confirmation covers every listed candidate; pass --yes to skip it in CI. Deleted workspaces can be restored with `workspace restore` for a limited time.
|
|
215
|
+
|
|
216
|
+
Only workspaces visible to the current login (or the machine user in CI) are considered.
|
|
217
|
+
|
|
173
218
|
### workspace restore
|
|
174
219
|
|
|
175
220
|
Restore a deleted workspace
|
|
@@ -189,6 +234,74 @@ tailor workspace restore [options]
|
|
|
189
234
|
|
|
190
235
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
191
236
|
|
|
237
|
+
### workspace ttl
|
|
238
|
+
|
|
239
|
+
Manage when a workspace becomes prunable.
|
|
240
|
+
|
|
241
|
+
**Usage**
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
tailor workspace ttl [command]
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
248
|
+
|
|
249
|
+
**Commands**
|
|
250
|
+
|
|
251
|
+
| Command | Description |
|
|
252
|
+
| --------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
253
|
+
| [`workspace ttl set`](#workspace-ttl-set) | Record when a workspace becomes prunable, replacing any expiry it already records. |
|
|
254
|
+
| [`workspace ttl clear`](#workspace-ttl-clear) | Drop a workspace's recorded prune expiry. |
|
|
255
|
+
|
|
256
|
+
#### workspace ttl clear
|
|
257
|
+
|
|
258
|
+
Drop a workspace's recorded prune expiry.
|
|
259
|
+
|
|
260
|
+
**Usage**
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
tailor workspace ttl clear [options]
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Options**
|
|
267
|
+
|
|
268
|
+
| Option | Alias | Description | Required | Default | Env |
|
|
269
|
+
| ------------------------------- | ----- | ----------------- | -------- | ------- | ------------------------------ |
|
|
270
|
+
| `--workspace-id <WORKSPACE_ID>` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` |
|
|
271
|
+
| `--profile <PROFILE>` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` |
|
|
272
|
+
|
|
273
|
+
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
274
|
+
|
|
275
|
+
**Notes**
|
|
276
|
+
|
|
277
|
+
A workspace recording no expiry is never deleted by `workspace prune --expired`. Clearing an expiry the workspace does not record succeeds without changing anything.
|
|
278
|
+
|
|
279
|
+
#### workspace ttl set
|
|
280
|
+
|
|
281
|
+
Record when a workspace becomes prunable, replacing any expiry it already records.
|
|
282
|
+
|
|
283
|
+
**Usage**
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
tailor workspace ttl set [options]
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Options**
|
|
290
|
+
|
|
291
|
+
| Option | Alias | Description | Required | Default | Env |
|
|
292
|
+
| ------------------------------- | ----- | --------------------------------------------------------------------------- | -------- | ------- | ------------------------------ |
|
|
293
|
+
| `--workspace-id <WORKSPACE_ID>` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` |
|
|
294
|
+
| `--profile <PROFILE>` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` |
|
|
295
|
+
| `--ttl <TTL>` | - | Time from now until the workspace becomes prunable, such as 30m, 24h, or 7d | Yes | - | - |
|
|
296
|
+
|
|
297
|
+
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
298
|
+
|
|
299
|
+
**Notes**
|
|
300
|
+
|
|
301
|
+
The expiry runs from now, not from when the workspace was created, so `--ttl 24h` always leaves a full day regardless of the workspace's age. Use this to give a restored workspace a new expiry, or to record one after `workspace create --ttl` failed to.
|
|
302
|
+
|
|
303
|
+
This is not an auto-delete timer: it only makes the workspace eligible for `workspace prune --expired`, which still honors delete protection and its own filters.
|
|
304
|
+
|
|
192
305
|
### workspace user
|
|
193
306
|
|
|
194
307
|
Manage workspace users
|
package/docs/cli-reference.md
CHANGED
|
@@ -19,6 +19,12 @@ tailor <command> [options]
|
|
|
19
19
|
| `--verbose` | - | Enable verbose logging | No | `false` |
|
|
20
20
|
| `--json` | `-j` | Output as JSON | No | `false` |
|
|
21
21
|
|
|
22
|
+
### Progress and Detailed Logs
|
|
23
|
+
|
|
24
|
+
`generate` and `deploy` show service progress and failures on stderr. Pass `--verbose`
|
|
25
|
+
to include individual loaded files, plugin table changes, and generated file paths.
|
|
26
|
+
Generation reports completion for each plugin that finishes processing its output files.
|
|
27
|
+
|
|
22
28
|
### JSON Output
|
|
23
29
|
|
|
24
30
|
For commands that return structured results, passing `--json` writes one parseable JSON document
|
|
@@ -29,10 +35,68 @@ Commands that only perform side effects and do not define a structured result ma
|
|
|
29
35
|
even when `--json` is passed.
|
|
30
36
|
|
|
31
37
|
Errors, warnings, progress, and diagnostic messages are written to stderr. After argument parsing,
|
|
32
|
-
a command failure under `--json` emits a JSON error envelope to stderr.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
a command failure under `--json` emits a JSON error envelope to stderr. Failures you can act on — an
|
|
39
|
+
invalid or missing option, a resource that does not exist, an invalid configuration, or an unmet
|
|
40
|
+
precondition — carry a stable `error.code` such as `PROFILE_NOT_FOUND`, `TAILORDB_NAMESPACE_NOT_FOUND`,
|
|
41
|
+
or `MIGRATION_SCRIPT_REQUIRED`. Where a remediation exists, the envelope also includes
|
|
42
|
+
`error.suggestion`, `error.help` (the `--help` invocation for the failing command), `error.next` (a
|
|
43
|
+
runnable command), or `error.context`. `UNEXPECTED_ERROR` marks failures without a dedicated code,
|
|
44
|
+
including SDK-internal errors. Diagnostic lines may precede the error envelope, and stdout is not
|
|
45
|
+
guaranteed to contain an error object.
|
|
46
|
+
|
|
47
|
+
Authentication failures distinguish missing credentials (`AUTH_TOKEN_NOT_FOUND`), a missing saved
|
|
48
|
+
user (`AUTH_USER_NOT_FOUND`), an expired token (`AUTH_TOKEN_EXPIRED`), and a failed token refresh
|
|
49
|
+
(`AUTH_TOKEN_REFRESH_FAILED`). Login recovery preserves the selected profile. For saved identities,
|
|
50
|
+
the next step opens login help so you can reuse the original browser or machine-user login method. Permission and
|
|
51
|
+
connection failures include guidance in `error.suggestion`; API failures also identify the operation
|
|
52
|
+
and affected resources in `error.context`.
|
|
53
|
+
|
|
54
|
+
If deployment fails and saving recovery metadata also fails, `DEPLOY_METADATA_RECOVERY_FAILED`
|
|
55
|
+
includes separate `error.context.apply` and `error.context.recovery` errors, each retaining its code
|
|
56
|
+
and available recovery information. Inspect the current resource state before retrying: some writes
|
|
57
|
+
may have completed. `--verbose --json` additionally includes stack traces for both causes.
|
|
58
|
+
|
|
59
|
+
Generation hook failures use `PLUGIN_GENERATION_FAILED`. The error includes the failed hook
|
|
60
|
+
and each failing plugin's ID and error in `error.context.failures`; successful plugins are
|
|
61
|
+
excluded from that list.
|
|
62
|
+
|
|
63
|
+
### Verbose Output
|
|
64
|
+
|
|
65
|
+
Use `--verbose` to include debug diagnostics and error stack traces. `DEBUG=true` or
|
|
66
|
+
`RUNNER_DEBUG=1` also enables verbose output, including stacks in JSON errors. GitHub Actions
|
|
67
|
+
sets `RUNNER_DEBUG=1` when debug logging is enabled, so the same command automatically includes
|
|
68
|
+
these details in a debug run. These settings do not enable JSON output; pass `--json` separately.
|
|
69
|
+
|
|
70
|
+
Capture the original failure's stderr and exit code before retrying. Argument parsing and failures
|
|
71
|
+
before the CLI starts may produce plain text even with `--json`. A failed deployment may have
|
|
72
|
+
already applied changes, so inspect its output before deciding to run it again.
|
|
73
|
+
|
|
74
|
+
### GitHub Actions Annotations
|
|
75
|
+
|
|
76
|
+
When `GITHUB_ACTIONS` is exactly `true`, a command that ends in failure also writes one
|
|
77
|
+
`::error::` workflow command to stderr, so the failure appears as an annotation on the run
|
|
78
|
+
instead of only inside the scrolled log. The annotation repeats what the CLI already prints:
|
|
79
|
+
its `title` is the error code (`AUTH_TOKEN_NOT_FOUND`, `PLUGIN_GENERATION_FAILED`, ...), and its
|
|
80
|
+
body carries the same details, suggestion, and next action. Colors are stripped and newlines are
|
|
81
|
+
encoded, so the annotation is a single line.
|
|
82
|
+
|
|
83
|
+
Exactly one annotation is written per failed command, and only for the failure that ends it.
|
|
84
|
+
Warnings and individually reported problems stay plain stderr output. The bundled CLI plugins
|
|
85
|
+
(`seed`, `setup`, `tailordb-erd`) annotate their failures the same way. A command that exits
|
|
86
|
+
without reporting through the CLI's error path, such as one relaying a failed remote execution,
|
|
87
|
+
writes no annotation.
|
|
88
|
+
|
|
89
|
+
Set `TAILOR_GITHUB_ACTIONS_ANNOTATIONS=false` (also `off`, `no`, or `0`) to turn annotations off.
|
|
90
|
+
Passing `--json` also suppresses them, so a workflow step that parses `--json` output gets only the
|
|
91
|
+
error envelope on stderr. The flag is honored even when the command fails during argument parsing,
|
|
92
|
+
before the envelope itself becomes available.
|
|
93
|
+
|
|
94
|
+
An annotation does not by itself fail a step: the step still fails on the CLI's exit code, which
|
|
95
|
+
is unchanged. Workflows that already echo their own `::error::` around the CLI keep working;
|
|
96
|
+
those messages describe the workflow's own checks, which can fail even when the CLI succeeds.
|
|
97
|
+
|
|
98
|
+
Annotations do not yet carry `file=`/`line=` source locations, and `generate` and `deploy` do not
|
|
99
|
+
group their per-service progress.
|
|
36
100
|
|
|
37
101
|
## Common Options
|
|
38
102
|
|
|
@@ -83,6 +147,7 @@ You can use environment variables to configure workspace and authentication:
|
|
|
83
147
|
| `TAILOR_BUNDLE_CONCURRENCY` | Max concurrent bundle workers for `deploy` (resolvers/executors/workflows). Defaults to CPU count |
|
|
84
148
|
| `TAILOR_APPLY_CONCURRENCY` | Max concurrent platform RPCs during `apply`/`deploy`. Defaults to 16 |
|
|
85
149
|
| `VISUAL` / `EDITOR` | Preferred editor for commands that open files (e.g., `vim`, `code`, `nano`) |
|
|
150
|
+
| `TAILOR_GITHUB_ACTIONS_ANNOTATIONS` | GitHub Actions failure annotations: `on` (default) or `off` |
|
|
86
151
|
| `TAILOR_CRASH_REPORTS_LOCAL` | Local crash log writing: `on` (default) or `off` |
|
|
87
152
|
| `TAILOR_CRASH_REPORTS_REMOTE` | Automatic crash report submission: `off` (default) or `on` |
|
|
88
153
|
|
|
@@ -265,27 +330,31 @@ Commands for managing organizations and folders.
|
|
|
265
330
|
|
|
266
331
|
Commands for managing workspaces and profiles.
|
|
267
332
|
|
|
268
|
-
| Command | Description
|
|
269
|
-
| ----------------------------------------------------------------- |
|
|
270
|
-
| [workspace](./cli/workspace.md#workspace) | Manage Tailor Platform workspaces.
|
|
271
|
-
| [workspace app](./cli/workspace.md#workspace-app) | Manage workspace applications
|
|
272
|
-
| [workspace app health](./cli/workspace.md#workspace-app-health) | Check application schema health
|
|
273
|
-
| [workspace app list](./cli/workspace.md#workspace-app-list) | List applications in a workspace
|
|
274
|
-
| [workspace create](./cli/workspace.md#workspace-create) | Create a new Tailor Platform workspace.
|
|
275
|
-
| [workspace delete](./cli/workspace.md#workspace-delete) | Delete a Tailor Platform workspace.
|
|
276
|
-
| [workspace get](./cli/workspace.md#workspace-get) | Show detailed information about a workspace
|
|
277
|
-
| [workspace list](./cli/workspace.md#workspace-list) | List all Tailor Platform workspaces.
|
|
278
|
-
| [workspace
|
|
279
|
-
| [workspace
|
|
280
|
-
| [workspace
|
|
281
|
-
| [workspace
|
|
282
|
-
| [workspace
|
|
283
|
-
| [workspace user
|
|
284
|
-
| [
|
|
285
|
-
| [
|
|
286
|
-
| [
|
|
287
|
-
| [
|
|
288
|
-
| [profile
|
|
333
|
+
| Command | Description |
|
|
334
|
+
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
335
|
+
| [workspace](./cli/workspace.md#workspace) | Manage Tailor Platform workspaces. |
|
|
336
|
+
| [workspace app](./cli/workspace.md#workspace-app) | Manage workspace applications |
|
|
337
|
+
| [workspace app health](./cli/workspace.md#workspace-app-health) | Check application schema health |
|
|
338
|
+
| [workspace app list](./cli/workspace.md#workspace-app-list) | List applications in a workspace |
|
|
339
|
+
| [workspace create](./cli/workspace.md#workspace-create) | Create a new Tailor Platform workspace. |
|
|
340
|
+
| [workspace delete](./cli/workspace.md#workspace-delete) | Delete a Tailor Platform workspace. |
|
|
341
|
+
| [workspace get](./cli/workspace.md#workspace-get) | Show detailed information about a workspace |
|
|
342
|
+
| [workspace list](./cli/workspace.md#workspace-list) | List all Tailor Platform workspaces. |
|
|
343
|
+
| [workspace prune](./cli/workspace.md#workspace-prune) | Delete stale temporary workspaces, by name and age or by the expiry each recorded at creation. |
|
|
344
|
+
| [workspace restore](./cli/workspace.md#workspace-restore) | Restore a deleted workspace |
|
|
345
|
+
| [workspace ttl](./cli/workspace.md#workspace-ttl) | Manage when a workspace becomes prunable. |
|
|
346
|
+
| [workspace ttl clear](./cli/workspace.md#workspace-ttl-clear) | Drop a workspace's recorded prune expiry. |
|
|
347
|
+
| [workspace ttl set](./cli/workspace.md#workspace-ttl-set) | Record when a workspace becomes prunable, replacing any expiry it already records. |
|
|
348
|
+
| [workspace user](./cli/workspace.md#workspace-user) | Manage workspace users |
|
|
349
|
+
| [workspace user invite](./cli/workspace.md#workspace-user-invite) | Invite a user to a workspace |
|
|
350
|
+
| [workspace user list](./cli/workspace.md#workspace-user-list) | List users in a workspace |
|
|
351
|
+
| [workspace user remove](./cli/workspace.md#workspace-user-remove) | Remove a user from a workspace |
|
|
352
|
+
| [workspace user update](./cli/workspace.md#workspace-user-update) | Update a user's role in a workspace |
|
|
353
|
+
| [profile](./cli/workspace.md#profile) | Manage workspace profiles (user + workspace combinations). |
|
|
354
|
+
| [profile create](./cli/workspace.md#profile-create) | Create a new profile. |
|
|
355
|
+
| [profile delete](./cli/workspace.md#profile-delete) | Delete a profile. |
|
|
356
|
+
| [profile list](./cli/workspace.md#profile-list) | List all profiles. |
|
|
357
|
+
| [profile update](./cli/workspace.md#profile-update) | Update profile properties. |
|
|
289
358
|
|
|
290
359
|
### [Auth Resource Commands](./cli/auth.md)
|
|
291
360
|
|
package/docs/plugin/custom.md
CHANGED
|
@@ -324,6 +324,37 @@ const AuditLog = await getGeneratedTable(configPath, "@example/audit-log", null,
|
|
|
324
324
|
5. Caches the result to avoid redundant processing
|
|
325
325
|
6. Returns the generated table matching the specified kind
|
|
326
326
|
|
|
327
|
+
## getExtendedTable Helper
|
|
328
|
+
|
|
329
|
+
A table that plugins are attached to gains the fields those plugins return in `extends.fields`, but only in the table `tailor generate` registers — the object exported from the table's source file stays as written. `getExtendedTable()` returns the table with every plugin-added field applied, so tooling that reads the table at runtime sees the same fields `tailor generate` does.
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import { join } from "node:path";
|
|
333
|
+
import { getExtendedTable } from "@tailor-platform/sdk/plugin";
|
|
334
|
+
import { customer } from "./tailordb/customer";
|
|
335
|
+
|
|
336
|
+
const configPath = join(import.meta.dirname, "./tailor.config.ts");
|
|
337
|
+
|
|
338
|
+
const extendedCustomer = await getExtendedTable(configPath, customer);
|
|
339
|
+
extendedCustomer.fields.deletedAt; // added by a plugin attached with .plugin()
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**Parameters:**
|
|
343
|
+
|
|
344
|
+
- `configPath`: Path to `tailor.config.ts` (absolute or relative to cwd)
|
|
345
|
+
- `sourceTable`: The TailorDB table as exported from its source file
|
|
346
|
+
|
|
347
|
+
**How it works:**
|
|
348
|
+
|
|
349
|
+
1. Returns `sourceTable` itself when no plugin is attached to it
|
|
350
|
+
2. Loads and caches the config from the given path
|
|
351
|
+
3. Auto-resolves the namespace from config
|
|
352
|
+
4. Calls each attached plugin's `onTableLoaded()` in the order of the `.plugin()` calls, each seeing the fields the plugins before it added
|
|
353
|
+
5. Caches the result per config path and table
|
|
354
|
+
6. Returns a new table with the added fields; `sourceTable` is not changed
|
|
355
|
+
|
|
356
|
+
The seed schema files `tailor generate` writes for tables with plugins attached use this helper, so `tailor seed validate` checks plugin-added fields like the table's own.
|
|
357
|
+
|
|
327
358
|
## Examples
|
|
328
359
|
|
|
329
360
|
### Definition-time Plugin (Soft Delete)
|
|
@@ -646,10 +677,11 @@ of whether `.files()` or `.plugin()` was called first. `tailor generate` also re
|
|
|
646
677
|
collision at runtime, as a backstop for any case a table's static type doesn't otherwise catch.
|
|
647
678
|
|
|
648
679
|
This only affects the table's static type. The corresponding field exists on the table's
|
|
649
|
-
generated schema, and on the table
|
|
650
|
-
|
|
651
|
-
(`table.fields.status`) returns `undefined`, and `pickFields(["status"])`
|
|
652
|
-
with the table's originally declared fields,
|
|
680
|
+
generated schema, and on the table `tailor generate` registers, only once `extends.fields` is
|
|
681
|
+
applied; the table object exported from the source file never gains it. Reading an injected field
|
|
682
|
+
directly off that object (`table.fields.status`) returns `undefined`, and `pickFields(["status"])`
|
|
683
|
+
throws — call these only with the table's originally declared fields, or load the table with
|
|
684
|
+
[`getExtendedTable()`](#getextendedtable-helper) first.
|
|
653
685
|
|
|
654
686
|
To keep the declared type and the runtime implementation in sync, give `Plugin`'s optional third
|
|
655
687
|
type parameter the same shape and use it inside `onTableLoaded`:
|
|
@@ -386,7 +386,7 @@ The `env` values are injected at bundle time (the same mechanism as resolvers/ex
|
|
|
386
386
|
| Change field type (verified pair) | Yes | Yes | In-place for the pairs listed under [Field type changes](#field-type-changes); review the generated normalization scaffold and customize it only when existing values need transformation |
|
|
387
387
|
| Change field type (other pair) | Yes | Yes | Two migrations, generated together after you confirm — see [Converting a field type](#converting-a-field-type). Edit the conversion in the first; the second needs no changes. |
|
|
388
388
|
| Change array → single value | - | - | **Not supported** — see [Converting a field type](#converting-a-field-type) |
|
|
389
|
-
| Change single value → array |
|
|
389
|
+
| Change single value → array | Yes | Yes | Two migrations, generated together after you confirm — see [Converting a field type](#converting-a-field-type). Each stored value becomes a one-element array, so the conversion needs no edits. |
|
|
390
390
|
|
|
391
391
|
### Field type changes
|
|
392
392
|
|
|
@@ -460,7 +460,7 @@ The generated `never` annotation intentionally causes a TypeScript error until y
|
|
|
460
460
|
|
|
461
461
|
### Converting a field type
|
|
462
462
|
|
|
463
|
-
A field type change outside the verified in-place pairs — `string` → `integer`, for example — cannot be applied in one step, because the field would have to hold both shapes at once. `migration generate` offers to carry the values through a temporary field instead:
|
|
463
|
+
A field type change outside the verified in-place pairs — `string` → `integer`, for example — cannot be applied in one step, because the field would have to hold both shapes at once. The same holds when a single value becomes an array (`string` → `string[]`): the stored values must be rewritten as arrays before the field can take the new shape. `migration generate` offers to carry the values through a temporary field instead:
|
|
464
464
|
|
|
465
465
|
```
|
|
466
466
|
User.price changes from string to integer, which cannot be applied in one step.
|
|
@@ -469,9 +469,11 @@ User.price changes from string to integer, which cannot be applied in one step.
|
|
|
469
469
|
|
|
470
470
|
Confirming writes two migrations:
|
|
471
471
|
|
|
472
|
-
1. **The conversion.** Adds a temporary field (`priceMigrate`), converts each stored value into it, and clears and removes the original field. Edit the conversion expression before deploying: the generated `never` annotation fails your typecheck, and `tailordb migration validate` rejects the migration while the review marker is still there.
|
|
472
|
+
1. **The conversion.** Adds a temporary field (`priceMigrate`), converts each stored value into it, and clears and removes the original field. Edit the conversion expression before deploying: the generated `never` annotation fails your typecheck, and `tailordb migration validate` rejects the migration while the review marker is still there. When only the array-ness changes (`string` → `string[]`), the conversion stores each value as a one-element array and carries no review marker; when the element type changes as well (`integer` → `string[]`), you convert the element and the script wraps it.
|
|
473
473
|
2. **The rename.** Renames the temporary field back to `price`. Its copy script is complete, but this migration also carries every other schema change the same run picked up, so review it as you would any generated migration.
|
|
474
474
|
|
|
475
|
+
If converting to an array also reduces a decimal field's `scale` or removes enum values, the conversion keeps the review marker. Edit the element conversion to satisfy the target field before deploying.
|
|
476
|
+
|
|
475
477
|
`tailor deploy` applies both. Because the conversion only touches rows whose original value is still set, a re-run resumes where it stopped rather than converting a row twice.
|
|
476
478
|
|
|
477
479
|
The original field is removed in the first migration rather than the second, because the rename needs its name free. Your script can still read it while the conversion runs.
|
|
@@ -490,7 +492,7 @@ Without the flag the command fails rather than converting anything, so a scripte
|
|
|
490
492
|
|
|
491
493
|
Some changes are still rejected and need a temporary field you add yourself — add the new field, write a script that fills it and clears the old one, then remove the old field and rename the temporary one in a later migration:
|
|
492
494
|
|
|
493
|
-
-
|
|
495
|
+
- A field that is already an array: collapsing it into a single value has no answer the generated script could choose for you, and changing its element type (`string[]` → `integer[]`) is not generated either.
|
|
494
496
|
- A field that is unique, or that an index, relationship, permission, or table-level script names. Those keep pointing at the original name, which the conversion removes.
|
|
495
497
|
|
|
496
498
|
## Testing Pending Migrations
|