@stacksjs/actions 0.72.57 → 0.72.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/action.d.ts CHANGED
@@ -4,10 +4,13 @@ import type { ExtractParams, InferValidations, JobOptions, RequestInstance } fro
4
4
  * ts-validation `Validator<T>` rule with an optional error message.
5
5
  *
6
6
  * Kept loose at the index-signature level so existing actions with
7
- * untyped validation objects keep compiling. New code that wants the
8
- * body-inference benefit (stacksjs/stacks#1851 Phase 2b) declares
9
- * validations `as const` so {@link InferValidations} can read the
10
- * concrete rule types.
7
+ * untyped validation objects keep compiling. Anything that declares
8
+ * `validations` gets the body inference (stacksjs/stacks#1851 Phase 2b) for
9
+ * free - this used to say `as const` was needed for
10
+ * {@link InferValidations} to read the concrete rule types, and it is not:
11
+ * a `Validator<T>` carries its own output type, so an ordinary object
12
+ * literal infers exactly the same. The note sent people adding an `as const`
13
+ * that changed nothing.
11
14
  *
12
15
  * Exported so the router can run validations without redeclaring the
13
16
  * type (stacksjs/stacks#1870 R-3 — the previous copy in
@@ -33,10 +36,11 @@ export declare interface ActionResponse {
33
36
  description: string
34
37
  schema?: Record<string, unknown>
35
38
  }
36
- declare interface ActionOptions<TModel = string, TValidations extends ActionValidations | undefined = undefined, TPath extends string = '', /** * The payload `handle` receives when the action is invoked by something * other than the router - an event listener, for instance, which calls it * with the event object rather than a request (`app/Events.ts` maps * 'user:registered' straight onto an action name). Defaults to `never`, * which leaves every HTTP action typed exactly as before. */ TPayload = never, /** * What `handle` answers with, inferred from the handler body. * * `handle` used to be declared as returning the whole {@link ActionResult} * union, which is a complete description of what the router will accept and * a useless one for anybody downstream: the concrete shape an action * actually returns was erased the moment it was written down. A typed client * asking "what comes back from this endpoint" got the union back and could * say nothing more. * * Inferred, so nothing has to be annotated, and constrained to * {@link ActionResult} so the router's contract is unchanged. Defaults to * the full union, which is what an action whose return type cannot be * inferred falls back to - the behaviour every action had before. */ TResult extends ActionResult = ActionResult,> {
39
+ declare interface ActionOptions<TModel = string, TValidations extends ActionValidations | undefined = undefined, TPath extends string = '', /** * The payload `handle` receives when the action is invoked by something * other than the router - an event listener, for instance, which calls it * with the event object rather than a request (`app/Events.ts` maps * 'user:registered' straight onto an action name). Defaults to `never`, * which leaves every HTTP action typed exactly as before. */ TPayload = never, /** * What `handle` answers with, inferred from the handler body. * * `handle` used to be declared as returning the whole {@link ActionResult} * union, which is a complete description of what the router will accept and * a useless one for anybody downstream: the concrete shape an action * actually returns was erased the moment it was written down. A typed client * asking "what comes back from this endpoint" got the union back and could * say nothing more. * * Inferred, so nothing has to be annotated, and constrained to * {@link ActionResult} so the router's contract is unchanged. Defaults to * the full union, which is what an action whose return type cannot be * inferred falls back to - the behaviour every action had before. */ TResult extends ActionResult = ActionResult, /** * How this action is invoked, which decides what `handle` is handed. * * `'http'` (the default) means the router calls it with a request. * `'event'` means something dispatches to it with a payload - the * `app/Events.ts` map does exactly that, calling `handle(payload, event)` * with the event object and no request anywhere near it. * * The distinction was already real and only expressible as the fourth * positional type argument (`new Action<string, undefined, '', Payload>`), * so almost nothing declared it - and an action wired to an event while * written against a request threw `request.get is not a function` the first * time its event fired. Saying `invocation: 'event'` types `handle`'s * parameter as the payload, inferred from `validations`. */ TInvocation extends 'http' | 'event' = 'http',> {
37
40
  name?: string
38
41
  description?: string
39
42
  apiResponse?: boolean
43
+ invocation?: TInvocation
40
44
  validations?: TValidations
41
45
  method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
42
46
  rate?: JobOptions['rate']
@@ -59,7 +63,11 @@ declare interface ActionOptions<TModel = string, TValidations extends ActionVali
59
63
  ) => void | Response | Promise<void | Response>
60
64
  handle: {
61
65
  bivarianceHack: (
62
- request: [TPayload] extends [never] ? InferRequest<TModel, TValidations, TPath> : TPayload,
66
+ request: [TPayload] extends [never]
67
+ ? (TInvocation extends 'event'
68
+ ? ResolveBody<TModel, TValidations>
69
+ : InferRequest<TModel, TValidations, TPath>)
70
+ : TPayload,
63
71
  ) => TResult | Promise<TResult>
64
72
  }['bivarianceHack']
65
73
  dependencies?: () => Record<string, unknown>
@@ -115,10 +123,11 @@ export type ActionResult = | Response
115
123
  | boolean
116
124
  | object
117
125
  | unknown[];
118
- export declare class Action<TModel = string, TValidations extends ActionValidations | undefined = undefined, TPath extends string = '', TPayload = never, /** @see {@link ActionOptions} - inferred from `handle`'s return type. */ TResult extends ActionResult = ActionResult,> {
126
+ export declare class Action<TModel = string, TValidations extends ActionValidations | undefined = undefined, TPath extends string = '', TPayload = never, /** @see {@link ActionOptions} - inferred from `handle`'s return type. */ TResult extends ActionResult = ActionResult, /** @see {@link ActionOptions} - `'event'` types `handle` with the payload. */ TInvocation extends 'http' | 'event' = 'http',> {
119
127
  name?: string;
120
128
  description?: string;
121
129
  apiResponse?: boolean;
130
+ invocation?: TInvocation;
122
131
  rate?: ActionOptions['rate'];
123
132
  tries?: ActionOptions['tries'];
124
133
  backoff?: ActionOptions['backoff'];
@@ -134,13 +143,14 @@ export declare class Action<TModel = string, TValidations extends ActionValidati
134
143
  csrf?: boolean;
135
144
  authorize?: ActionOptions<TModel, TValidations, TPath>['authorize'];
136
145
  before?: ActionOptions<TModel, TValidations, TPath>['before'];
137
- handle: ActionOptions<TModel, TValidations, TPath, TPayload, TResult>['handle'];
146
+ handle: ActionOptions<TModel, TValidations, TPath, TPayload, TResult, TInvocation>['handle'];
138
147
  model?: string;
139
148
  modelDefinition?: TModel;
140
149
  constructor({
141
150
  name,
142
151
  description,
143
152
  apiResponse,
153
+ invocation,
144
154
  validations,
145
155
  handle,
146
156
  rate,
@@ -159,7 +169,7 @@ export declare class Action<TModel = string, TValidations extends ActionValidati
159
169
  authorize,
160
170
  before,
161
171
  dependencies,
162
- }: ActionOptions<TModel, TValidations, TPath, TPayload, TResult>);
172
+ }: ActionOptions<TModel, TValidations, TPath, TPayload, TResult, TInvocation>);
163
173
  get deps(): Record<string, unknown>;
164
174
  overrideDependencies(overrides: Record<string, unknown>): void;
165
175
  resetDependencies(): void;
package/dist/action.js CHANGED
@@ -1 +1 @@
1
- export class Action{name;description;apiResponse;rate;tries;backoff;enabled;path;method;validations;requestFile;responses;responseHeaders;requestHeaders;skipCsrf;csrf;authorize;before;handle;model;modelDefinition;_dependenciesFactory;_resolvedDeps;_depsOverrides;constructor({name,description,apiResponse,validations,handle,rate,tries,backoff,enabled,path,method,requestFile,responses,responseHeaders,requestHeaders,model,skipCsrf,csrf,authorize,before,dependencies}){this.name=name;this.description=description;this.apiResponse=apiResponse;this.validations=validations;this.rate=rate;this.tries=tries;this.backoff=backoff;this.enabled=enabled;this.path=path;this.method=method;this.handle=handle;this.requestFile=requestFile;this.responses=responses;this.responseHeaders=responseHeaders;this.requestHeaders=requestHeaders;this.skipCsrf=skipCsrf;this.csrf=csrf;this.authorize=authorize;this.before=before;this._dependenciesFactory=dependencies;this.modelDefinition=model;if(model&&typeof model==="object"&&"name"in model)this.model=model.name;else if(typeof model==="string")this.model=model}get deps(){if(!this._resolvedDeps)this._resolvedDeps=this._dependenciesFactory?.()??{};if(this._depsOverrides)return{...this._resolvedDeps,...this._depsOverrides};return this._resolvedDeps}overrideDependencies(overrides){this._depsOverrides={...this._depsOverrides??{},...overrides}}resetDependencies(){this._depsOverrides=void 0;this._resolvedDeps=void 0}}
1
+ export class Action{name;description;apiResponse;invocation;rate;tries;backoff;enabled;path;method;validations;requestFile;responses;responseHeaders;requestHeaders;skipCsrf;csrf;authorize;before;handle;model;modelDefinition;_dependenciesFactory;_resolvedDeps;_depsOverrides;constructor({name,description,apiResponse,invocation,validations,handle,rate,tries,backoff,enabled,path,method,requestFile,responses,responseHeaders,requestHeaders,model,skipCsrf,csrf,authorize,before,dependencies}){this.name=name;this.invocation=invocation;this.description=description;this.apiResponse=apiResponse;this.validations=validations;this.rate=rate;this.tries=tries;this.backoff=backoff;this.enabled=enabled;this.path=path;this.method=method;this.handle=handle;this.requestFile=requestFile;this.responses=responses;this.responseHeaders=responseHeaders;this.requestHeaders=requestHeaders;this.skipCsrf=skipCsrf;this.csrf=csrf;this.authorize=authorize;this.before=before;this._dependenciesFactory=dependencies;this.modelDefinition=model;if(model&&typeof model==="object"&&"name"in model)this.model=model.name;else if(typeof model==="string")this.model=model}get deps(){if(!this._resolvedDeps)this._resolvedDeps=this._dependenciesFactory?.()??{};if(this._depsOverrides)return{...this._resolvedDeps,...this._depsOverrides};return this._resolvedDeps}overrideDependencies(overrides){this._depsOverrides={...this._depsOverrides??{},...overrides}}resetDependencies(){this._depsOverrides=void 0;this._resolvedDeps=void 0}}
@@ -1 +1 @@
1
- import*as fs from"node:fs";import process from"node:process";import{runCommand}from"@stacksjs/cli";import{Action,NpmScript}from"@stacksjs/enums";import{log}from"@stacksjs/logging";import{frameworkPath,projectPath,storagePath}from"@stacksjs/path";import{ExitCode}from"@stacksjs/types";import{runNpmScript}from"@stacksjs/utils";import{runAction}from"../helpers";import{generateVsCodeCustomData as genVsCodeCustomData}from"../helpers/vscode-custom-data";import{generateProjectImages}from"./images";import{generateActionTypes}from"./action-types";import{generateEnvFiles}from"./env-files";export{generateProjectImages}from"./images";export{generateVSchema}from"./vschema";export async function invoke(options){if(options?.types)await generateTypes(options);else if(options?.entries)await generateLibEntries(options);else if(options?.webTypes)await generateWebTypes(options);else if(options?.customData)await generateVsCodeCustomData();else if(options?.ideHelpers)await generateIdeHelpers(options);else if(options?.componentMeta)await generateComponentMeta();else if(options?.coreSymlink)await generateCoreSymlink();else if(options?.openApiSpec)await generateOpenApiSpec();else if(options?.images)await generateProjectImages({verbose:options?.verbose})}export function generate(options){return invoke(options)}export async function generateLibEntries(options){const result=await runAction(Action.GenerateLibraryEntries,{...options,cwd:projectPath()});if(result.isErr){log.error("There was an error generating your library entry points",result.error);process.exit(ExitCode.FatalError)}log.success("Library entry points generated successfully")}export async function generateWebTypes(options){const result=await runNpmScript(NpmScript.GenerateWebTypes,options);if(result.isErr){log.error("There was an error generating the web-types.json file.",result.error);process.exit(ExitCode.FatalError)}log.success("Successfully generated the web-types.json file")}export async function generateVsCodeCustomData(){const result=await genVsCodeCustomData();if(result.isErr){log.error("There was an error generating the custom-elements.json file.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated the custom-elements.json file")}export async function generateIdeHelpers(options){const result=await runNpmScript(NpmScript.GenerateIdeHelpers,options);if(result.isErr){log.error("There was an error generating IDE helpers.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated IDE helpers")}export async function generateComponentMeta(){const result=await genVsCodeCustomData();if(result.isErr){log.error("There was an error generating your component meta information.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated component meta information")}export async function generateTypes(options){await generateEnvFiles();await generateActionTypes();const entry=frameworkPath("core/actions/src/generate/types.ts");if(!fs.existsSync(entry)){await import(`./types?t=${Date.now()}`);return}const result=await runNpmScript(NpmScript.GenerateTypes,{cwd:frameworkPath(),...options});if(result.isErr){log.error("There was an error generating your types.",result.error);throw result.error instanceof Error?result.error:Error(String(result.error))}log.success("Types were generated successfully")}export async function watchTypes(options){try{const manifestPath=`${frameworkPath()}/package.json`,text=fs.existsSync(manifestPath)?fs.readFileSync(manifestPath,"utf-8"):"";if(!(text?JSON.parse(text):{})?.scripts?.["generate:types"]){log.warn("[generate:types --watch] no `generate:types` script in framework package.json - type regeneration disabled. dev:api will keep running, but type definitions won't auto-refresh on model/config changes.");return}}catch{}const watched=[projectPath("app/Models"),storagePath("framework/defaults/app/Models"),projectPath("config"),projectPath("database/migrations")];log.info(`[generate:types --watch] watching ${watched.length} directories`);let pending=null,inflight=!1;const trigger=()=>{if(pending)clearTimeout(pending);pending=setTimeout(async()=>{if(inflight)return;inflight=!0;try{log.info("[generate:types --watch] change detected, regenerating\u2026");await generateTypes(options);log.success("[generate:types --watch] types up to date")}catch(err){log.error("[generate:types --watch] regeneration failed:",err)}finally{inflight=!1}},200)},watchers=[];for(const dir of watched)try{if(!fs.existsSync(dir))continue;const w=fs.watch(dir,{recursive:!0},()=>trigger());watchers.push(w)}catch(err){log.warn(`[generate:types --watch] cannot watch ${dir}: ${err}`)}if(watchers.length===0){log.warn("[generate:types --watch] no directories to watch - exiting");return}await new Promise((resolve)=>{process.once("SIGINT",()=>{log.info("[generate:types --watch] stopping");for(const w of watchers)try{w.close()}catch{}resolve()})})}export function generatePantryConfig(){log.success("Successfully generated `./pantry.yaml` based on your config")}export async function generateSeeder(){}export async function generateCoreSymlink(){const link=projectPath(".framework");if(fs.existsSync(link))await runCommand(`rm -f ${link}`);await runCommand(`ln -s ${frameworkPath()} ${link}`)}export async function generateOpenApiSpec(){const{generateOpenApi}=await import("@stacksjs/api");await generateOpenApi();log.success("Successfully generated Open API Spec")}
1
+ import*as fs from"node:fs";import process from"node:process";import{runCommand}from"@stacksjs/cli";import{Action,NpmScript}from"@stacksjs/enums";import{log}from"@stacksjs/logging";import{frameworkPath,projectPath,storagePath}from"@stacksjs/path";import{ExitCode}from"@stacksjs/types";import{runNpmScript}from"@stacksjs/utils";import{runAction}from"../helpers";import{generateVsCodeCustomData as genVsCodeCustomData}from"../helpers/vscode-custom-data";import{generateProjectImages}from"./images";import{generateActionTypes}from"./action-types";import{generateEnvFiles}from"./env-files";export{generateProjectImages}from"./images";export{generateVSchema}from"./vschema";export async function invoke(options){if(options?.types)await generateTypes(options);else if(options?.entries)await generateLibEntries(options);else if(options?.webTypes)await generateWebTypes(options);else if(options?.customData)await generateVsCodeCustomData();else if(options?.ideHelpers)await generateIdeHelpers(options);else if(options?.componentMeta)await generateComponentMeta();else if(options?.coreSymlink)await generateCoreSymlink();else if(options?.openApiSpec)await generateOpenApiSpec();else if(options?.images)await generateProjectImages({verbose:options?.verbose})}export function generate(options){return invoke(options)}export async function generateLibEntries(options){const result=await runAction(Action.GenerateLibraryEntries,{...options,cwd:projectPath()});if(result.isErr){log.error("There was an error generating your library entry points",result.error);process.exit(ExitCode.FatalError)}log.success("Library entry points generated successfully")}export async function generateWebTypes(options){const result=await runNpmScript(NpmScript.GenerateWebTypes,options);if(result.isErr){log.error("There was an error generating the web-types.json file.",result.error);process.exit(ExitCode.FatalError)}log.success("Successfully generated the web-types.json file")}export async function generateVsCodeCustomData(){const result=await genVsCodeCustomData();if(result.isErr){log.error("There was an error generating the custom-elements.json file.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated the custom-elements.json file")}export async function generateIdeHelpers(options){const result=await runNpmScript(NpmScript.GenerateIdeHelpers,options);if(result.isErr){log.error("There was an error generating IDE helpers.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated IDE helpers")}export async function generateComponentMeta(){const result=await genVsCodeCustomData();if(result.isErr){log.error("There was an error generating your component meta information.",result.error);process.exit(ExitCode.FatalError)}await runAction(Action.LintFix,{verbose:!0,cwd:projectPath()});log.success("Successfully generated component meta information")}export async function generateTypes(options){await generateEnvFiles();await generateActionTypes();try{const{generateServerAutoImportTypes}=await import("@stacksjs/server");await generateServerAutoImportTypes()}catch(error){log.debug("[generate:types] Could not refresh server auto-import declarations",{error})}const entry=frameworkPath("core/actions/src/generate/types.ts");if(!fs.existsSync(entry)){await import(`./types?t=${Date.now()}`);return}const result=await runNpmScript(NpmScript.GenerateTypes,{cwd:frameworkPath(),...options});if(result.isErr){log.error("There was an error generating your types.",result.error);throw result.error instanceof Error?result.error:Error(String(result.error))}log.success("Types were generated successfully")}export async function watchTypes(options){try{const manifestPath=`${frameworkPath()}/package.json`,text=fs.existsSync(manifestPath)?fs.readFileSync(manifestPath,"utf-8"):"";if(!(text?JSON.parse(text):{})?.scripts?.["generate:types"]){log.warn("[generate:types --watch] no `generate:types` script in framework package.json - type regeneration disabled. dev:api will keep running, but type definitions won't auto-refresh on model/config changes.");return}}catch{}const watched=[projectPath("app/Models"),storagePath("framework/defaults/app/Models"),projectPath("config"),projectPath("database/migrations")];log.info(`[generate:types --watch] watching ${watched.length} directories`);let pending=null,inflight=!1;const trigger=()=>{if(pending)clearTimeout(pending);pending=setTimeout(async()=>{if(inflight)return;inflight=!0;try{log.info("[generate:types --watch] change detected, regenerating\u2026");await generateTypes(options);log.success("[generate:types --watch] types up to date")}catch(err){log.error("[generate:types --watch] regeneration failed:",err)}finally{inflight=!1}},200)},watchers=[];for(const dir of watched)try{if(!fs.existsSync(dir))continue;const w=fs.watch(dir,{recursive:!0},()=>trigger());watchers.push(w)}catch(err){log.warn(`[generate:types --watch] cannot watch ${dir}: ${err}`)}if(watchers.length===0){log.warn("[generate:types --watch] no directories to watch - exiting");return}await new Promise((resolve)=>{process.once("SIGINT",()=>{log.info("[generate:types --watch] stopping");for(const w of watchers)try{w.close()}catch{}resolve()})})}export function generatePantryConfig(){log.success("Successfully generated `./pantry.yaml` based on your config")}export async function generateSeeder(){}export async function generateCoreSymlink(){const link=projectPath(".framework");if(fs.existsSync(link))await runCommand(`rm -f ${link}`);await runCommand(`ln -s ${frameworkPath()} ${link}`)}export async function generateOpenApiSpec(){const{generateOpenApi}=await import("@stacksjs/api");await generateOpenApi();log.success("Successfully generated Open API Spec")}
@@ -1 +1 @@
1
- var {require}=import.meta;import{existsSync}from"node:fs";import{homedir}from"node:os";import{delimiter,join}from"node:path";import process from"node:process";import{buddyOptions,runCommand}from"@stacksjs/cli";import{err}from"@stacksjs/error-handling";import{log}from"@stacksjs/logging";import*as p from"@stacksjs/path";export function publishedActionCandidates(action,packageRoot){let root=packageRoot;if(!root)try{const pkgUrl=import.meta.resolve("@stacksjs/actions/package.json");if(pkgUrl){const pkgPath=new URL(pkgUrl).pathname;root=pkgPath.slice(0,pkgPath.lastIndexOf("/"))}}catch{return[]}if(!root)return[];return[`${root}/dist/${action}.js`,`${root}/dist/src/${action}.js`,`${root}/src/${action}.ts`]}export function developmentConditionForProject(projectRoot){return existsSync(join(projectRoot,"storage/framework/core"))&&existsSync(join(projectRoot,"node_modules/@stacksjs/env/src/index.ts"))?"--conditions development":""}export function actionNodePath(projectRoot,existingNodePath){const nodeModulesPath=join(projectRoot,"node_modules"),pantryPath=join(projectRoot,"pantry"),paths=[nodeModulesPath];for(const entry of existingNodePath?.split(delimiter)??[])if(entry&&entry!==nodeModulesPath&&entry!==pantryPath&&!paths.includes(entry))paths.push(entry);paths.push(pantryPath);return paths.join(delimiter)}async function resolveActionFile(action,projectRoot){const candidates=[];if(projectRoot)candidates.push(join(projectRoot,`storage/framework/core/actions/src/${action}.ts`));candidates.push(p.actionsPath(`src/${action}.ts`));candidates.push(...publishedActionCandidates(action));for(const candidate of candidates)if(await Bun.file(candidate).exists())return candidate;return null}export async function runAction(action,options){log.debug(`[action] Running: ${action}`);if(action==="dev/views")try{const nodePath=actionNodePath(p.projectPath(),process.env.NODE_PATH);if(process.env.NODE_PATH!==nodePath){process.env.NODE_PATH=nodePath;require("module").Module._initPaths?.()}const viewsEntries=[p.projectPath("storage/framework/core/actions/src/dev/views.ts"),p.frameworkPath("actions/src/dev/views.ts"),...publishedActionCandidates("dev/views")];for(const entry of viewsEntries)if(existsSync(entry)){await import(entry);return{ok:!0,value:{}}}return err("dev/views entry not found")}catch(error){return err(`Failed to start dev server: ${error}`)}const isLikelyCoreAction=action.includes("/")||["dev","build","install","upgrade","migrate"].some((prefix)=>action.startsWith(prefix)),userActionsBase=options?.cwd?join(String(options.cwd),"app/Actions"):p.userActionsPath();if(!isLikelyCoreAction&&existsSync(userActionsBase)){const glob=new Bun.Glob("**/*.{ts,js}"),scanOptions={cwd:userActionsBase,onlyFiles:!0,absolute:!0},matchingFiles=[],basePath=userActionsBase;for await(const file of glob.scan(scanOptions)){if(file.replace(`${basePath}/`,"").replace(/\.(ts|js)$/,"")===action||file.endsWith(`${action}.ts`)||file.endsWith(`${action}.js`)){log.debug(`[action] Resolved: ${action} \u2192 ${file}`);return await(await import(file)).default.handle(void 0)}matchingFiles.push(file)}for(const file of matchingFiles)try{const a=await import(file);if(a.name===action){log.debug(`[action] Resolved: ${action} \u2192 ${file}`);return await a.handle()}}catch(error){}}const path=await resolveActionFile(action,options?.cwd?String(options.cwd):void 0);if(!path)return err(`Action '${action}' not found in storage/framework/core/actions/src or @stacksjs/actions`);log.debug(`[action] Resolved: ${action} \u2192 ${path}`);const isDevAction=action.startsWith("dev/"),watchFlag=developmentWatchFlag(action),developmentCondition=developmentConditionForProject(p.projectPath()),opts=isDevAction?"":buddyOptions(options)||"",cmd=["bun",developmentCondition,watchFlag,path,opts].filter(Boolean).join(" "),nodePath=actionNodePath(p.projectPath(),process.env.NODE_PATH),shouldInherit=options?.verbose||isDevAction&&!options?.quiet,optionsWithCwd={cwd:options?.cwd||p.projectPath(),...options,stdout:shouldInherit?"inherit":void 0,stderr:shouldInherit?"inherit":void 0,env:{...options?.env,NODE_PATH:nodePath,...isDevAction?{STACKS_DEV_SERVER:"1"}:{}}},result=await runCommand(cmd,optionsWithCwd);log.debug(`[action] Completed: ${action}`);return result}export function developmentWatchFlag(action){if(!action.startsWith("dev/"))return"";return action==="dev/dashboard"||action==="dev/desktop"?"":"--watch"}export async function runActions(actions,options){if(!actions.length)return err("No actions were specified");for(const action of actions)if(!hasAction(action))return err(`The specified action "${action}" does not exist`);return await runActionSequence(actions,options)}export async function runActionSequence(actions,options,runner=runAction){let result;for(const action of actions){result=await runner(action,options);if(result?.isErr)return result}return result}export function hasAction(action){const userActionPatterns=[`${action}.ts`,`${action}`,`Dashboard/${action}.ts`,`Dashboard/${action}`,`Buddy/${action}.ts`,`Buddy/${action}`],actionPatterns=[`src/${action}.ts`,`src/${action}`,`${action}.ts`,`${action}`];return[...userActionPatterns.map((pattern)=>p.userActionsPath(pattern)),...actionPatterns.map((pattern)=>p.actionsPath(pattern)),...publishedActionCandidates(action)].some((candidate)=>existsSync(candidate))}
1
+ var {require}=import.meta;import{existsSync}from"node:fs";import{delimiter,join}from"node:path";import process from"node:process";import{buddyOptions,runCommand}from"@stacksjs/cli";import{err}from"@stacksjs/error-handling";import{log}from"@stacksjs/logging";import*as p from"@stacksjs/path";export function publishedActionCandidates(action,packageRoot){let root=packageRoot;if(!root)try{const pkgUrl=import.meta.resolve("@stacksjs/actions/package.json");if(pkgUrl){const pkgPath=new URL(pkgUrl).pathname;root=pkgPath.slice(0,pkgPath.lastIndexOf("/"))}}catch{return[]}if(!root)return[];return[`${root}/dist/${action}.js`,`${root}/dist/src/${action}.js`,`${root}/src/${action}.ts`]}export function developmentConditionForProject(projectRoot){return existsSync(join(projectRoot,"storage/framework/core"))&&existsSync(join(projectRoot,"node_modules/@stacksjs/env/src/index.ts"))?"--conditions development":""}export function actionNodePath(projectRoot,existingNodePath){const nodeModulesPath=join(projectRoot,"node_modules"),pantryPath=join(projectRoot,"pantry"),paths=[nodeModulesPath];for(const entry of existingNodePath?.split(delimiter)??[])if(entry&&entry!==nodeModulesPath&&entry!==pantryPath&&!paths.includes(entry))paths.push(entry);paths.push(pantryPath);return paths.join(delimiter)}async function resolveActionFile(action,projectRoot){const candidates=[];if(projectRoot)candidates.push(join(projectRoot,`storage/framework/core/actions/src/${action}.ts`));candidates.push(p.actionsPath(`src/${action}.ts`));candidates.push(...publishedActionCandidates(action));for(const candidate of candidates)if(await Bun.file(candidate).exists())return candidate;return null}export async function runAction(action,options){log.debug(`[action] Running: ${action}`);if(action==="dev/views")try{const nodePath=actionNodePath(p.projectPath(),process.env.NODE_PATH);if(process.env.NODE_PATH!==nodePath){process.env.NODE_PATH=nodePath;require("module").Module._initPaths?.()}const viewsEntries=[p.projectPath("storage/framework/core/actions/src/dev/views.ts"),p.frameworkPath("actions/src/dev/views.ts"),...publishedActionCandidates("dev/views")];for(const entry of viewsEntries)if(existsSync(entry)){await import(entry);return{ok:!0,value:{}}}return err("dev/views entry not found")}catch(error){return err(`Failed to start dev server: ${error}`)}const isLikelyCoreAction=action.includes("/")||["dev","build","install","upgrade","migrate"].some((prefix)=>action.startsWith(prefix)),userActionsBase=options?.cwd?join(String(options.cwd),"app/Actions"):p.userActionsPath();if(!isLikelyCoreAction&&existsSync(userActionsBase)){const glob=new Bun.Glob("**/*.{ts,js}"),scanOptions={cwd:userActionsBase,onlyFiles:!0,absolute:!0},matchingFiles=[],basePath=userActionsBase;for await(const file of glob.scan(scanOptions)){if(file.replace(`${basePath}/`,"").replace(/\.(ts|js)$/,"")===action||file.endsWith(`${action}.ts`)||file.endsWith(`${action}.js`)){log.debug(`[action] Resolved: ${action} \u2192 ${file}`);return await(await import(file)).default.handle(void 0)}matchingFiles.push(file)}for(const file of matchingFiles)try{const a=await import(file);if(a.name===action){log.debug(`[action] Resolved: ${action} \u2192 ${file}`);return await a.handle()}}catch(error){}}const path=await resolveActionFile(action,options?.cwd?String(options.cwd):void 0);if(!path)return err(`Action '${action}' not found in storage/framework/core/actions/src or @stacksjs/actions`);log.debug(`[action] Resolved: ${action} \u2192 ${path}`);const isDevAction=action.startsWith("dev/"),watchFlag=developmentWatchFlag(action),developmentCondition=developmentConditionForProject(p.projectPath()),opts=isDevAction?"":buddyOptions(options)||"",cmd=["bun",developmentCondition,watchFlag,path,opts].filter(Boolean).join(" "),nodePath=actionNodePath(p.projectPath(),process.env.NODE_PATH),shouldInherit=options?.verbose||isDevAction&&!options?.quiet,optionsWithCwd={cwd:options?.cwd||p.projectPath(),...options,stdout:shouldInherit?"inherit":void 0,stderr:shouldInherit?"inherit":void 0,env:{...options?.env,NODE_PATH:nodePath,...isDevAction?{STACKS_DEV_SERVER:"1"}:{}}},result=await runCommand(cmd,optionsWithCwd);log.debug(`[action] Completed: ${action}`);return result}export function developmentWatchFlag(action){if(!action.startsWith("dev/"))return"";return action==="dev/dashboard"||action==="dev/desktop"?"":"--watch"}export async function runActions(actions,options){if(!actions.length)return err("No actions were specified");for(const action of actions)if(!hasAction(action))return err(`The specified action "${action}" does not exist`);return await runActionSequence(actions,options)}export async function runActionSequence(actions,options,runner=runAction){let result;for(const action of actions){result=await runner(action,options);if(result?.isErr)return result}return result}export function hasAction(action){const userActionPatterns=[`${action}.ts`,`${action}`,`Dashboard/${action}.ts`,`Dashboard/${action}`,`Buddy/${action}.ts`,`Buddy/${action}`],actionPatterns=[`src/${action}.ts`,`src/${action}`,`${action}.ts`,`${action}`];return[...userActionPatterns.map((pattern)=>p.userActionsPath(pattern)),...actionPatterns.map((pattern)=>p.actionsPath(pattern)),...publishedActionCandidates(action)].some((candidate)=>existsSync(candidate))}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/actions",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.72.57",
5
+ "version": "0.72.61",
6
6
  "description": "The Stacks actions.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -56,38 +56,39 @@
56
56
  "scripts": {
57
57
  "build": "bun build.ts",
58
58
  "typecheck": "bun tsc --noEmit",
59
+ "typecheck:types": "bun tsc --noEmit -p tsconfig.type-tests.json --pretty false",
59
60
  "prepublishOnly": "bun run build"
60
61
  },
61
62
  "dependencies": {
62
- "@stacksjs/config": "0.72.57",
63
+ "@stacksjs/config": "0.72.61",
63
64
  "@stacksjs/bumpx": "^0.2.6",
64
65
  "@stacksjs/bunpress": "^0.2.8",
65
66
  "@stacksjs/logsmith": "^0.2.3",
66
- "@stacksjs/registry": "0.72.57",
67
- "@stacksjs/stx": "^0.2.219",
67
+ "@stacksjs/registry": "0.72.61",
68
+ "@stacksjs/stx": "^0.2.227",
68
69
  "@stacksjs/ts-cloud": "^0.11.4",
69
70
  "@stacksjs/ts-md": "^0.1.1"
70
71
  },
71
72
  "devDependencies": {
72
- "@stacksjs/api": "0.72.57",
73
- "@stacksjs/cli": "0.72.57",
74
- "@stacksjs/database": "0.72.57",
73
+ "@stacksjs/api": "0.72.61",
74
+ "@stacksjs/cli": "0.72.61",
75
+ "@stacksjs/database": "0.72.61",
75
76
  "@stacksjs/tlsx": "^0.13.2",
76
77
  "better-dx": "^0.2.24",
77
- "@stacksjs/dns": "0.72.57",
78
- "@stacksjs/enums": "0.72.57",
79
- "@stacksjs/env": "0.72.57",
80
- "@stacksjs/error-handling": "0.72.57",
81
- "@stacksjs/image": "0.72.57",
82
- "@stacksjs/logging": "0.72.57",
83
- "@stacksjs/path": "0.72.57",
84
- "@stacksjs/security": "0.72.57",
85
- "@stacksjs/cms": "0.72.57",
86
- "@stacksjs/sites": "0.72.57",
87
- "@stacksjs/storage": "0.72.57",
88
- "@stacksjs/strings": "0.72.57",
89
- "@stacksjs/utils": "0.72.57",
90
- "@stacksjs/validation": "0.72.57"
78
+ "@stacksjs/dns": "0.72.61",
79
+ "@stacksjs/enums": "0.72.61",
80
+ "@stacksjs/env": "0.72.61",
81
+ "@stacksjs/error-handling": "0.72.61",
82
+ "@stacksjs/image": "0.72.61",
83
+ "@stacksjs/logging": "0.72.61",
84
+ "@stacksjs/path": "0.72.61",
85
+ "@stacksjs/security": "0.72.61",
86
+ "@stacksjs/cms": "0.72.61",
87
+ "@stacksjs/sites": "0.72.61",
88
+ "@stacksjs/storage": "0.72.61",
89
+ "@stacksjs/strings": "0.72.61",
90
+ "@stacksjs/utils": "0.72.61",
91
+ "@stacksjs/validation": "0.72.61"
91
92
  },
92
93
  "peerDependencies": {
93
94
  "pickier": "^0.1.58",