@stacksjs/buddy 0.75.104 → 0.75.105
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/app-store-connect.d.ts +36 -0
- package/dist/app-store-connect.js +2 -0
- package/dist/commands/release.js +2 -2
- package/package.json +55 -55
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** The API key from the environment, or null when one is not configured. */
|
|
2
|
+
export declare function appStoreConnectCredentials(env?: Record<string, string | undefined>): AppStoreConnectCredentials | null;
|
|
3
|
+
/**
|
|
4
|
+
* A token for the API: an ES256 JWT, valid for 20 minutes (Apple's limit),
|
|
5
|
+
* signed with the key's private half.
|
|
6
|
+
*/
|
|
7
|
+
export declare function appStoreConnectToken(credentials: AppStoreConnectCredentials, now?: unknown): Promise<string>;
|
|
8
|
+
/**
|
|
9
|
+
* The builds a release retires: every unexpired build but the newest `keep`
|
|
10
|
+
* that finished processing. A build still processing is never touched, and
|
|
11
|
+
* neither is anything newer than the newest kept one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildsToExpire(builds: TestFlightBuild[], keep?: number): TestFlightBuild[];
|
|
14
|
+
/** The tag for the build Xcode Cloud is about to number, given its newest run. */
|
|
15
|
+
export declare function tagForXcodeCloudRun(version: string, latestRun: number): string;
|
|
16
|
+
export declare interface AppStoreConnectCredentials {
|
|
17
|
+
keyId: string
|
|
18
|
+
issuerId: string
|
|
19
|
+
privateKey: string
|
|
20
|
+
}
|
|
21
|
+
export declare interface TestFlightBuild {
|
|
22
|
+
id: string
|
|
23
|
+
number: number
|
|
24
|
+
uploadedDate: string
|
|
25
|
+
processingState: string
|
|
26
|
+
expired: boolean
|
|
27
|
+
}
|
|
28
|
+
declare type Fetch = (input: string, init?: RequestInit) => Promise<Response>;
|
|
29
|
+
export declare class AppStoreConnect {
|
|
30
|
+
constructor(token: string, fetchImpl?: Fetch);
|
|
31
|
+
static connect(credentials: AppStoreConnectCredentials, fetchImpl?: Fetch): Promise<AppStoreConnect>;
|
|
32
|
+
appId(bundleId: string): Promise<string>;
|
|
33
|
+
latestXcodeCloudRun(appId: string): Promise<number | null>;
|
|
34
|
+
builds(appId: string): Promise<TestFlightBuild[]>;
|
|
35
|
+
expire(buildId: string): Promise<void>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{existsSync,readFileSync}from"node:fs";const API="https://api.appstoreconnect.apple.com";export function appStoreConnectCredentials(env=process.env){const keyId=env.APP_STORE_CONNECT_KEY_ID?.trim(),issuerId=env.APP_STORE_CONNECT_ISSUER_ID?.trim();let privateKey=env.APP_STORE_CONNECT_PRIVATE_KEY?.trim();const keyPath=env.APP_STORE_CONNECT_PRIVATE_KEY_PATH?.trim();if(!privateKey&&keyPath&&existsSync(keyPath))privateKey=readFileSync(keyPath,"utf8").trim();if(!keyId||!issuerId||!privateKey)return null;return{keyId,issuerId,privateKey:privateKey.replace(/\\n/g,`
|
|
2
|
+
`)}}function base64url(bytes){return(typeof bytes==="string"?Buffer.from(bytes):Buffer.from(bytes)).toString("base64").replace(/=+$/,"").replace(/\+/g,"-").replace(/\//g,"_")}export async function appStoreConnectToken(credentials,now=Date.now()){const pem=credentials.privateKey.replace(/-----(BEGIN|END) PRIVATE KEY-----/g,"").replace(/\s+/g,""),key=await crypto.subtle.importKey("pkcs8",Buffer.from(pem,"base64"),{name:"ECDSA",namedCurve:"P-256"},!1,["sign"]),iat=Math.floor(now/1000),header=base64url(JSON.stringify({alg:"ES256",kid:credentials.keyId,typ:"JWT"})),payload=base64url(JSON.stringify({iss:credentials.issuerId,iat,exp:iat+1200,aud:"appstoreconnect-v1"})),signature=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},key,Buffer.from(`${header}.${payload}`));return`${header}.${payload}.${base64url(new Uint8Array(signature))}`}export class AppStoreConnect{token;fetchImpl;constructor(token,fetchImpl=fetch){this.token=token;this.fetchImpl=fetchImpl}static async connect(credentials,fetchImpl){return new AppStoreConnect(await appStoreConnectToken(credentials),fetchImpl)}async request(path,init={}){const response=await this.fetchImpl(`${API}${path}`,{...init,headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json",...init.headers}});if(!response.ok){const body=await response.text().catch(()=>"");throw Error(`App Store Connect ${init.method??"GET"} ${path} answered ${response.status}${body?`: ${body.slice(0,300)}`:""}`)}return response.status===204?null:await response.json()}async appId(bundleId){const id=(await this.request(`/v1/apps?filter[bundleId]=${encodeURIComponent(bundleId)}&limit=1`))?.data?.[0]?.id;if(!id)throw Error(`App Store Connect has no app with the bundle id ${bundleId}`);return id}async latestXcodeCloudRun(appId){const productId=(await this.request(`/v1/ciProducts?filter[app]=${appId}&limit=1`))?.data?.[0]?.id;if(!productId)return null;const runs=await this.request(`/v1/ciProducts/${productId}/buildRuns?sort=-number&limit=1&fields[ciBuildRuns]=number`),number=Number(runs?.data?.[0]?.attributes?.number);return Number.isInteger(number)?number:null}async builds(appId){return((await this.request(`/v1/builds?filter[app]=${appId}&sort=-uploadedDate&limit=50&fields[builds]=version,uploadedDate,processingState,expired`))?.data??[]).map((build)=>({id:build.id,number:Number(build.attributes?.version),uploadedDate:String(build.attributes?.uploadedDate??""),processingState:String(build.attributes?.processingState??""),expired:Boolean(build.attributes?.expired)}))}async expire(buildId){await this.request(`/v1/builds/${buildId}`,{method:"PATCH",body:JSON.stringify({data:{type:"builds",id:buildId,attributes:{expired:!0}}})})}}export function buildsToExpire(builds,keep=1){return builds.filter((build)=>!build.expired&&build.processingState==="VALID").sort((a,b)=>b.number-a.number).slice(Math.max(0,keep))}export function tagForXcodeCloudRun(version,latestRun){return`v${version}-build.${latestRun+1}`}
|
package/dist/commands/release.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{execFileSync}from"node:child_process";import{existsSync,readFileSync,writeFileSync}from"node:fs";import{join}from"node:path";import process from"node:process";import{runAction}from"@stacksjs/actions";import{intro,italic,log,onUnknownSubcommand,outro}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{ExitCode}from"@stacksjs/types";import{bumpedVersion,iosVersionIn,nextBuildTag,withIosVersion}from"../release-ios";import{resultFailed}from"../result";const descriptions={release:"Release a new version of your libraries/packages",project:"Target a specific project",dryRun:"Run the release without actually releasing",bump:"Non-interactive bump: patch | minor | major | prepatch | preminor | premajor | prerelease | calendar | x.y.z",verbose:"Enable verbose output"};export function release(buddy){buddy.command("release",descriptions.release).option("--dry-run",descriptions.dryRun,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--bump <type>",descriptions.bump).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{log.debug("Running `buddy release` ...",options);if(options.dryRun)log.warn("Dry run enabled. No changes will be made or committed.");const startTime=await intro("buddy release"),result=await runAction(Action.Release,options);if(resultFailed(result)){await log.error("Failed to release",result.error);process.exit(ExitCode.FatalError)}await outro(options.dryRun?"Dry run complete. Nothing was committed, tagged or pushed.":"Triggered CI/CD Release via GitHub Actions",{startTime,useSeconds:!0});if(!options.dryRun)log.info(`Follow along: ${italic(resolveGitHubActionsUrl(readOriginRemote()))}`)});buddy.command("release:ios","Ship the iOS app: regenerate its project for production, commit, tag and push").option("--bump <type>","Raise the app version first: patch | minor | major | x.y.z (default: a new build of the current version)").option("--dry-run",descriptions.dryRun,{default:!1}).action(async(options)=>{const startTime=await intro("buddy release:ios");try{const tag=await releaseIos(options);await outro(options.dryRun?`Dry run complete: would release ${tag}`:`Released ${tag}`,{startTime,useSeconds:!0});if(!options.dryRun)log.info('A CI that builds tags (Xcode Cloud: Tag Changes, prefix "v") turns it into a TestFlight build now.')}catch(error){await log.error("Failed to release the iOS app",error);process.exit(ExitCode.FatalError)}});onUnknownSubcommand(buddy,"release")}function git(...args){return execFileSync("git",args,{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}async function releaseIos(options){const root=process.cwd(),configPath=join(root,"config/mobile.ts");if(!existsSync(configPath))throw Error("config/mobile.ts not found: run this in a Stacks app with a mobile config");const branch=git("rev-parse","--abbrev-ref","HEAD");if(branch!=="main")throw Error(`releases are cut from main; this is ${branch}`);if(git("status","--porcelain","--untracked-files=no"))throw Error("commit or stash your changes first, so the release is exactly what is on main");git("pull","--quiet","--rebase","origin","main");git("fetch","--quiet","--tags","origin");const source=readFileSync(configPath,"utf8"),current=iosVersionIn(source);if(!current)throw Error("config/mobile.ts declares no iOS `version`");const version=options.bump?bumpedVersion(current,options.bump):current,
|
|
2
|
-
`).filter(Boolean));log.info(`Releasing ${tag}${version===current?"":` (version ${current} \u2192 ${version})`}`);if(options.dryRun)return tag
|
|
1
|
+
import{execFileSync}from"node:child_process";import{existsSync,readFileSync,writeFileSync}from"node:fs";import{join}from"node:path";import{pathToFileURL}from"node:url";import process from"node:process";import{runAction}from"@stacksjs/actions";import{intro,italic,log,onUnknownSubcommand,outro}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{ExitCode}from"@stacksjs/types";import{AppStoreConnect,appStoreConnectCredentials,buildsToExpire,tagForXcodeCloudRun}from"../app-store-connect";import{bumpedVersion,iosVersionIn,nextBuildTag,withIosVersion}from"../release-ios";import{resultFailed}from"../result";const descriptions={release:"Release a new version of your libraries/packages",project:"Target a specific project",dryRun:"Run the release without actually releasing",bump:"Non-interactive bump: patch | minor | major | prepatch | preminor | premajor | prerelease | calendar | x.y.z",verbose:"Enable verbose output"};export function release(buddy){buddy.command("release",descriptions.release).option("--dry-run",descriptions.dryRun,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--bump <type>",descriptions.bump).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{log.debug("Running `buddy release` ...",options);if(options.dryRun)log.warn("Dry run enabled. No changes will be made or committed.");const startTime=await intro("buddy release"),result=await runAction(Action.Release,options);if(resultFailed(result)){await log.error("Failed to release",result.error);process.exit(ExitCode.FatalError)}await outro(options.dryRun?"Dry run complete. Nothing was committed, tagged or pushed.":"Triggered CI/CD Release via GitHub Actions",{startTime,useSeconds:!0});if(!options.dryRun)log.info(`Follow along: ${italic(resolveGitHubActionsUrl(readOriginRemote()))}`)});buddy.command("release:ios","Ship the iOS app: regenerate its project for production, commit, tag and push").option("--bump <type>","Raise the app version first: patch | minor | major | x.y.z (default: a new build of the current version)").option("--keep-builds <n>","TestFlight builds to keep besides the new one; older ones are expired (needs an App Store Connect API key)",{default:1}).option("--dry-run",descriptions.dryRun,{default:!1}).action(async(options)=>{const startTime=await intro("buddy release:ios");try{const tag=await releaseIos(options);await outro(options.dryRun?`Dry run complete: would release ${tag}`:`Released ${tag}`,{startTime,useSeconds:!0});if(!options.dryRun)log.info('A CI that builds tags (Xcode Cloud: Tag Changes, prefix "v") turns it into a TestFlight build now.')}catch(error){await log.error("Failed to release the iOS app",error);process.exit(ExitCode.FatalError)}});onUnknownSubcommand(buddy,"release")}function git(...args){return execFileSync("git",args,{encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim()}async function releaseIos(options){const root=process.cwd(),configPath=join(root,"config/mobile.ts");if(!existsSync(configPath))throw Error("config/mobile.ts not found: run this in a Stacks app with a mobile config");const branch=git("rev-parse","--abbrev-ref","HEAD");if(branch!=="main")throw Error(`releases are cut from main; this is ${branch}`);if(git("status","--porcelain","--untracked-files=no"))throw Error("commit or stash your changes first, so the release is exactly what is on main");git("pull","--quiet","--rebase","origin","main");git("fetch","--quiet","--tags","origin");const source=readFileSync(configPath,"utf8"),current=iosVersionIn(source);if(!current)throw Error("config/mobile.ts declares no iOS `version`");const version=options.bump?bumpedVersion(current,options.bump):current,existingTags=git("tag","--list",`v${version}-build.*`).split(`
|
|
2
|
+
`).filter(Boolean);let tag=nextBuildTag(version,existingTags);const credentials=appStoreConnectCredentials();let store=null;if(credentials){const bundleId=(await import(pathToFileURL(configPath).href)).default.ios?.bundleId;if(!bundleId)throw Error("config/mobile.ts declares no ios.bundleId");const api=await AppStoreConnect.connect(credentials);store={api,appId:await api.appId(bundleId)};const latestRun=await api.latestXcodeCloudRun(store.appId);if(latestRun!==null){const fromStore=tagForXcodeCloudRun(version,latestRun);if(!existingTags.includes(fromStore))tag=fromStore}}else log.warn("No App Store Connect API key (APP_STORE_CONNECT_KEY_ID, _ISSUER_ID, _PRIVATE_KEY_PATH): the tag counts releases, not the build number TestFlight will show, and older builds stay listed.");log.info(`Releasing ${tag}${version===current?"":` (version ${current} \u2192 ${version})`}`);const keep=Math.max(0,Number(options.keepBuilds??1)||0);if(options.dryRun){if(store){const retiring=buildsToExpire(await store.api.builds(store.appId),keep);log.info(retiring.length?`Would expire TestFlight builds ${retiring.map((b)=>b.number).join(", ")}`:"No TestFlight builds to expire")}return tag}const paths=["config/mobile.ts","storage/framework/mobile/ios"];if(version!==current){writeFileSync(configPath,withIosVersion(source,version));const pkgPath=join(root,"package.json");if(existsSync(pkgPath)){const pkg=readFileSync(pkgPath,"utf8");writeFileSync(pkgPath,pkg.replace(/("version"\s*:\s*)"[^"]*"/,`$1"${version}"`));paths.push("package.json")}}for(const key of["MOBILE_URL","IOS_APP_VERSION","IOS_BUILD_NUMBER"])delete process.env[key];const result=await runAction(Action.BuildIos,{});if(resultFailed(result))throw result.error??Error("the iOS build failed");git("add","--",...paths);if(git("diff","--cached","--name-only"))git("commit","--quiet","-m",`chore(release): ${tag}`);git("tag","-a",tag,"-m",tag);git("push","--quiet","--atomic","origin","main",tag);if(store)try{const retiring=buildsToExpire(await store.api.builds(store.appId),keep);for(const build of retiring)await store.api.expire(build.id);if(retiring.length)log.info(`Expired TestFlight builds ${retiring.map((b)=>b.number).join(", ")}`)}catch(error){log.warn(`Could not expire older TestFlight builds: ${error instanceof Error?error.message:String(error)}`)}return tag}export function resolveGitHubActionsUrl(remoteUrl,repository=process.env.GITHUB_REPOSITORY,serverUrl=process.env.GITHUB_SERVER_URL??"https://github.com"){const repo=repository?.trim()||remoteUrl?.trim().match(/github\.com[/:]([^/\s]+\/[^/\s]+?)(?:\.git)?$/)?.[1];return repo?`${serverUrl.replace(/\/$/,"")}/${repo}/actions`:"https://github.com/stacksjs/stacks/actions"}function readOriginRemote(){try{return execFileSync("git",["config","--get","remote.origin.url"],{encoding:"utf8"}).trim()}catch{return}}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.105",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -95,68 +95,68 @@
|
|
|
95
95
|
"prepublishOnly": "bun run build"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@stacksjs/actions": "^0.75.
|
|
99
|
-
"@stacksjs/ai": "^0.75.
|
|
100
|
-
"@stacksjs/alias": "^0.75.
|
|
101
|
-
"@stacksjs/analytics": "^0.75.
|
|
102
|
-
"@stacksjs/api": "^0.75.
|
|
103
|
-
"@stacksjs/arrays": "^0.75.
|
|
104
|
-
"@stacksjs/auth": "^0.75.
|
|
105
|
-
"@stacksjs/browser-extension": "^0.75.
|
|
106
|
-
"@stacksjs/build": "^0.75.
|
|
107
|
-
"@stacksjs/cache": "^0.75.
|
|
108
|
-
"@stacksjs/chat": "^0.75.
|
|
98
|
+
"@stacksjs/actions": "^0.75.105",
|
|
99
|
+
"@stacksjs/ai": "^0.75.105",
|
|
100
|
+
"@stacksjs/alias": "^0.75.105",
|
|
101
|
+
"@stacksjs/analytics": "^0.75.105",
|
|
102
|
+
"@stacksjs/api": "^0.75.105",
|
|
103
|
+
"@stacksjs/arrays": "^0.75.105",
|
|
104
|
+
"@stacksjs/auth": "^0.75.105",
|
|
105
|
+
"@stacksjs/browser-extension": "^0.75.105",
|
|
106
|
+
"@stacksjs/build": "^0.75.105",
|
|
107
|
+
"@stacksjs/cache": "^0.75.105",
|
|
108
|
+
"@stacksjs/chat": "^0.75.105",
|
|
109
109
|
"@stacksjs/clapp": "^0.2.16",
|
|
110
|
-
"@stacksjs/cli": "^0.75.
|
|
111
|
-
"@stacksjs/cloud": "^0.75.
|
|
112
|
-
"@stacksjs/cms": "^0.75.
|
|
113
|
-
"@stacksjs/collections": "^0.75.
|
|
114
|
-
"@stacksjs/commerce": "^0.75.
|
|
115
|
-
"@stacksjs/config": "^0.75.
|
|
116
|
-
"@stacksjs/database": "^0.75.
|
|
117
|
-
"@stacksjs/desktop-build": "^0.75.
|
|
118
|
-
"@stacksjs/dns": "^0.75.
|
|
110
|
+
"@stacksjs/cli": "^0.75.105",
|
|
111
|
+
"@stacksjs/cloud": "^0.75.105",
|
|
112
|
+
"@stacksjs/cms": "^0.75.105",
|
|
113
|
+
"@stacksjs/collections": "^0.75.105",
|
|
114
|
+
"@stacksjs/commerce": "^0.75.105",
|
|
115
|
+
"@stacksjs/config": "^0.75.105",
|
|
116
|
+
"@stacksjs/database": "^0.75.105",
|
|
117
|
+
"@stacksjs/desktop-build": "^0.75.105",
|
|
118
|
+
"@stacksjs/dns": "^0.75.105",
|
|
119
119
|
"@stacksjs/dnsx": "^0.2.3",
|
|
120
|
-
"@stacksjs/email": "^0.75.
|
|
121
|
-
"@stacksjs/enums": "^0.75.
|
|
122
|
-
"@stacksjs/env": "^0.75.
|
|
123
|
-
"@stacksjs/error-handling": "^0.75.
|
|
124
|
-
"@stacksjs/events": "^0.75.
|
|
125
|
-
"@stacksjs/features": "^0.75.
|
|
126
|
-
"@stacksjs/git": "^0.75.
|
|
120
|
+
"@stacksjs/email": "^0.75.105",
|
|
121
|
+
"@stacksjs/enums": "^0.75.105",
|
|
122
|
+
"@stacksjs/env": "^0.75.105",
|
|
123
|
+
"@stacksjs/error-handling": "^0.75.105",
|
|
124
|
+
"@stacksjs/events": "^0.75.105",
|
|
125
|
+
"@stacksjs/features": "^0.75.105",
|
|
126
|
+
"@stacksjs/git": "^0.75.105",
|
|
127
127
|
"@stacksjs/gitit": "^0.2.5",
|
|
128
|
-
"@stacksjs/health": "^0.75.
|
|
128
|
+
"@stacksjs/health": "^0.75.105",
|
|
129
129
|
"@stacksjs/httx": "^0.1.10",
|
|
130
|
-
"@stacksjs/image": "^0.75.
|
|
131
|
-
"@stacksjs/lint": "^0.75.
|
|
132
|
-
"@stacksjs/logging": "^0.75.
|
|
133
|
-
"@stacksjs/notifications": "^0.75.
|
|
134
|
-
"@stacksjs/objects": "^0.75.
|
|
135
|
-
"@stacksjs/orm": "^0.75.
|
|
136
|
-
"@stacksjs/path": "^0.75.
|
|
137
|
-
"@stacksjs/payments": "^0.75.
|
|
138
|
-
"@stacksjs/realtime": "^0.75.
|
|
139
|
-
"@stacksjs/router": "^0.75.
|
|
130
|
+
"@stacksjs/image": "^0.75.105",
|
|
131
|
+
"@stacksjs/lint": "^0.75.105",
|
|
132
|
+
"@stacksjs/logging": "^0.75.105",
|
|
133
|
+
"@stacksjs/notifications": "^0.75.105",
|
|
134
|
+
"@stacksjs/objects": "^0.75.105",
|
|
135
|
+
"@stacksjs/orm": "^0.75.105",
|
|
136
|
+
"@stacksjs/path": "^0.75.105",
|
|
137
|
+
"@stacksjs/payments": "^0.75.105",
|
|
138
|
+
"@stacksjs/realtime": "^0.75.105",
|
|
139
|
+
"@stacksjs/router": "^0.75.105",
|
|
140
140
|
"@stacksjs/rpx": "^0.11.54",
|
|
141
|
-
"@stacksjs/scheduler": "^0.75.
|
|
142
|
-
"@stacksjs/search-engine": "^0.75.
|
|
143
|
-
"@stacksjs/security": "^0.75.
|
|
144
|
-
"@stacksjs/server": "^0.75.
|
|
145
|
-
"@stacksjs/sites": "^0.75.
|
|
146
|
-
"@stacksjs/skills": "^0.75.
|
|
147
|
-
"@stacksjs/socials": "^0.75.
|
|
148
|
-
"@stacksjs/storage": "^0.75.
|
|
149
|
-
"@stacksjs/strings": "^0.75.
|
|
141
|
+
"@stacksjs/scheduler": "^0.75.105",
|
|
142
|
+
"@stacksjs/search-engine": "^0.75.105",
|
|
143
|
+
"@stacksjs/security": "^0.75.105",
|
|
144
|
+
"@stacksjs/server": "^0.75.105",
|
|
145
|
+
"@stacksjs/sites": "^0.75.105",
|
|
146
|
+
"@stacksjs/skills": "^0.75.105",
|
|
147
|
+
"@stacksjs/socials": "^0.75.105",
|
|
148
|
+
"@stacksjs/storage": "^0.75.105",
|
|
149
|
+
"@stacksjs/strings": "^0.75.105",
|
|
150
150
|
"@stacksjs/stx": "^0.2.419",
|
|
151
|
-
"@stacksjs/testing": "^0.75.
|
|
152
|
-
"@stacksjs/tinker": "^0.75.
|
|
151
|
+
"@stacksjs/testing": "^0.75.105",
|
|
152
|
+
"@stacksjs/tinker": "^0.75.105",
|
|
153
153
|
"@stacksjs/tlsx": "^0.13.19",
|
|
154
154
|
"@stacksjs/ts-cloud": "^0.16.47",
|
|
155
|
-
"@stacksjs/tunnel": "^0.75.
|
|
156
|
-
"@stacksjs/types": "^0.75.
|
|
157
|
-
"@stacksjs/ui": "^0.75.
|
|
158
|
-
"@stacksjs/utils": "^0.75.
|
|
159
|
-
"@stacksjs/validation": "^0.75.
|
|
155
|
+
"@stacksjs/tunnel": "^0.75.105",
|
|
156
|
+
"@stacksjs/types": "^0.75.105",
|
|
157
|
+
"@stacksjs/ui": "^0.75.105",
|
|
158
|
+
"@stacksjs/utils": "^0.75.105",
|
|
159
|
+
"@stacksjs/validation": "^0.75.105",
|
|
160
160
|
"ajv": "^8.20.0",
|
|
161
161
|
"ajv-formats": "^3.0.1",
|
|
162
162
|
"bun-plugin-stx": "^0.2.419",
|