@coreframe/scripts 0.1.1 → 0.1.2
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/config.d.ts +11 -1
- package/dist/config.js +1 -1
- package/dist/db/client.d.ts +14 -14
- package/dist/db/client.js +1 -1
- package/dist/db/migrate-held.d.ts +4 -4
- package/dist/db/migrate.js +1 -1
- package/dist/db/project.d.ts +14 -6
- package/dist/db/project.js +1 -1
- package/dist/db/reset.js +1 -1
- package/dist/db/schema-push.d.ts +4 -4
- package/dist/db/schema-push.js +1 -1
- package/dist/deploy/migrations.js +2 -2
- package/dist/deploy/pending-migrations.d.ts +3 -3
- package/dist/deploy/tauri-release.js +1 -1
- package/dist/deploy.d.ts +1 -2
- package/dist/deploy.js +1 -1
- package/dist/dev.d.ts +3 -0
- package/dist/dev.js +1 -1
- package/dist/image-generator.d.ts +14 -2
- package/dist/typecheck.js +1 -1
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
import { DatabaseDialect } from "./db/client.js";
|
|
1
2
|
import { DeployConfig } from "./deploy/config.js";
|
|
2
3
|
|
|
3
4
|
//#region config.d.ts
|
|
4
5
|
type CoreframeConfig = {
|
|
6
|
+
database?: DatabaseConfig;
|
|
5
7
|
deploy?: DeployConfig;
|
|
6
8
|
};
|
|
9
|
+
type DatabaseConfig = {
|
|
10
|
+
dialect: DatabaseDialect;
|
|
11
|
+
};
|
|
7
12
|
declare function defineConfig(config: CoreframeConfig): CoreframeConfig;
|
|
13
|
+
declare function readProjectConfig({
|
|
14
|
+
cwd
|
|
15
|
+
}?: {
|
|
16
|
+
cwd?: string;
|
|
17
|
+
}): Promise<CoreframeConfig>;
|
|
8
18
|
//#endregion
|
|
9
|
-
export { CoreframeConfig, defineConfig };
|
|
19
|
+
export { CoreframeConfig, DatabaseConfig, defineConfig, readProjectConfig };
|
package/dist/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
import{access as e}from"node:fs/promises";import{resolve as t}from"node:path";import{pathToFileURL as n}from"node:url";function r(e){return e}async function i({cwd:r=process.cwd()}={}){let i=t(r,`coreframe.config.ts`);try{await e(i)}catch{return{}}return(await import(n(i).href)).default??{}}export{r as defineConfig,i as readProjectConfig};
|
package/dist/db/client.d.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { SQL } from "drizzle-orm";
|
|
2
2
|
|
|
3
3
|
//#region db/client.d.ts
|
|
4
|
-
type
|
|
5
|
-
type
|
|
4
|
+
type DatabaseDialect = "postgres" | "sqlite";
|
|
5
|
+
type QueryResult<Row extends Record<string, unknown> = Record<string, unknown>> = {
|
|
6
6
|
rowCount?: number | null;
|
|
7
7
|
rows: Row[];
|
|
8
8
|
};
|
|
9
|
-
type
|
|
10
|
-
dialect:
|
|
11
|
-
execute<Row extends Record<string, unknown> = Record<string, unknown>>(statement: string): Promise<
|
|
12
|
-
transaction?<Result>(run: (database:
|
|
9
|
+
type DatabaseClient = {
|
|
10
|
+
dialect: DatabaseDialect;
|
|
11
|
+
execute<Row extends Record<string, unknown> = Record<string, unknown>>(statement: string): Promise<QueryResult<Row>>;
|
|
12
|
+
transaction?<Result>(run: (database: DatabaseClient) => Promise<Result>): Promise<Result>;
|
|
13
13
|
close?(): Promise<void>;
|
|
14
14
|
};
|
|
15
|
-
type
|
|
15
|
+
type DrizzleExecutor = {
|
|
16
16
|
execute<Result = unknown>(query: SQL): Result | Promise<Result>;
|
|
17
17
|
};
|
|
18
|
-
type
|
|
18
|
+
type CreateDatabaseAdapterOptions = {
|
|
19
19
|
close?(): Promise<void>;
|
|
20
|
-
database:
|
|
21
|
-
dialect:
|
|
20
|
+
database: DrizzleExecutor;
|
|
21
|
+
dialect: DatabaseDialect;
|
|
22
22
|
};
|
|
23
|
-
declare function
|
|
23
|
+
declare function createDatabaseAdapter({
|
|
24
24
|
close,
|
|
25
25
|
database,
|
|
26
26
|
dialect
|
|
27
|
-
}:
|
|
28
|
-
declare function normalizeQueryResult<Row extends Record<string, unknown> = Record<string, unknown>>(result: unknown):
|
|
27
|
+
}: CreateDatabaseAdapterOptions): DatabaseClient;
|
|
28
|
+
declare function normalizeQueryResult<Row extends Record<string, unknown> = Record<string, unknown>>(result: unknown): QueryResult<Row>;
|
|
29
29
|
//#endregion
|
|
30
|
-
export {
|
|
30
|
+
export { CreateDatabaseAdapterOptions, DatabaseClient, DatabaseDialect, DrizzleExecutor, QueryResult, createDatabaseAdapter, normalizeQueryResult };
|
package/dist/db/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{sql as e}from"drizzle-orm";function t({close:t,database:r,dialect:i}){return{dialect:i,async execute(t){return n(await r.execute(e.raw(t)))},close:t}}function n(e){return Array.isArray(e)?{rows:e}:r(e)?{rowCount:typeof e.rowCount==`number`?e.rowCount:null,rows:e.rows}:{rows:[]}}function r(e){return typeof e==`object`&&!!e&&`rows`in e&&Array.isArray(e.rows)}export{t as
|
|
1
|
+
import{sql as e}from"drizzle-orm";function t({close:t,database:r,dialect:i}){return{dialect:i,async execute(t){return n(await r.execute(e.raw(t)))},close:t}}function n(e){return Array.isArray(e)?{rows:e}:r(e)?{rowCount:typeof e.rowCount==`number`?e.rowCount:null,rows:e.rows}:{rows:[]}}function r(e){return typeof e==`object`&&!!e&&`rows`in e&&Array.isArray(e.rows)}export{t as createDatabaseAdapter,n as normalizeQueryResult};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DatabaseClient, DatabaseDialect } from "./client.js";
|
|
2
2
|
|
|
3
3
|
//#region db/migrate-held.d.ts
|
|
4
4
|
type MigrateHeldOptions = {
|
|
5
5
|
argv?: string[];
|
|
6
|
-
database?:
|
|
6
|
+
database?: DatabaseClient;
|
|
7
7
|
env?: NodeJS.ProcessEnv;
|
|
8
8
|
};
|
|
9
9
|
declare function migrateHeldMigrations({
|
|
@@ -12,7 +12,7 @@ declare function migrateHeldMigrations({
|
|
|
12
12
|
env
|
|
13
13
|
}?: MigrateHeldOptions): Promise<void>;
|
|
14
14
|
declare function validateHeldMigrationHeader(sql: string, relativePath: string): void;
|
|
15
|
-
declare function heldMigrationSelectQuery(dialect:
|
|
16
|
-
declare function heldMigrationInsertQuery(dialect:
|
|
15
|
+
declare function heldMigrationSelectQuery(dialect: DatabaseDialect, id: string): string;
|
|
16
|
+
declare function heldMigrationInsertQuery(dialect: DatabaseDialect, id: string, sha256: string): string;
|
|
17
17
|
//#endregion
|
|
18
18
|
export { heldMigrationInsertQuery, heldMigrationSelectQuery, migrateHeldMigrations, validateHeldMigrationHeader };
|
package/dist/db/migrate.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{importProjectModule as e}from"../project.js";import{LOCAL_DB_DIR as t,MIGRATIONS_FOLDER as n}from"./config.js";import{
|
|
2
|
+
import{importProjectModule as e}from"../project.js";import{LOCAL_DB_DIR as t,MIGRATIONS_FOLDER as n}from"./config.js";import{access as r}from"node:fs/promises";import{resolve as i}from"node:path";import{migrate as a}from"drizzle-orm/pglite/migrator";const o=i(n);async function s(){await r(o);let{createLocalDb:n}=await e(`src/db/local.ts`),i=n(t);try{await a(i,{migrationsFolder:o}),console.log(`Applied local migrations from ${o}`)}finally{await i.$client.close()}}import.meta.main&&s().catch(e=>{console.error(e),process.exit(1)});export{s as migrateLocalDb};
|
package/dist/db/project.d.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DatabaseClient } from "./client.js";
|
|
2
|
+
import { DatabaseConfig } from "../config.js";
|
|
3
|
+
import { importProjectModule } from "../project.js";
|
|
2
4
|
|
|
3
5
|
//#region db/project.d.ts
|
|
4
6
|
type CreateProjectDatabaseOptions = {
|
|
7
|
+
config?: DatabaseConfig;
|
|
5
8
|
env?: NodeJS.ProcessEnv;
|
|
9
|
+
importProjectDependency?: ImportProjectDependency;
|
|
10
|
+
importProjectModule?: typeof importProjectModule;
|
|
6
11
|
};
|
|
7
|
-
type
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
type ImportProjectDependency = <T>(specifier: string) => Promise<T>;
|
|
13
|
+
declare function createProjectDeployDatabase({
|
|
14
|
+
config,
|
|
15
|
+
env,
|
|
16
|
+
importProjectDependency,
|
|
17
|
+
importProjectModule: importModule
|
|
18
|
+
}?: CreateProjectDatabaseOptions): Promise<DatabaseClient>;
|
|
11
19
|
//#endregion
|
|
12
|
-
export { CreateProjectDatabaseOptions,
|
|
20
|
+
export { CreateProjectDatabaseOptions, createProjectDeployDatabase };
|
package/dist/db/project.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{readProjectConfig as e}from"../config.js";import{importProjectModule as t}from"../project.js";import{createDatabaseAdapter as n}from"./client.js";import{createRequire as r}from"node:module";import{resolve as i}from"node:path";import{pathToFileURL as a}from"node:url";const o=`src/db/relations.ts`;async function s({config:n,env:r=process.env,importProjectDependency:i=u,importProjectModule:a=t}={}){let o=(n??(await e()).database)?.dialect??`postgres`;if(o===`postgres`)return c({env:r,importModule:a,importProjectDependency:i});if(o===`sqlite`)return l({env:r,importModule:a,importProjectDependency:i});throw Error(`Unsupported database dialect "${o}".`)}async function c({env:e,importModule:t,importProjectDependency:r}){let i=e.DATABASE_URL;if(!i)throw Error(`DATABASE_URL is required to create the deploy database.`);let[{drizzle:a},{relations:s}]=await Promise.all([r(`drizzle-orm/node-postgres`),t(o)]),c=a({connection:{connectionString:i,max:1},relations:s});return n({database:c,dialect:`postgres`,close:()=>c.$client?.end?.()??Promise.resolve()})}async function l({env:e,importModule:t,importProjectDependency:r}){let i=e.TURSO_DATABASE_URL??e.DATABASE_URL;if(!i)throw Error(`TURSO_DATABASE_URL or DATABASE_URL is required to create the deploy database.`);let[{createClient:a},{drizzle:s},{relations:c}]=await Promise.all([r(`@libsql/client`),r(`drizzle-orm/libsql`),t(o)]),l=a({url:i,authToken:e.TURSO_AUTH_TOKEN});return n({database:s({client:l,relations:c}),dialect:`sqlite`,close:async()=>{await l.close?.()}})}async function u(e){return await import(a(r(i(`package.json`)).resolve(e)).href)}export{s as createProjectDeployDatabase};
|
package/dist/db/reset.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{LOCAL_DB_DIR as e}from"./config.js";import{
|
|
2
|
+
import{LOCAL_DB_DIR as e}from"./config.js";import{rm as t}from"node:fs/promises";import{relative as n,resolve as r}from"node:path";async function i(){let i=r(e),a=n(process.cwd(),i);if(a===``||a.startsWith(`..`))throw Error(`Refusing to reset local database outside the project: ${i}`);await t(i,{force:!0,recursive:!0}),console.log(`Removed local PGlite data at ${i}`)}import.meta.main&&i().catch(e=>{console.error(e),process.exit(1)});export{i as resetLocalDb};
|
package/dist/db/schema-push.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DatabaseDialect } from "./client.js";
|
|
2
2
|
|
|
3
3
|
//#region db/schema-push.d.ts
|
|
4
4
|
type SchemaPushPlan = {
|
|
@@ -15,8 +15,8 @@ type SchemaPushModule = {
|
|
|
15
15
|
schema?: string;
|
|
16
16
|
}): Promise<SchemaPushPlan>;
|
|
17
17
|
};
|
|
18
|
-
type ImportSchemaPushModule = (dialect:
|
|
19
|
-
declare function planLocalSchemaPush(dialect:
|
|
20
|
-
declare function inferSchemaDialect(schema: Record<string, unknown>):
|
|
18
|
+
type ImportSchemaPushModule = (dialect: DatabaseDialect) => Promise<SchemaPushModule>;
|
|
19
|
+
declare function planLocalSchemaPush(dialect: DatabaseDialect, schema: Record<string, unknown>, db: unknown, importModule?: ImportSchemaPushModule): Promise<SchemaPushPlan>;
|
|
20
|
+
declare function inferSchemaDialect(schema: Record<string, unknown>): DatabaseDialect;
|
|
21
21
|
//#endregion
|
|
22
22
|
export { SchemaPushModule, SchemaPushPlan, inferSchemaDialect, planLocalSchemaPush };
|
package/dist/db/schema-push.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createRequire as e}from"node:module";import{resolve as t}from"node:path";import{
|
|
1
|
+
import{createRequire as e}from"node:module";import{resolve as t}from"node:path";import{pathToFileURL as n}from"node:url";import{is as r}from"drizzle-orm";import{PgMaterializedView as i,PgTable as a,PgView as o}from"drizzle-orm/pg-core";import{SQLiteTable as s,SQLiteView as c}from"drizzle-orm/sqlite-core";const l={postgres:`drizzle-kit/payload/postgres`,sqlite:`drizzle-kit/payload/sqlite`};async function u(e,t,n,r=f){let{pushSchema:i}=await r(e);return i(t,n)}function d(e){let t=!1,n=!1;for(let r of Object.values(e))t||=p(r),n||=m(r);if(t&&n)throw Error(`Local database schema mixes PostgreSQL and SQLite entities.`);if(t)return`postgres`;if(n)return`sqlite`;throw Error(`Could not infer local database dialect from src/db/schema.ts.`)}async function f(r){return await import(n(e(t(`package.json`)).resolve(l[r])).href)}function p(e){return r(e,a)||r(e,o)||r(e,i)}function m(e){return r(e,s)||r(e,c)}export{d as inferSchemaDialect,u as planLocalSchemaPush};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{HELD_MIGRATIONS_FOLDER as e,MIGRATIONS_FOLDER as t}from"../db/config.js";import{
|
|
1
|
+
import{HELD_MIGRATIONS_FOLDER as e,MIGRATIONS_FOLDER as t}from"../db/config.js";import{access as n,readFile as r,readdir as i}from"node:fs/promises";import{basename as a,join as o,relative as s,resolve as c}from"node:path";const l=[{code:`drop-schema-object`,pattern:/\bdrop\s+(?:table|view|materialized\s+view|index|sequence|type|schema|function|trigger|policy)\b/giu,reason:`drops schema that the currently deployed app may still depend on`},{code:`drop-column`,pattern:/\balter\s+table\b[^;]*?\bdrop\s+column\b/giu,reason:`removes a column that the currently deployed app may still read or write`},{code:`drop-constraint`,pattern:/\balter\s+table\b[^;]*?\bdrop\s+constraint\b/giu,reason:`removes a constraint outside the staged contract phase`},{code:`truncate`,pattern:/\btruncate\b/giu,reason:`removes data outside the deploy-safe migration path`},{code:`rename-table-or-column`,pattern:/\balter\s+table\b[^;]*?\brename(?:\s+column)?\b/giu,reason:`renames schema in a way old and new app versions cannot both address`},{code:`rewrite-column-type`,pattern:/\balter\s+table\b[^;]*?\balter\s+column\b[^;]*?\btype\b/giu,reason:`rewrites a column type outside a staged expand/contract rollout`},{code:`set-not-null`,pattern:/\balter\s+table\b[^;]*?\balter\s+column\b[^;]*?\bset\s+not\s+null\b/giu,reason:`enforces NOT NULL before a separate backfill and verification step`},{code:`set-default`,pattern:/\balter\s+table\b[^;]*?\balter\s+column\b[^;]*?\bset\s+default\b/giu,reason:`changes default write behavior while old app code may still be running`},{code:`broad-update`,pattern:/\bupdate\b/giu,reason:`changes data outside a separately reviewed backfill or held migration`},{code:`broad-delete`,pattern:/\bdelete\s+from\b/giu,reason:`removes data outside a held migration`}];async function u(e=process.cwd()){return _(c(e,t),e)}async function d(t=process.cwd()){return v(c(t,e),t)}async function f(e){return(await Promise.all(e.map(async e=>({migration:e,risks:p(await r(e.path,`utf8`))})))).filter(e=>e.risks.length>0)}function p(e){let t=S(e),n=g(t),r=[];for(let n of l)for(let i of t.matchAll(n.pattern))r.push(T(e,i,n.code,n.reason));for(let i of t.matchAll(/\balter\s+table\s+(?:if\s+exists\s+|only\s+)?(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)\s+add\s+column\b[^;]*?\bnot\s+null\b/giu))n.has(w(i.groups?.table))||r.push(T(e,i,`add-not-null-column`,`adds a required column to an existing table before a separate compatibility rollout`));for(let i of t.matchAll(/\balter\s+table\s+(?:if\s+exists\s+|only\s+)?(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)\s+add\s+constraint\b[^;]*?\b(?:foreign\s+key|unique|primary\s+key|check)\b/giu))n.has(w(i.groups?.table))||r.push(T(e,i,`add-constraint`,`enforces a constraint on an existing table before a separate validation step`));for(let i of t.matchAll(/\bcreate\s+unique\s+index(?:\s+concurrently)?(?:\s+if\s+not\s+exists)?\s+(?:"[^"]+"|\w+)\s+on\s+(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)/giu))n.has(w(i.groups?.table))||r.push(T(e,i,`create-unique-index`,`adds uniqueness to existing data before a separate dedupe and validation step`));return r.sort((e,t)=>e.line-t.line||e.code.localeCompare(t.code))}function m(e){return e.flatMap(e=>e.risks.map(t=>`${e.migration.relativePath}:${t.line} ${t.code}: ${t.reason} (${t.match.trim()})`)).join(`
|
|
2
2
|
`)}function h(e){return e.length===0?`No migration files found.`:e.map(e=>`- ${e.relativePath}`).join(`
|
|
3
|
-
`)}function g(e){let t=new Set;for(let n of e.matchAll(/\bcreate\s+(?:temporary\s+|temp\s+)?table\s+(?:if\s+not\s+exists\s+)?(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)/giu))t.add(w(n.groups?.table));return t}async function _(e,t){let n=await y(e),
|
|
3
|
+
`)}function g(e){let t=new Set;for(let n of e.matchAll(/\bcreate\s+(?:temporary\s+|temp\s+)?table\s+(?:if\s+not\s+exists\s+)?(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)/giu))t.add(w(n.groups?.table));return t}async function _(e,t){let n=await y(e),r=[];for(let i of n){let n=o(e,i.name);if(i.isDirectory()){let e=o(n,`migration.sql`);await b(e)&&r.push(x(e,t,i.name));continue}i.isFile()&&i.name.endsWith(`.sql`)&&r.push(x(n,t,i.name.replace(/\.sql$/u,``)))}return r.sort((e,t)=>e.id.localeCompare(t.id))}async function v(e,t){return(await y(e)).filter(e=>e.isFile()&&e.name.endsWith(`.sql`)).map(n=>x(o(e,n.name),t,n.name.replace(/\.sql$/u,``))).sort((e,t)=>e.id.localeCompare(t.id))}async function y(e){try{return await i(e,{withFileTypes:!0})}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return[];throw e}}async function b(e){try{return await n(e),!0}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return!1;throw e}}function x(e,t,n=a(e,`.sql`)){return{id:n,path:e,relativePath:s(t,e)}}function S(e){return e.replace(/--[^\n\r]*/gu,C).replace(/\/\*[\s\S]*?\*\//gu,C).replace(/\$([A-Za-z_][A-Za-z0-9_]*)?\$[\s\S]*?\$\1\$/gu,C).replace(/'(?:''|[^'])*'/gu,C)}function C(e){return e.replace(/[^\n\r]/gu,` `)}function w(e){return(e??``).split(`.`).map(e=>e.trim().replace(/^"|"$/gu,``).toLowerCase()).at(-1)??``}function T(e,t,n,r){return{code:n,line:E(e,t.index??0),match:e.slice(t.index??0,(t.index??0)+t[0].length),reason:r}}function E(e,t){let n=1;for(let r=0;r<t;r+=1)e[r]===`
|
|
4
4
|
`&&(n+=1);return n}export{u as collectDeployMigrationFiles,d as collectHeldMigrationFiles,h as formatMigrationList,m as formatMigrationScanFailures,f as scanDeployMigrationFiles,p as scanMigrationSql};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DatabaseClient, DatabaseDialect } from "../db/client.js";
|
|
2
2
|
import { MigrationFile } from "./migrations.js";
|
|
3
3
|
|
|
4
4
|
//#region deploy/pending-migrations.d.ts
|
|
5
5
|
declare function filterPendingMigrations(migrations: MigrationFile[], appliedNames: Iterable<string>): MigrationFile[];
|
|
6
|
-
declare function readAppliedMigrationNames(database:
|
|
7
|
-
declare function appliedMigrationsQuery(dialect:
|
|
6
|
+
declare function readAppliedMigrationNames(database: DatabaseClient): Promise<Set<string>>;
|
|
7
|
+
declare function appliedMigrationsQuery(dialect: DatabaseDialect): "select name from drizzle.__drizzle_migrations where name is not null" | "select name from __drizzle_migrations where name is not null";
|
|
8
8
|
//#endregion
|
|
9
9
|
export { appliedMigrationsQuery, filterPendingMigrations, readAppliedMigrationNames };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{tauriReleasePlatforms as e}from"./config.js";import{basename as t,dirname as n,join as r,relative as i,resolve as a,sep as o}from"node:path";import s from"nano-spawn";import{access as c,cp as l,mkdir as u,readFile as d,rm as f,stat as p,writeFile as m}from"node:fs/promises";import{randomUUID as h}from"node:crypto";import{constants as g}from"node:fs";import{setTimeout as _}from"node:timers/promises";import{glob as v}from"tinyglobby";const y={android:{artifactGlobs:[`tauri/src-tauri/target/**/*.sig`,`tauri/gen/android/**/*.sig`],buildArgs:[`tauri`,`android`,`build`,`--target`,`aarch64-linux-android`],targetTriple:`aarch64-linux-android`,updatePlatform:`android-aarch64`},ios:{artifactGlobs:[`tauri/src-tauri/target/**/*.sig`,`tauri/gen/apple/**/*.sig`],buildArgs:[`tauri`,`ios`,`build`,`--target`,`aarch64-apple-ios`],targetTriple:`aarch64-apple-ios`,updatePlatform:`ios-aarch64`},linux:{artifactGlobs:[`tauri/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`x86_64-unknown-linux-gnu`,`--`,`--locked`],targetTriple:`x86_64-unknown-linux-gnu`,updatePlatform:`linux-x86_64`},macos:{artifactGlobs:[`tauri/src-tauri/target/aarch64-apple-darwin/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`aarch64-apple-darwin`,`--`,`--locked`],targetTriple:`aarch64-apple-darwin`,updatePlatform:`darwin-aarch64`},windows:{artifactGlobs:[`tauri/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`x86_64-pc-windows-msvc`,`--`,`--locked`],targetTriple:`x86_64-pc-windows-msvc`,updatePlatform:`windows-x86_64`}};function b(e){return e?e.split(/[,\s]+/u).filter(Boolean).map(e=>x(e)):[]}function x(t){if(Y(t))return t;throw Error(`Invalid Tauri release platform "${t}". Expected one of: ${e.join(`, `)}.`)}function S({args:e,config:t={},env:n}){let r=J([...t.localPlatforms??[],...b(n.TAURI_RELEASE_LOCAL_PLATFORMS),...e.tauriLocalPlatforms]),i=J([...t.workflowPlatforms??[],...b(n.TAURI_RELEASE_WORKFLOW_PLATFORMS),...e.tauriWorkflowPlatforms]),a=r.filter(e=>i.includes(e));if(a.length>0)throw Error(`Build each Tauri release platform either locally or through the workflow, not both: ${a.join(`, `)}.`);return{artifactDownloadDir:n.TAURI_RELEASE_ARTIFACT_DOWNLOAD_DIR??t.artifactDownloadDir??`.coreframe/tauri-artifacts`,b2ApplicationKey:n.B2_APPLICATION_KEY??n.B2_SECRET_ACCESS_KEY,b2ApplicationKeyId:n.B2_APPLICATION_KEY_ID??n.B2_KEY_ID??n.B2_ACCESS_KEY_ID,b2Bucket:t.b2Bucket??n.B2_BUCKET,enabled:r.length>0||i.length>0,latestManifestPath:n.TAURI_RELEASE_LATEST_MANIFEST_PATH??t.latestManifestPath??`latest.json`,localPlatforms:r,platform:I(t.platform,n),publicBaseUrl:t.publicBaseUrl??n.TAURI_RELEASE_PUBLIC_BASE_URL??n.UPDATE_PUBLIC_BASE_URL,publicPathPrefix:n.TAURI_RELEASE_PUBLIC_PATH_PREFIX??t.publicPathPrefix??n.UPDATE_PUBLIC_PATH_PREFIX??``,releaseNotesPath:n.TAURI_RELEASE_NOTES_FILE??t.releaseNotesPath,releasePath:n.TAURI_RELEASE_PATH??t.releasePath??"releases/${version}",releaseUploadDir:n.TAURI_RELEASE_UPLOAD_DIR??t.releaseUploadDir??`release-upload`,signingPrivateKey:n.TAURI_SIGNING_PRIVATE_KEY,workflowName:e.tauriWorkflowName??n.TAURI_RELEASE_WORKFLOW_NAME??t.workflowName??`tauri-release-artifacts.yml`,workflowPlatforms:i,workflowPollIntervalMs:q(n.TAURI_RELEASE_WORKFLOW_POLL_SECONDS,`TAURI_RELEASE_WORKFLOW_POLL_SECONDS`)*1e3||t.workflowPollIntervalMs||15e3,workflowRef:e.tauriWorkflowRef??n.TAURI_RELEASE_WORKFLOW_REF??t.workflowRef,workflowTimeoutMs:q(n.TAURI_RELEASE_WORKFLOW_TIMEOUT_MINUTES,`TAURI_RELEASE_WORKFLOW_TIMEOUT_MINUTES`)*6e4||t.workflowTimeoutMs||36e5}}async function C(e,t=process.cwd()){if(!e.enabled)return;let n=[[`TAURI_RELEASE_PUBLIC_BASE_URL`,e.publicBaseUrl],[`B2_APPLICATION_KEY_ID`,e.b2ApplicationKeyId],[`B2_APPLICATION_KEY`,e.b2ApplicationKey],[`B2_BUCKET`,e.b2Bucket]].flatMap(([e,t])=>t?[]:[e]);if(n.length>0)throw Error(`Missing required Tauri release configuration: ${n.join(`, `)}`);try{new URL(e.publicBaseUrl)}catch{throw Error(`Invalid TAURI_RELEASE_PUBLIC_BASE_URL: ${e.publicBaseUrl}`)}if(!await X(r(t,`tauri/src-tauri/tauri.conf.json`)))throw Error(`Tauri release platforms were requested, but tauri/src-tauri/tauri.conf.json does not exist.`);if(e.localPlatforms.length>0&&!e.signingPrivateKey)throw Error(`TAURI_SIGNING_PRIVATE_KEY is required for local Tauri release builds.`);e.workflowPlatforms.length>0&&await s(`gh`,[`workflow`,`view`,e.workflowName,`--ref`,e.workflowRef??await V()],{stdin:`ignore`}),await s(`b2`,[`version`],{stdin:`ignore`})}async function w(e,t,n=process.cwd()){if(!e.enabled)return{files:[]};let i=r(n,`tauri/src-tauri/tauri.conf.json`),a=r(n,`tauri/src-tauri/Cargo.toml`),o=r(n,`tauri/src-tauri/Cargo.lock`),s=await d(i,`utf8`),c=await d(a,`utf8`),l=R(c,a),u=[{path:i,source:s},{path:a,source:c}],f=[],p=JSON.parse(s);if(p.version=t,p.bundle={...p.bundle??{},createUpdaterArtifacts:!0},f.push({path:i,source:`${JSON.stringify(p,null,2)}\n`}),f.push({path:a,source:z(c,l,t,a)}),await X(o)){let e=await d(o,`utf8`);u.push({path:o,source:e}),f.push({path:o,source:B(e,l,t,o)})}for(let e of f)await m(e.path,e.source);return{files:u}}async function T(e){for(let t of e.files)await m(t.path,t.source)}async function E({env:e,plan:t,releaseName:n,version:r}){if(!t.enabled)return;await H(t.artifactDownloadDir),await H(t.releaseUploadDir);let i=t.workflowPlatforms.length>0?await A({plan:t,releaseName:n,version:r}):void 0;for(let n of t.localPlatforms)await N(n,t,e);if(i){let e=await j(t,i.runNameMarker);await s(`gh`,[`run`,`download`,String(e),`--dir`,t.artifactDownloadDir],{stdio:`inherit`})}return k({plan:t,version:r})}async function D(e,t){await s(`b2`,[`account`,`authorize`,e.b2ApplicationKeyId,e.b2ApplicationKey],{stdin:`ignore`});let n=(await v(`**/*`,{cwd:t.uploadDir,onlyFiles:!0})).sort((e,n)=>e===t.manifestPath?1:n===t.manifestPath?-1:e.localeCompare(n));for(let i of n)await s(`b2`,[`file`,`upload`,e.b2Bucket,r(t.uploadDir,i),i],{stdin:`ignore`}),console.log(`Uploaded ${i}`)}function O({artifacts:e,notes:t,pubDate:n=new Date,version:r}){return{...t?{notes:t}:{},platforms:Object.fromEntries(e.map(e=>[e.updatePlatform,{signature:e.signature,url:e.url}])),pub_date:n.toISOString(),version:r}}async function k({plan:e,version:i}){let a=K(e.publicPathPrefix,W(e.releasePath,i)),o=K(e.publicPathPrefix,e.latestManifestPath),s=[...e.localPlatforms,...e.workflowPlatforms],c=[];for(let o of s){let s=e.platform[o],f=e.localPlatforms.includes(o)?`.`:r(e.artifactDownloadDir,`tauri-${o}-${i}`),p=await P({globs:e.localPlatforms.includes(o)?s.artifactGlobs:[`**/*.sig`],sourceRoot:f,version:i}),m=K(a,s.updatePlatform),h=K(m,t(p.artifactPath)),g=K(m,t(p.signaturePath)),_=r(e.releaseUploadDir,...h.split(`/`)),v=r(e.releaseUploadDir,...g.split(`/`)),y=(await d(p.signaturePath,`utf8`)).trim();await u(n(_),{recursive:!0}),await l(p.artifactPath,_),await l(p.signaturePath,v),c.push({signature:y,updatePlatform:s.updatePlatform,url:G(e.publicBaseUrl,h)})}let f=O({artifacts:c,notes:e.releaseNotesPath?await d(e.releaseNotesPath,`utf8`):void 0,version:i}),p=r(e.releaseUploadDir,...o.split(`/`));return await u(n(p),{recursive:!0}),await m(p,`${JSON.stringify(f,null,2)}\n`),{manifestPath:o,uploadDir:e.releaseUploadDir}}async function A({plan:t,releaseName:n,version:r}){let i=t.workflowRef??await V(),a=`coreframe-${Date.now()}-${h().slice(0,8)}`;return await s(`gh`,[`workflow`,`run`,t.workflowName,`--ref`,i,`-f`,`release_name=${n}`,`-f`,`run_id=${a}`,`-f`,`version=${r}`,...e.flatMap(e=>[`-f`,`${e}=${t.workflowPlatforms.includes(e)?`true`:`false`}`])],{stdin:`ignore`}),{runNameMarker:a}}async function j(e,t){let n=Date.now()+e.workflowTimeoutMs;for(;Date.now()<n;){let n=await M(e,t);if(n?.status===`completed`){if(n.conclusion===`success`)return n.databaseId;throw Error(`Tauri release workflow ${n.databaseId} finished with ${n.conclusion}.`)}await _(e.workflowPollIntervalMs)}throw Error(`Timed out waiting for Tauri release workflow after ${Math.round(e.workflowTimeoutMs/6e4)} minutes.`)}async function M(e,t){let{stdout:n}=await s(`gh`,[`run`,`list`,`--workflow`,e.workflowName,`--event`,`workflow_dispatch`,`--json`,`conclusion,databaseId,displayTitle,status`,`--limit`,`50`],{stdin:`ignore`});return JSON.parse(n).find(e=>e.displayTitle.includes(t))}async function N(e,t,n){await s(`pnpm`,t.platform[e].buildArgs,{env:n,stdio:`inherit`})}async function P({globs:e,sourceRoot:t,version:n}){let r=await v(e,{cwd:t,absolute:!0,onlyFiles:!0}),i=[];for(let e of r){let t=e.replace(/\.sig$/u,``);await Z(t)&&i.push({artifactPath:t,signaturePath:e})}if(i.length===0)throw Error(`Could not find a Tauri updater artifact and .sig pair under ${t}.`);return i.sort((e,t)=>{let r=F(e.artifactPath,n);return F(t.artifactPath,n)-r||e.artifactPath.localeCompare(t.artifactPath)})[0]}function F(e,t){let n=0;return e.includes(t)&&(n+=100),/\.(app\.tar\.gz|AppImage\.tar\.gz|zip)$/u.test(e)&&(n+=10),/\.(exe|msi|dmg|AppImage|deb|rpm|apk|aab|ipa)$/u.test(e)&&(n+=5),n}function I(t={},n){return Object.fromEntries(e.map(e=>{let r=t[e]??{},i={...y[e],...r},a=n[`TAURI_RELEASE_${e.toUpperCase()}_TARGET_TRIPLE`],o=n[`TAURI_RELEASE_${e.toUpperCase()}_UPDATE_PLATFORM`],s=a??i.targetTriple,c=r.buildArgs?r.buildArgs:L(e,s);return[e,{...i,artifactGlobs:i.artifactGlobs??y[e].artifactGlobs,buildArgs:c,targetTriple:s,updatePlatform:o??i.updatePlatform}]}))}function L(e,t){return e===`android`?[`tauri`,`android`,`build`,`--target`,t]:e===`ios`?[`tauri`,`ios`,`build`,`--target`,t]:[`tauri`,`build`,`--target`,t,`--`,`--locked`]}function R(e,t){let n=/^\[package\][\s\S]*?^name = "(?<name>[^"]+)"/mu.exec(e);if(!n?.groups?.name)throw Error(`${t} is missing a [package] name.`);return n.groups.name}function z(e,t,n,r){let i=RegExp(`(^\\[package\\][\\s\\S]*?^name = "${Q(t)}"[\\s\\S]*?^version = ")[^"]+(")`,`mu`),a=e.replace(i,`$1${n}$2`);if(a===e)throw Error(`${r} is missing a package version for ${t}.`);return a}function B(e,t,n,r){let i=RegExp(`(\\[\\[package\\]\\]\\nname = "${Q(t)}"\\nversion = ")[^"]+(")`,`u`),a=e.replace(i,`$1${n}$2`);if(a===e)throw Error(`${r} is missing a package lock entry for ${t}.`);return a}async function V(){let{stdout:e}=await s(`git`,[`rev-parse`,`--abbrev-ref`,`HEAD`],{stdin:`ignore`}),t=e.trim();if(t!==`HEAD`)return t;let{stdout:n}=await s(`git`,[`rev-parse`,`HEAD`],{stdin:`ignore`});return n.trim()}async function H(e){U(e),await f(e,{force:!0,recursive:!0}),await u(e,{recursive:!0})}function U(e){let t=a(e),n=i(process.cwd(),t).split(o).join(`/`);if(n===``||n===`.`||n.startsWith(`../`)||n===`tauri`||n.startsWith(`tauri/`))throw Error(`Refusing to reset unsafe Tauri release directory: ${e}`)}function W(e,t){return e.replaceAll("${version}",t)}function G(e,t){let n=new URL(e),r=K(n.pathname.replace(/\/+$/u,``),t);return n.pathname=r.startsWith(`/`)?r:`/${r}`,n.toString()}function K(...e){return e.flatMap(e=>e.split(`/`)).map(e=>e.trim()).filter(Boolean).join(`/`)}function q(e,t){if(!e)return 0;let n=Number(e);if(!Number.isInteger(n)||n<=0)throw Error(`${t} must be a positive integer.`);return n}function J(e){return[...new Set(e)]}function Y(t){return e.includes(t)}async function X(e){try{return await c(e,g.F_OK),!0}catch{return!1}}async function Z(e){try{return(await p(e)).isFile()}catch{return!1}}function Q(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}export{k as createTauriReleaseUpload,O as createTauriUpdateManifest,x as parseTauriReleasePlatform,b as parseTauriReleasePlatformList,E as prepareTauriRelease,S as resolveTauriReleasePlan,T as restoreTauriReleaseMetadata,D as uploadTauriReleaseToB2,C as validateTauriReleasePlan,w as writeTauriReleaseMetadata};
|
|
1
|
+
import{tauriReleasePlatforms as e}from"./config.js";import{access as t,cp as n,mkdir as r,readFile as i,rm as a,stat as o,writeFile as s}from"node:fs/promises";import{basename as c,dirname as l,join as u,relative as d,resolve as f,sep as p}from"node:path";import m from"nano-spawn";import{randomUUID as h}from"node:crypto";import{constants as g}from"node:fs";import{setTimeout as _}from"node:timers/promises";import{glob as v}from"tinyglobby";const y={android:{artifactGlobs:[`tauri/src-tauri/target/**/*.sig`,`tauri/gen/android/**/*.sig`],buildArgs:[`tauri`,`android`,`build`,`--target`,`aarch64-linux-android`],targetTriple:`aarch64-linux-android`,updatePlatform:`android-aarch64`},ios:{artifactGlobs:[`tauri/src-tauri/target/**/*.sig`,`tauri/gen/apple/**/*.sig`],buildArgs:[`tauri`,`ios`,`build`,`--target`,`aarch64-apple-ios`],targetTriple:`aarch64-apple-ios`,updatePlatform:`ios-aarch64`},linux:{artifactGlobs:[`tauri/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`x86_64-unknown-linux-gnu`,`--`,`--locked`],targetTriple:`x86_64-unknown-linux-gnu`,updatePlatform:`linux-x86_64`},macos:{artifactGlobs:[`tauri/src-tauri/target/aarch64-apple-darwin/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`aarch64-apple-darwin`,`--`,`--locked`],targetTriple:`aarch64-apple-darwin`,updatePlatform:`darwin-aarch64`},windows:{artifactGlobs:[`tauri/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`x86_64-pc-windows-msvc`,`--`,`--locked`],targetTriple:`x86_64-pc-windows-msvc`,updatePlatform:`windows-x86_64`}};function b(e){return e?e.split(/[,\s]+/u).filter(Boolean).map(e=>x(e)):[]}function x(t){if(Y(t))return t;throw Error(`Invalid Tauri release platform "${t}". Expected one of: ${e.join(`, `)}.`)}function S({args:e,config:t={},env:n}){let r=J([...t.localPlatforms??[],...b(n.TAURI_RELEASE_LOCAL_PLATFORMS),...e.tauriLocalPlatforms]),i=J([...t.workflowPlatforms??[],...b(n.TAURI_RELEASE_WORKFLOW_PLATFORMS),...e.tauriWorkflowPlatforms]),a=r.filter(e=>i.includes(e));if(a.length>0)throw Error(`Build each Tauri release platform either locally or through the workflow, not both: ${a.join(`, `)}.`);return{artifactDownloadDir:n.TAURI_RELEASE_ARTIFACT_DOWNLOAD_DIR??t.artifactDownloadDir??`.coreframe/tauri-artifacts`,b2ApplicationKey:n.B2_APPLICATION_KEY??n.B2_SECRET_ACCESS_KEY,b2ApplicationKeyId:n.B2_APPLICATION_KEY_ID??n.B2_KEY_ID??n.B2_ACCESS_KEY_ID,b2Bucket:t.b2Bucket??n.B2_BUCKET,enabled:r.length>0||i.length>0,latestManifestPath:n.TAURI_RELEASE_LATEST_MANIFEST_PATH??t.latestManifestPath??`latest.json`,localPlatforms:r,platform:I(t.platform,n),publicBaseUrl:t.publicBaseUrl??n.TAURI_RELEASE_PUBLIC_BASE_URL??n.UPDATE_PUBLIC_BASE_URL,publicPathPrefix:n.TAURI_RELEASE_PUBLIC_PATH_PREFIX??t.publicPathPrefix??n.UPDATE_PUBLIC_PATH_PREFIX??``,releaseNotesPath:n.TAURI_RELEASE_NOTES_FILE??t.releaseNotesPath,releasePath:n.TAURI_RELEASE_PATH??t.releasePath??"releases/${version}",releaseUploadDir:n.TAURI_RELEASE_UPLOAD_DIR??t.releaseUploadDir??`release-upload`,signingPrivateKey:n.TAURI_SIGNING_PRIVATE_KEY,workflowName:e.tauriWorkflowName??n.TAURI_RELEASE_WORKFLOW_NAME??t.workflowName??`tauri-release-artifacts.yml`,workflowPlatforms:i,workflowPollIntervalMs:q(n.TAURI_RELEASE_WORKFLOW_POLL_SECONDS,`TAURI_RELEASE_WORKFLOW_POLL_SECONDS`)*1e3||t.workflowPollIntervalMs||15e3,workflowRef:e.tauriWorkflowRef??n.TAURI_RELEASE_WORKFLOW_REF??t.workflowRef,workflowTimeoutMs:q(n.TAURI_RELEASE_WORKFLOW_TIMEOUT_MINUTES,`TAURI_RELEASE_WORKFLOW_TIMEOUT_MINUTES`)*6e4||t.workflowTimeoutMs||36e5}}async function C(e,t=process.cwd()){if(!e.enabled)return;let n=[[`TAURI_RELEASE_PUBLIC_BASE_URL`,e.publicBaseUrl],[`B2_APPLICATION_KEY_ID`,e.b2ApplicationKeyId],[`B2_APPLICATION_KEY`,e.b2ApplicationKey],[`B2_BUCKET`,e.b2Bucket]].flatMap(([e,t])=>t?[]:[e]);if(n.length>0)throw Error(`Missing required Tauri release configuration: ${n.join(`, `)}`);try{new URL(e.publicBaseUrl)}catch{throw Error(`Invalid TAURI_RELEASE_PUBLIC_BASE_URL: ${e.publicBaseUrl}`)}if(!await X(u(t,`tauri/src-tauri/tauri.conf.json`)))throw Error(`Tauri release platforms were requested, but tauri/src-tauri/tauri.conf.json does not exist.`);if(e.localPlatforms.length>0&&!e.signingPrivateKey)throw Error(`TAURI_SIGNING_PRIVATE_KEY is required for local Tauri release builds.`);e.workflowPlatforms.length>0&&await m(`gh`,[`workflow`,`view`,e.workflowName,`--ref`,e.workflowRef??await V()],{stdin:`ignore`}),await m(`b2`,[`version`],{stdin:`ignore`})}async function w(e,t,n=process.cwd()){if(!e.enabled)return{files:[]};let r=u(n,`tauri/src-tauri/tauri.conf.json`),a=u(n,`tauri/src-tauri/Cargo.toml`),o=u(n,`tauri/src-tauri/Cargo.lock`),c=await i(r,`utf8`),l=await i(a,`utf8`),d=R(l,a),f=[{path:r,source:c},{path:a,source:l}],p=[],m=JSON.parse(c);if(m.version=t,m.bundle={...m.bundle??{},createUpdaterArtifacts:!0},p.push({path:r,source:`${JSON.stringify(m,null,2)}\n`}),p.push({path:a,source:z(l,d,t,a)}),await X(o)){let e=await i(o,`utf8`);f.push({path:o,source:e}),p.push({path:o,source:B(e,d,t,o)})}for(let e of p)await s(e.path,e.source);return{files:f}}async function T(e){for(let t of e.files)await s(t.path,t.source)}async function E({env:e,plan:t,releaseName:n,version:r}){if(!t.enabled)return;await H(t.artifactDownloadDir),await H(t.releaseUploadDir);let i=t.workflowPlatforms.length>0?await A({plan:t,releaseName:n,version:r}):void 0;for(let n of t.localPlatforms)await N(n,t,e);if(i){let e=await j(t,i.runNameMarker);await m(`gh`,[`run`,`download`,String(e),`--dir`,t.artifactDownloadDir],{stdio:`inherit`})}return k({plan:t,version:r})}async function D(e,t){await m(`b2`,[`account`,`authorize`,e.b2ApplicationKeyId,e.b2ApplicationKey],{stdin:`ignore`});let n=(await v(`**/*`,{cwd:t.uploadDir,onlyFiles:!0})).sort((e,n)=>e===t.manifestPath?1:n===t.manifestPath?-1:e.localeCompare(n));for(let r of n)await m(`b2`,[`file`,`upload`,e.b2Bucket,u(t.uploadDir,r),r],{stdin:`ignore`}),console.log(`Uploaded ${r}`)}function O({artifacts:e,notes:t,pubDate:n=new Date,version:r}){return{...t?{notes:t}:{},platforms:Object.fromEntries(e.map(e=>[e.updatePlatform,{signature:e.signature,url:e.url}])),pub_date:n.toISOString(),version:r}}async function k({plan:e,version:t}){let a=K(e.publicPathPrefix,W(e.releasePath,t)),o=K(e.publicPathPrefix,e.latestManifestPath),d=[...e.localPlatforms,...e.workflowPlatforms],f=[];for(let o of d){let s=e.platform[o],d=e.localPlatforms.includes(o)?`.`:u(e.artifactDownloadDir,`tauri-${o}-${t}`),p=await P({globs:e.localPlatforms.includes(o)?s.artifactGlobs:[`**/*.sig`],sourceRoot:d,version:t}),m=K(a,s.updatePlatform),h=K(m,c(p.artifactPath)),g=K(m,c(p.signaturePath)),_=u(e.releaseUploadDir,...h.split(`/`)),v=u(e.releaseUploadDir,...g.split(`/`)),y=(await i(p.signaturePath,`utf8`)).trim();await r(l(_),{recursive:!0}),await n(p.artifactPath,_),await n(p.signaturePath,v),f.push({signature:y,updatePlatform:s.updatePlatform,url:G(e.publicBaseUrl,h)})}let p=O({artifacts:f,notes:e.releaseNotesPath?await i(e.releaseNotesPath,`utf8`):void 0,version:t}),m=u(e.releaseUploadDir,...o.split(`/`));return await r(l(m),{recursive:!0}),await s(m,`${JSON.stringify(p,null,2)}\n`),{manifestPath:o,uploadDir:e.releaseUploadDir}}async function A({plan:t,releaseName:n,version:r}){let i=t.workflowRef??await V(),a=`coreframe-${Date.now()}-${h().slice(0,8)}`;return await m(`gh`,[`workflow`,`run`,t.workflowName,`--ref`,i,`-f`,`release_name=${n}`,`-f`,`run_id=${a}`,`-f`,`version=${r}`,...e.flatMap(e=>[`-f`,`${e}=${t.workflowPlatforms.includes(e)?`true`:`false`}`])],{stdin:`ignore`}),{runNameMarker:a}}async function j(e,t){let n=Date.now()+e.workflowTimeoutMs;for(;Date.now()<n;){let n=await M(e,t);if(n?.status===`completed`){if(n.conclusion===`success`)return n.databaseId;throw Error(`Tauri release workflow ${n.databaseId} finished with ${n.conclusion}.`)}await _(e.workflowPollIntervalMs)}throw Error(`Timed out waiting for Tauri release workflow after ${Math.round(e.workflowTimeoutMs/6e4)} minutes.`)}async function M(e,t){let{stdout:n}=await m(`gh`,[`run`,`list`,`--workflow`,e.workflowName,`--event`,`workflow_dispatch`,`--json`,`conclusion,databaseId,displayTitle,status`,`--limit`,`50`],{stdin:`ignore`});return JSON.parse(n).find(e=>e.displayTitle.includes(t))}async function N(e,t,n){await m(`pnpm`,t.platform[e].buildArgs,{env:n,stdio:`inherit`})}async function P({globs:e,sourceRoot:t,version:n}){let r=await v(e,{cwd:t,absolute:!0,onlyFiles:!0}),i=[];for(let e of r){let t=e.replace(/\.sig$/u,``);await Z(t)&&i.push({artifactPath:t,signaturePath:e})}if(i.length===0)throw Error(`Could not find a Tauri updater artifact and .sig pair under ${t}.`);return i.sort((e,t)=>{let r=F(e.artifactPath,n);return F(t.artifactPath,n)-r||e.artifactPath.localeCompare(t.artifactPath)})[0]}function F(e,t){let n=0;return e.includes(t)&&(n+=100),/\.(app\.tar\.gz|AppImage\.tar\.gz|zip)$/u.test(e)&&(n+=10),/\.(exe|msi|dmg|AppImage|deb|rpm|apk|aab|ipa)$/u.test(e)&&(n+=5),n}function I(t={},n){return Object.fromEntries(e.map(e=>{let r=t[e]??{},i={...y[e],...r},a=n[`TAURI_RELEASE_${e.toUpperCase()}_TARGET_TRIPLE`],o=n[`TAURI_RELEASE_${e.toUpperCase()}_UPDATE_PLATFORM`],s=a??i.targetTriple,c=r.buildArgs?r.buildArgs:L(e,s);return[e,{...i,artifactGlobs:i.artifactGlobs??y[e].artifactGlobs,buildArgs:c,targetTriple:s,updatePlatform:o??i.updatePlatform}]}))}function L(e,t){return e===`android`?[`tauri`,`android`,`build`,`--target`,t]:e===`ios`?[`tauri`,`ios`,`build`,`--target`,t]:[`tauri`,`build`,`--target`,t,`--`,`--locked`]}function R(e,t){let n=/^\[package\][\s\S]*?^name = "(?<name>[^"]+)"/mu.exec(e);if(!n?.groups?.name)throw Error(`${t} is missing a [package] name.`);return n.groups.name}function z(e,t,n,r){let i=RegExp(`(^\\[package\\][\\s\\S]*?^name = "${Q(t)}"[\\s\\S]*?^version = ")[^"]+(")`,`mu`),a=e.replace(i,`$1${n}$2`);if(a===e)throw Error(`${r} is missing a package version for ${t}.`);return a}function B(e,t,n,r){let i=RegExp(`(\\[\\[package\\]\\]\\nname = "${Q(t)}"\\nversion = ")[^"]+(")`,`u`),a=e.replace(i,`$1${n}$2`);if(a===e)throw Error(`${r} is missing a package lock entry for ${t}.`);return a}async function V(){let{stdout:e}=await m(`git`,[`rev-parse`,`--abbrev-ref`,`HEAD`],{stdin:`ignore`}),t=e.trim();if(t!==`HEAD`)return t;let{stdout:n}=await m(`git`,[`rev-parse`,`HEAD`],{stdin:`ignore`});return n.trim()}async function H(e){U(e),await a(e,{force:!0,recursive:!0}),await r(e,{recursive:!0})}function U(e){let t=f(e),n=d(process.cwd(),t).split(p).join(`/`);if(n===``||n===`.`||n.startsWith(`../`)||n===`tauri`||n.startsWith(`tauri/`))throw Error(`Refusing to reset unsafe Tauri release directory: ${e}`)}function W(e,t){return e.replaceAll("${version}",t)}function G(e,t){let n=new URL(e),r=K(n.pathname.replace(/\/+$/u,``),t);return n.pathname=r.startsWith(`/`)?r:`/${r}`,n.toString()}function K(...e){return e.flatMap(e=>e.split(`/`)).map(e=>e.trim()).filter(Boolean).join(`/`)}function q(e,t){if(!e)return 0;let n=Number(e);if(!Number.isInteger(n)||n<=0)throw Error(`${t} must be a positive integer.`);return n}function J(e){return[...new Set(e)]}function Y(t){return e.includes(t)}async function X(e){try{return await t(e,g.F_OK),!0}catch{return!1}}async function Z(e){try{return(await o(e)).isFile()}catch{return!1}}function Q(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}export{k as createTauriReleaseUpload,O as createTauriUpdateManifest,x as parseTauriReleasePlatform,b as parseTauriReleasePlatformList,E as prepareTauriRelease,S as resolveTauriReleasePlan,T as restoreTauriReleaseMetadata,D as uploadTauriReleaseToB2,C as validateTauriReleasePlan,w as writeTauriReleaseMetadata};
|
package/dist/deploy.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TauriReleasePlatform } from "./deploy/config.js";
|
|
2
|
-
import {
|
|
2
|
+
import { readProjectConfig } from "./config.js";
|
|
3
3
|
|
|
4
4
|
//#region deploy.d.ts
|
|
5
5
|
type DeployArgs = {
|
|
@@ -13,7 +13,6 @@ type DeployArgs = {
|
|
|
13
13
|
yes: boolean;
|
|
14
14
|
};
|
|
15
15
|
declare function deployProject(argv?: string[], env?: NodeJS.ProcessEnv): Promise<void>;
|
|
16
|
-
declare function readProjectConfig(): Promise<CoreframeConfig>;
|
|
17
16
|
declare function parseDeployArgs(argv: string[]): DeployArgs;
|
|
18
17
|
//#endregion
|
|
19
18
|
export { deployProject, parseDeployArgs, readProjectConfig };
|
package/dist/deploy.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{collectDeployMigrationFiles as
|
|
2
|
+
import{readProjectConfig as e}from"./config.js";import{collectDeployMigrationFiles as t,formatMigrationList as n,formatMigrationScanFailures as r,scanDeployMigrationFiles as i}from"./deploy/migrations.js";import{createProjectDeployDatabase as a}from"./db/project.js";import{runPostDeployChecks as o}from"./deploy/checks.js";import{resolveDeployConfig as s}from"./deploy/config.js";import{filterPendingMigrations as c,readAppliedMigrationNames as l}from"./deploy/pending-migrations.js";import{parseTauriReleasePlatform as u,prepareTauriRelease as d,resolveTauriReleasePlan as f,restoreTauriReleaseMetadata as p,uploadTauriReleaseToB2 as m,validateTauriReleasePlan as h,writeTauriReleaseMetadata as g}from"./deploy/tauri-release.js";import{nextReleaseVersion as _,readPackageJson as v,releaseName as y,writePackageVersion as b}from"./deploy/version.js";import{writeFile as x}from"node:fs/promises";import S from"nano-spawn";import*as C from"@clack/prompts";const w=`package.json`;async function T(t=process.argv.slice(2),n=process.env){let c=E(t),{packageJson:l,source:u}=await v(w),T=_(l.version),D=y(l.name,T),O=n.DEPLOY_ENV??`production`,A=F(n,D,l.name,T),L=await e(),R=s(L.deploy??{},n),z=f({args:c,config:R.tauriRelease,env:n}),B=!1,V={files:[]};C.intro(`Deploy ${D}`),N(c),P(n,[`POSTHOG_API_KEY`,`POSTHOG_PROJECT_ID`]),await M(),await h(z);let H=await k(await a({config:L.database,env:n})),U=await i(H);if(U.length>0)throw Error(`Pending deploy migrations contain unsafe SQL. Move unsafe statements to held migrations.\n${r(U)}`);let W=await j(c,H);try{await b(w,l,T),V=await g(z,T),C.log.step(`Running pre-deploy build`),await S(`pnpm`,[`build`],{env:I(A),stdio:`inherit`});let e=z.enabled?await d({env:I(A),plan:z,releaseName:D,version:T}):void 0;C.log.step(`Running release build and uploading PostHog source maps`),B=!0,await S(`pnpm`,[`build`],{env:A,stdio:`inherit`}),W&&(C.log.step(`Running deploy-safe database migrations`),await S(`pnpm`,[`db`,`migrate`],{env:A,stdio:`inherit`})),C.log.step(`Deploying Worker and static assets to Cloudflare`),await S(`pnpm`,[`exec`,`wrangler`,`deploy`,`--strict`,`--keep-vars`,`--tag`,D,`--message`,`Deploy ${D}`,`--var`,`POSTHOG_RELEASE:${D}`],{env:A,stdio:`inherit`}),c.skipPostDeployChecks||(C.log.step(`Running post-deploy checks`),await o(R,{environment:O,productionUrl:R.productionUrl,releaseName:D,version:T})),e&&(C.log.step(`Uploading Tauri release artifacts to Backblaze B2`),await m(z,e)),C.outro(`Deployed ${D}`)}catch(e){throw B||(await x(w,u),await p(V)),e}}function E(e){return{runMigrations:e.includes(`--run-migrations`)||e.includes(`--yes`),skipMigrations:e.includes(`--skip-migrations`),skipPostDeployChecks:e.includes(`--skip-post-deploy-checks`),tauriLocalPlatforms:D(e,`--tauri-local-platform`).map(e=>u(e)),tauriWorkflowName:O(e,`--tauri-workflow-name`),tauriWorkflowPlatforms:D(e,`--tauri-workflow-platform`).map(e=>u(e)),tauriWorkflowRef:O(e,`--tauri-workflow-ref`),yes:e.includes(`--yes`)}}function D(e,t){let n=[];for(let r=0;r<e.length;r+=1){let i=e[r];if(i===t){let i=e[r+1];if(!i||i.startsWith(`--`))throw Error(`${t} requires a value.`);n.push(...i.split(`,`).filter(Boolean)),r+=1;continue}i.startsWith(`${t}=`)&&n.push(...i.slice(t.length+1).split(`,`).filter(Boolean))}return n}function O(e,t){let n=D(e,t);if(n.length>1)throw Error(`${t} can only be provided once.`);return n[0]}async function k(e){try{return await A(e)}finally{await e.close?.()}}async function A(e){return c(await t(),await l(e))}async function j(e,t){if(t.length===0)return C.log.info(`No pending deploy migrations.`),!1;if(C.note(n(t),`Pending deploy migrations`),e.runMigrations)return!0;if(e.skipMigrations)return!1;if(!process.stdout.isTTY)throw Error(`Pending migrations require --run-migrations or --skip-migrations in noninteractive deploys.`);let r=await C.confirm({initialValue:!0,message:`Run these deploy-safe database migrations before Cloudflare deploy?`});if(C.isCancel(r))throw C.cancel(`Deploy cancelled.`),Error(`Deploy cancelled.`);return r}async function M(){let{stdout:e}=await S(`git`,[`status`,`--porcelain`],{stdin:`ignore`});if(e.trim().length>0)throw Error(`Deploy requires a clean git tree before the release version is applied.`)}function N(e){if(e.runMigrations&&e.skipMigrations)throw Error(`Use only one of --run-migrations, --skip-migrations, or --yes.`)}function P(e,t){let n=t.filter(t=>!e[t]);if(n.length>0)throw Error(`Missing required deploy environment variables: ${n.join(`, `)}`);return Object.fromEntries(t.map(t=>[t,e[t]]))}function F(e,t,n,r){return{...e,POSTHOG_RELEASE:t,POSTHOG_RELEASE_NAME:e.POSTHOG_RELEASE_NAME??n,POSTHOG_RELEASE_VERSION:e.POSTHOG_RELEASE_VERSION??r}}function I(e){let{POSTHOG_API_KEY:t,POSTHOG_PROJECT_ID:n,...r}=e;return r}import.meta.main&&T().catch(e=>{console.error(e),process.exit(1)});export{T as deployProject,E as parseDeployArgs,e as readProjectConfig};
|
package/dist/dev.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readProjectConfig } from "./config.js";
|
|
1
2
|
import { spawn as spawn$1 } from "node:child_process";
|
|
2
3
|
|
|
3
4
|
//#region dev.d.ts
|
|
@@ -7,6 +8,7 @@ type DevServerOptions = {
|
|
|
7
8
|
env?: NodeJS.ProcessEnv;
|
|
8
9
|
logPath?: string;
|
|
9
10
|
platform?: DevPlatform;
|
|
11
|
+
readProjectConfig?: typeof readProjectConfig;
|
|
10
12
|
spawn?: Spawn;
|
|
11
13
|
};
|
|
12
14
|
type DevPlatform = "android" | "desktop" | "ios" | "web";
|
|
@@ -15,6 +17,7 @@ declare function runDevServer({
|
|
|
15
17
|
env,
|
|
16
18
|
logPath,
|
|
17
19
|
platform,
|
|
20
|
+
readProjectConfig: readConfig,
|
|
18
21
|
spawn
|
|
19
22
|
}?: DevServerOptions): Promise<void>;
|
|
20
23
|
//#endregion
|
package/dist/dev.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import e from"node:
|
|
2
|
+
import{readProjectConfig as e}from"./config.js";import{mkdir as t}from"node:fs/promises";import n from"node:path";import r from"node:process";import{createWriteStream as i}from"node:fs";import{spawn as a}from"node:child_process";const o=n.resolve(`node_modules`,`.bin`),s=r.platform===`win32`?`pnpm.cmd`:`pnpm`,c=r.platform===`win32`?`react-router.cmd`:`react-router`,l=r.platform===`win32`?`turso.cmd`:`turso`;async function u({cwd:t=r.cwd(),env:i=r.env,logPath:u=`.agents/logs/dev-server.log`,platform:_=`web`,readProjectConfig:v=e,spawn:y=a}={}){let b=i.PATH??i.Path??``,x=`TAURI_ENV_PLATFORM`in i?void 0:await f(u),S;try{if(_===`web`){(await v({cwd:t})).database?.dialect===`sqlite`&&(S=g(y,l,[`dev`],{cwd:t,env:i,log:x})),await h(y,s,[`db`,`ensure`],{cwd:t,env:i,log:x}),await d(h(y,c,[`dev`],{cwd:t,env:{...i,CLOUDFLARE_ENV:`development`,PATH:o+n.delimiter+b},log:x}),S);return}await h(y,s,m(_),{cwd:t,env:i,log:x})}finally{await S?.stop(),await p(x)}}async function d(e,t){if(!t){await e;return}await Promise.race([e,t.exited.then(()=>{throw Error(`turso dev exited before the web dev server stopped`)},e=>{throw e})])}async function f(e){return await t(n.dirname(e),{recursive:!0}),i(e,{flags:`w`})}function p(e){return e?new Promise((t,n)=>{e.once(`error`,n),e.end(t)}):Promise.resolve()}function m(e){return[`--dir=tauri`,`tauri`,...e===`desktop`?[]:[e],`dev`]}function h(e,t,n,{cwd:r,env:i,log:a}){return g(e,t,n,{cwd:r,env:i,log:a}).exited}function g(e,t,n,{cwd:i,env:a,log:o}){let s=!1,c=e(t,n,{cwd:i,env:a,stdio:o?[`inherit`,`pipe`,`pipe`]:`inherit`}),l=new Promise((e,i)=>{if(o){if(!c.stdout||!c.stderr){i(Error(`${[t,...n].join(` `)} did not provide output streams`));return}c.stdout.on(`data`,e=>{r.stdout.write(e),o.write(e)}),c.stderr.on(`data`,e=>{r.stderr.write(e),o.write(e)})}c.on(`error`,e=>{s=!0,i(e)}),c.on(`close`,(r,a)=>{if(s=!0,r===0){e();return}let o=[t,...n].join(` `);i(Error(`${o} failed${a?` with signal ${a}`:` with exit code ${r??1}`}`))})});return l.catch(()=>void 0),{exited:l,async stop(){s||c.kill?.(`SIGTERM`);try{await l}catch{}}}}import.meta.main&&u().catch(e=>{console.error(e),r.exit(1)});export{u as runDevServer};
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConfigEnv, FSWatcher } from "vite";
|
|
2
2
|
|
|
3
3
|
//#region image-generator.d.ts
|
|
4
|
-
declare function imageGenerator():
|
|
4
|
+
declare function imageGenerator(): {
|
|
5
|
+
name: string;
|
|
6
|
+
configResolved(config: {
|
|
7
|
+
command: ConfigEnv["command"];
|
|
8
|
+
}): void;
|
|
9
|
+
configureServer(server: {
|
|
10
|
+
watcher: FSWatcher;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
applyToEnvironment(environment: {
|
|
13
|
+
name: string;
|
|
14
|
+
}): boolean;
|
|
15
|
+
buildStart(): Promise<void>;
|
|
16
|
+
};
|
|
5
17
|
//#endregion
|
|
6
18
|
export { imageGenerator };
|
package/dist/typecheck.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import e
|
|
2
|
+
import{access as e}from"node:fs/promises";import t from"node:path";import n from"node:process";import{supervise as r}from"procband";const i=t.resolve(`node_modules`,`.bin`);n.env.PATH=i+t.delimiter+n.env.PATH;const a=n.platform===`win32`?`tsc.cmd`:`tsc`,o=[{name:`scripts`,path:`scripts/tsconfig.json`},{name:`shared`,path:`src/shared/tsconfig.json`},{name:`api`,path:`src/api/tsconfig.json`},{name:`worker`,path:`src/api/worker/tsconfig.json`},{name:`web`,path:`src/web/tsconfig.json`}];async function s(){let t=[];for(let n of o)try{await e(n.path),t.push(n)}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e}let i=t.map(e=>r({name:e.name,command:a,args:[`-p`,e.path]})),s=(await Promise.all(i.map(e=>e.wait()))).filter(e=>e.exitCode!==0);s.length>0&&(n.exitCode=s[0].exitCode)}import.meta.main&&s().catch(e=>{console.error(e),n.exit(1)});export{s as typecheckProject};
|