@hearthlog/tooling 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +235 -0
  2. package/bin/hearthlog.mjs +52 -0
  3. package/package.json +64 -3
  4. package/src/apply.ts +73 -0
  5. package/src/check/check-layers.ts +118 -0
  6. package/src/check/check-modules.ts +198 -0
  7. package/src/check/check-sdk-exports.ts +79 -0
  8. package/src/check/check-tenant-config.ts +208 -0
  9. package/src/cli/hearthlog.ts +212 -0
  10. package/src/cli/list-sites.ts +15 -0
  11. package/src/compose/compose-modules.ts +490 -0
  12. package/src/compose/module-scaffold.ts +194 -0
  13. package/src/deploy/artifact-compare.ts +93 -0
  14. package/src/deploy/artifact.ts +127 -0
  15. package/src/deploy/async-utils.ts +71 -0
  16. package/src/deploy/backup-tenants.ts +139 -0
  17. package/src/deploy/cloudflare-access.ts +789 -0
  18. package/src/deploy/copy-tenant.ts +395 -0
  19. package/src/deploy/dedicated-ledger.ts +77 -0
  20. package/src/deploy/deploy-ledger.ts +162 -0
  21. package/src/deploy/deploy-runner.ts +240 -0
  22. package/src/deploy/deploy-tenant.ts +170 -0
  23. package/src/deploy/deployment-security.ts +141 -0
  24. package/src/deploy/ensure-tenant.ts +988 -0
  25. package/src/deploy/event-policy.ts +23 -0
  26. package/src/deploy/frontend-dry-run.ts +18 -0
  27. package/src/deploy/ledger-credential.ts +48 -0
  28. package/src/deploy/ledger-scripts.ts +13 -0
  29. package/src/deploy/split-tenant.ts +295 -0
  30. package/src/dev/local-development.ts +288 -0
  31. package/src/dev/provision-local.ts +13 -0
  32. package/src/generate/build-generated.ts +166 -0
  33. package/src/generate/generate-brand-icons.ts +128 -0
  34. package/src/generate/generate-entities.ts +627 -0
  35. package/src/generate/generate-tenant.ts +161 -0
  36. package/src/host/core-routes.ts +39 -0
  37. package/src/host/write-host.ts +119 -0
  38. package/src/index.ts +8 -0
  39. package/src/init/check-module.ts +143 -0
  40. package/src/init/export-tenant.ts +124 -0
  41. package/src/init/init.ts +167 -0
  42. package/src/move.ts +189 -0
  43. package/src/plan.ts +160 -0
  44. package/src/public-workers/build-gallery-public.ts +114 -0
  45. package/src/public-workers/calendar-public-config.ts +27 -0
  46. package/src/public-workers/check-calendar-public-route.ts +41 -0
  47. package/src/public-workers/check-gallery-public-route.ts +43 -0
  48. package/src/public-workers/gallery-public-config.ts +22 -0
  49. package/src/receipt.ts +74 -0
  50. package/src/root.ts +16 -0
  51. package/src/security/audit-push.ts +136 -0
  52. package/src/security/forbidden-identities.ts +107 -0
  53. package/src/security/forbidden-init.ts +88 -0
  54. package/src/tenants/host-configs.ts +96 -0
  55. package/src/tenants/ledger-config.ts +57 -0
  56. package/src/tenants/lock-file.ts +45 -0
  57. package/src/tenants/module-lock.ts +58 -0
  58. package/src/tenants/tenant-config.ts +887 -0
  59. package/src/tenants/tenant-copy-plan.ts +119 -0
  60. package/src/tenants/tenant-schema.ts +171 -0
  61. package/src/tenants/tenant-wrangler.ts +37 -0
  62. package/src/tenants/wrangler-base.ts +50 -0
  63. package/src/tenants/wrangler-config.ts +266 -0
  64. package/src/vite/config.ts +310 -0
  65. package/src/vite/dev-plugins.ts +338 -0
  66. package/src/vite/vite-plugin-entity-gen.ts +70 -0
  67. package/src/vite/vite-plugin-tenant-manifest.ts +61 -0
  68. package/src/vite/vite-plugin-worker-assets.ts +42 -0
  69. package/templates/host/app.d.ts.txt +31 -0
  70. package/templates/host/microlighter.d.ts.txt +11 -0
  71. package/templates/module/ci.yml.tmpl +44 -0
  72. package/templates/module/gitignore.tmpl +7 -0
  73. package/templates/module/release.yml.tmpl +53 -0
  74. package/templates/tenant/README.md.tmpl +13 -0
  75. package/templates/tenant/generated-package.json.tmpl +16 -0
  76. package/templates/tenant/github-workflows/deploy.yml.tmpl +110 -0
  77. package/templates/tenant/gitignore.tmpl +11 -0
  78. package/templates/tenant/package.json.tmpl +11 -0
  79. package/templates/tenant/patches/sqlocal@0.18.0.patch +18 -0
  80. package/templates/tenant/pnpm-workspace.yaml.tmpl +8 -0
  81. package/templates/tenant/tenants/__id__/tenant.json.tmpl +8 -0
  82. package/templates/tenant/tenants.json.tmpl +17 -0
  83. package/templates/tenant/tsconfig.json.tmpl +21 -0
  84. package/templates/tenant/vite.config.ts.tmpl +5 -0
  85. package/README.md +0 -3
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Vite Plugin: Entity Generator
3
+ *
4
+ * Watches entity-definitions.ts and auto-regenerates types on change.
5
+ * This provides a better DX by eliminating the need to manually run
6
+ * `pnpm generate:entities` during development.
7
+ */
8
+
9
+ import type { Plugin } from 'vite';
10
+ import { spawn } from 'child_process';
11
+ import path from 'path';
12
+
13
+ let isGenerating = false;
14
+
15
+ export function entityGeneratorPlugin(): Plugin {
16
+ return {
17
+ name: 'entity-generator',
18
+ configureServer(server) {
19
+ const entityDefsPath = path.resolve('packages/contracts/src/event/entity-definitions.ts');
20
+
21
+ // Add the file to the watcher
22
+ server.watcher.add(entityDefsPath);
23
+
24
+ server.watcher.on('change', (changedPath) => {
25
+ // Normalize paths for comparison
26
+ const normalizedChanged = path.normalize(changedPath);
27
+ const normalizedTarget = path.normalize(entityDefsPath);
28
+
29
+ if (normalizedChanged === normalizedTarget && !isGenerating) {
30
+ isGenerating = true;
31
+ console.log('\n[entity-gen] 🔄 Regenerating entity types...');
32
+
33
+ const startTime = Date.now();
34
+ const child = spawn('pnpm', ['generate:entities'], {
35
+ stdio: 'pipe',
36
+ shell: true,
37
+ cwd: process.cwd()
38
+ });
39
+
40
+ child.stdout?.on('data', (data) => {
41
+ const output = data.toString().trim();
42
+ if (output) console.log(`[entity-gen] ${output}`);
43
+ });
44
+
45
+ child.stderr?.on('data', (data) => {
46
+ const output = data.toString().trim();
47
+ if (output) console.error(`[entity-gen] ❌ ${output}`);
48
+ });
49
+
50
+ child.on('close', (code) => {
51
+ const elapsed = Date.now() - startTime;
52
+ if (code === 0) {
53
+ console.log(`[entity-gen] ✅ Done in ${elapsed}ms`);
54
+ } else {
55
+ console.error(`[entity-gen] ❌ Failed with code ${code}`);
56
+ }
57
+ isGenerating = false;
58
+ });
59
+
60
+ child.on('error', (err) => {
61
+ console.error(`[entity-gen] ❌ Failed to start: ${err.message}`);
62
+ isGenerating = false;
63
+ });
64
+ }
65
+ });
66
+
67
+ console.log('[entity-gen] 👀 Watching entity-definitions.ts for changes');
68
+ },
69
+ };
70
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Vite Plugin: Tenant Web App Manifest
3
+ *
4
+ * Serves and emits /manifest.webmanifest for the tenant selected with
5
+ * VITE_STOR_TENANT, so each installed app gets its own name, theme colour, and
6
+ * icon set (tenants/<site-id>/static/icons/<site-id>/, see packages/tooling/src/generate/generate-brand-icons.ts).
7
+ */
8
+
9
+ import type { Plugin } from 'vite';
10
+
11
+ import { themeVariablesFor } from '../../../contracts/src/tenant/theme.js';
12
+ import { loadTenantConfig, siteById } from '../tenants/tenant-config.js';
13
+
14
+ const MANIFEST_PATH = '/manifest.webmanifest';
15
+
16
+ async function manifestJson(siteId: string): Promise<string> {
17
+ const { sites } = await loadTenantConfig(undefined, { only: siteId });
18
+ const site = siteById(sites, siteId);
19
+ const color = themeVariablesFor(site.theme.accent, 'light')['--stor-theme-color'];
20
+ const icons = `/icons/${site.id}`;
21
+ return JSON.stringify(
22
+ {
23
+ name: site.title,
24
+ short_name: site.title,
25
+ id: site.title.trim().toLowerCase(),
26
+ start_url: '/',
27
+ scope: '/',
28
+ display: 'standalone',
29
+ theme_color: color,
30
+ background_color: color,
31
+ icons: [
32
+ { src: `${icons}/pwa-192.png`, sizes: '192x192', type: 'image/png', purpose: 'any' },
33
+ { src: `${icons}/pwa-512.png`, sizes: '512x512', type: 'image/png', purpose: 'any' },
34
+ { src: `${icons}/maskable-512.png`, sizes: '512x512', type: 'image/png', purpose: 'maskable' },
35
+ ],
36
+ },
37
+ null,
38
+ 2,
39
+ );
40
+ }
41
+
42
+ export function tenantManifestPlugin(): Plugin {
43
+ const siteId = process.env.VITE_STOR_TENANT?.trim() || 'st';
44
+ return {
45
+ name: 'tenant-manifest',
46
+ configureServer(server) {
47
+ server.middlewares.use(MANIFEST_PATH, async (_request, response) => {
48
+ response.setHeader('Content-Type', 'application/manifest+json; charset=utf-8');
49
+ response.end(await manifestJson(siteId));
50
+ });
51
+ },
52
+ async generateBundle() {
53
+ if (this.environment?.name !== 'client') return;
54
+ this.emitFile({
55
+ type: 'asset',
56
+ fileName: MANIFEST_PATH.slice(1),
57
+ source: await manifestJson(siteId),
58
+ });
59
+ },
60
+ };
61
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Vite Plugin: Worker asset list for the service worker
3
+ *
4
+ * SvelteKit's `$app/manifest` lists the worker entry files but not the chunks
5
+ * and WASM they load, because those are copied into the client output after the
6
+ * service worker is bundled. The SQLite WASM worker needs all of them offline,
7
+ * so `virtual:worker-assets` lists everything Kit emitted under
8
+ * `_app/immutable/workers`.
9
+ */
10
+
11
+ import { existsSync, readdirSync } from 'node:fs';
12
+ import { join, relative } from 'node:path';
13
+
14
+ import type { Plugin } from 'vite';
15
+
16
+ const VIRTUAL_ID = 'virtual:worker-assets';
17
+ const RESOLVED_ID = `\0${VIRTUAL_ID}`;
18
+
19
+ function listFiles(directory: string): string[] {
20
+ if (!existsSync(directory)) return [];
21
+ return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
22
+ const path = join(directory, entry.name);
23
+ return entry.isDirectory() ? listFiles(path) : [path];
24
+ });
25
+ }
26
+
27
+ export function workerAssetsPlugin(outDir: string): Plugin {
28
+ const clientOutput = join(outDir, 'output', 'client');
29
+ return {
30
+ name: 'worker-assets',
31
+ resolveId(id) {
32
+ return id === VIRTUAL_ID ? RESOLVED_ID : undefined;
33
+ },
34
+ load(id) {
35
+ if (id !== RESOLVED_ID) return undefined;
36
+ const paths = listFiles(join(clientOutput, '_app', 'immutable', 'workers'))
37
+ .map((file) => ({ path: relative(clientOutput, file).split('\\').join('/') }))
38
+ .sort((left, right) => left.path.localeCompare(right.path));
39
+ return `export const workerAssets = ${JSON.stringify(paths)};`;
40
+ },
41
+ };
42
+ }
@@ -0,0 +1,31 @@
1
+ import 'unplugin-icons/types/svelte';
2
+
3
+ declare global {
4
+ namespace App { }
5
+ const __BUILD_TIMESTAMP__: string;
6
+ const __STACK_INFO__: {
7
+ packages: Record<string, string>;
8
+ node: string;
9
+ commit: string;
10
+ branch: string;
11
+ dirty: boolean;
12
+ };
13
+ interface Window {
14
+ __storE2E?: import('@hearthlog/runtime/testing/e2e-seed.js').StorE2ESeedApi;
15
+ }
16
+ }
17
+
18
+ interface ImportMetaEnv {
19
+ readonly VITE_LEDGER_SERVICE_URL?: string;
20
+ readonly VITE_LEDGER_AUTH_TOKEN?: string;
21
+ readonly VITE_LEDGER_TIMEOUT_MS?: string;
22
+ readonly VITE_LEDGER_MAX_RETRIES?: string;
23
+ readonly VITE_LEDGER_ENABLE_REALTIME?: string;
24
+ readonly VITE_E2E?: string;
25
+ }
26
+
27
+ interface ImportMeta {
28
+ readonly env: ImportMetaEnv;
29
+ }
30
+
31
+ export { };
@@ -0,0 +1,11 @@
1
+ declare module "microlighter" {
2
+ interface HighlightOptions {
3
+ root?: ParentNode;
4
+ selector?: string;
5
+ languageAliases?: Record<string, string>;
6
+ }
7
+
8
+ export function highlightAll(
9
+ options?: HighlightOptions,
10
+ ): Promise<HTMLElement[]>;
11
+ }
@@ -0,0 +1,44 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ test:
17
+ name: Builds into a site, unit tests
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
21
+ - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
22
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
23
+ with:
24
+ node-version: 24
25
+ - run: pnpm install
26
+ # Generates a site that enables this module against the platform range, installs and builds it, then runs the
27
+ # module's unit tests against that site's generated files.
28
+ - run: pnpm test
29
+
30
+ secrets:
31
+ name: Secret scan
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
35
+ with:
36
+ fetch-depth: 0
37
+ - name: Install gitleaks
38
+ run: |
39
+ version=8.30.1
40
+ curl -sSfL -o gitleaks.tar.gz "https://github.com/gitleaks/gitleaks/releases/download/v${version}/gitleaks_${version}_linux_x64.tar.gz"
41
+ echo "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb gitleaks.tar.gz" | sha256sum --check
42
+ tar xzf gitleaks.tar.gz gitleaks
43
+ - run: ./gitleaks git --redact --no-banner --verbose .
44
+ - run: ./gitleaks dir --redact --no-banner --verbose .
@@ -0,0 +1,7 @@
1
+ node_modules/
2
+ dist/
3
+ .DS_Store
4
+ .env
5
+ .env.*
6
+ .dev.vars
7
+ .wrangler/
@@ -0,0 +1,53 @@
1
+ name: Release
2
+
3
+ # Set "version" in package.json, commit, then push the tag `v<version>`. The publish job waits for approval in the
4
+ # protected `npm` environment; the registry credential is the organization secret NPM_TOKEN.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ verify:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
17
+ - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
18
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
19
+ with:
20
+ node-version: 24
21
+ - name: The tag names the version in package.json
22
+ run: test "$GITHUB_REF_NAME" = "v$(node -p "require('./package.json').version")"
23
+ - run: pnpm install
24
+ - run: pnpm test
25
+
26
+ publish:
27
+ needs: verify
28
+ runs-on: ubuntu-latest
29
+ environment: npm
30
+ permissions:
31
+ contents: read
32
+ id-token: write # provenance
33
+ steps:
34
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
35
+ - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
36
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
37
+ with:
38
+ node-version: 24
39
+ registry-url: https://registry.npmjs.org
40
+ - run: pnpm install
41
+ - run: pnpm publish --no-git-checks
42
+ env:
43
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
44
+
45
+ release:
46
+ needs: publish
47
+ runs-on: ubuntu-latest
48
+ permissions:
49
+ contents: write
50
+ steps:
51
+ - run: gh release create "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --title "$GITHUB_REF_NAME" --generate-notes
52
+ env:
53
+ GH_TOKEN: ${{ github.token }}
@@ -0,0 +1,13 @@
1
+ # {{title}}
2
+
3
+ A Hearthlog site. `tenants/{{id}}/tenant.json` says what it enables, `tenants/{{id}}/modules.lock.json` records the
4
+ modules it ships, and everything else the app needs is written by `pnpm build:generated` into `.generated/`.
5
+
6
+ ```bash
7
+ pnpm install
8
+ pnpm dev # builds the generated files, then starts Vite
9
+ pnpm build # a static build in build/
10
+ ```
11
+
12
+ `tenants.json` holds placeholder infrastructure names: it makes the site load, and it cannot be deployed until real
13
+ values replace them.
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@hearthlog/generated",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": {
7
+ "./schema": "./src/schema.generated.ts",
8
+ "./types": "./src/types.generated.ts",
9
+ "./standard-commands": "./src/standard-commands.generated.ts",
10
+ "./standard-db": "./src/standard-db.generated.ts",
11
+ "./module-repositories": "./src/module-repositories.generated.ts",
12
+ "./modules": "./src/modules.generated.ts",
13
+ "./module-icons": "./src/module-icons.generated.ts",
14
+ "./event-schemas": "./src/event-schemas.generated.ts"
15
+ }
16
+ }
@@ -0,0 +1,110 @@
1
+ name: Deploy {{id}}
2
+
3
+ # Two jobs. `build` has no secrets: it installs the locked dependencies, builds the site, and seals the result in
4
+ # artifact-manifest.json. `deploy` runs in the protected `{{id}}` environment, so it starts only once a reviewer
5
+ # approves, and it is the only job that holds secrets. It installs the same lockfile with scripts disabled, checks the
6
+ # manifest, and deploys what `build` made. It never creates a Ledger token or signing key: provision the stack once
7
+ # on your machine with `hearthlog apply`. Each run uploads its receipt (no secrets) as an artifact.
8
+ #
9
+ # In the `{{id}}` environment: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, and LEDGER_ADMIN_TOKEN (the administrator
10
+ # token of this site's Ledger); optionally INVOICE_RENDERER_TOKEN, VERTEX_API_KEY, and VERTEX_SERVICE_ACCOUNT.
11
+
12
+ on:
13
+ pull_request:
14
+ push:
15
+ branches: [main]{{pushPaths}}
16
+ workflow_dispatch:
17
+ inputs:
18
+ dry_run:
19
+ description: Validate and bundle without uploading
20
+ type: boolean
21
+ default: false
22
+
23
+ permissions:
24
+ contents: read
25
+
26
+ jobs:
27
+ build:
28
+ name: Build {{id}}
29
+ runs-on: ubuntu-latest
30
+ steps:
31
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
32
+ with:
33
+ persist-credentials: false
34
+ - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
35
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
36
+ with:
37
+ node-version: 24
38
+ cache: pnpm
39
+ - name: Install dependencies
40
+ run: pnpm install --frozen-lockfile
41
+ - name: Plan (read-only)
42
+ run: pnpm exec hearthlog plan --site {{id}}
43
+ - name: Build and seal
44
+ env:
45
+ VITE_STOR_TENANT: {{id}}
46
+ run: |
47
+ pnpm exec hearthlog build
48
+ pnpm exec hearthlog gallery-public:build --site {{id}}
49
+ pnpm exec vite build
50
+ pnpm exec hearthlog artifact manifest --site {{id}}
51
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
52
+ with:
53
+ name: release
54
+ path: |
55
+ build
56
+ .generated
57
+ artifact-manifest.json
58
+ include-hidden-files: true
59
+ if-no-files-found: error
60
+ retention-days: 14
61
+
62
+ deploy:
63
+ name: Deploy {{id}}
64
+ needs: build
65
+ if: github.event_name != 'pull_request'
66
+ runs-on: ubuntu-latest
67
+ environment: {{id}}
68
+ concurrency:
69
+ group: deploy-{{id}}
70
+ cancel-in-progress: false
71
+ steps:
72
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
73
+ with:
74
+ persist-credentials: false
75
+ - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v4.4.0
76
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
77
+ with:
78
+ node-version: 24
79
+ cache: pnpm
80
+ # No lifecycle script of any dependency runs in the job that holds the secrets.
81
+ - name: Install dependencies
82
+ run: pnpm install --frozen-lockfile --ignore-scripts
83
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
84
+ with:
85
+ name: release
86
+ path: .
87
+ - name: Check the release against its manifest
88
+ run: pnpm exec hearthlog artifact verify --site {{id}}
89
+ - name: Deploy
90
+ env:
91
+ DRY_RUN: ${{ github.event.inputs.dry_run }}
92
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
93
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
94
+ LEDGER_ADMIN_TOKEN_{{idUpper}}: ${{ secrets.LEDGER_ADMIN_TOKEN }}
95
+ INVOICE_RENDERER_TOKEN: ${{ secrets.INVOICE_RENDERER_TOKEN }}
96
+ INVOICE_EXTRACTION_API_KEY: ${{ secrets.VERTEX_API_KEY }}
97
+ INVOICE_EXTRACTION_SERVICE_ACCOUNT: ${{ secrets.VERTEX_SERVICE_ACCOUNT }}
98
+ run: |
99
+ set -euo pipefail
100
+ args=(--site {{id}} --yes --skip-build --no-bootstrap)
101
+ if [ "$DRY_RUN" = "true" ]; then args+=(--dry-run); fi
102
+ pnpm exec hearthlog apply "${args[@]}"
103
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
104
+ if: always()
105
+ with:
106
+ name: receipt
107
+ path: .wrangler/tenants/{{id}}/receipt.json
108
+ include-hidden-files: true
109
+ if-no-files-found: ignore
110
+ retention-days: 90
@@ -0,0 +1,11 @@
1
+ # What `hearthlog build` writes; only .generated/package.json is committed.
2
+ /.generated/*
3
+ !/.generated/package.json
4
+ /.svelte-kit/
5
+ /build/
6
+ # The seal of a build (`hearthlog artifact manifest`): it travels with the release artifact, not with the source.
7
+ /artifact-manifest.json
8
+ node_modules/
9
+ # Native apps (`hearthlog apple:*`): build output and personal device settings
10
+ /.apple-build/
11
+ /resign.local.json
@@ -0,0 +1,11 @@
1
+ {
2
+ "private": true,
3
+ "type": "module",
4
+ "packageManager": "pnpm@10.32.1",
5
+ "scripts": {
6
+ "build:generated": "hearthlog build",
7
+ "dev": "hearthlog build && vite dev",
8
+ "build": "hearthlog build && vite build",
9
+ "check": "hearthlog build && svelte-kit sync && tsc --noEmit -p tsconfig.json --skipLibCheck"
10
+ }
11
+ }
@@ -0,0 +1,18 @@
1
+ diff --git a/dist/processor.js b/dist/processor.js
2
+ --- a/dist/processor.js
3
+ +++ b/dist/processor.js
4
+ @@ -453,12 +453,13 @@ export class SQLocalProcessor {
5
+ const { queryKey } = message;
6
+ try {
7
+ const { name, data } = await this.driver.export();
8
+ + const transfer = data instanceof ArrayBuffer ? data : data.buffer;
9
+ this.emitMessage({
10
+ type: 'buffer',
11
+ queryKey,
12
+ bufferName: name,
13
+ buffer: data,
14
+ - }, [data]);
15
+ + }, [transfer]);
16
+ }
17
+ catch (error) {
18
+ this.emitMessage({
@@ -0,0 +1,8 @@
1
+ onlyBuiltDependencies:
2
+ - '@tailwindcss/oxide'
3
+ - esbuild
4
+ - sharp
5
+ - workerd
6
+
7
+ patchedDependencies:
8
+ sqlocal@0.18.0: patches/sqlocal@0.18.0.patch
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "{{id}}",
4
+ "ledgerAppName": "{{id}}",
5
+ "title": "{{title}}",
6
+ "features": {{features}},
7
+ "authorizedEmails": ["owner@example.com"]
8
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "infrastructure": {
3
+ "ledgerWorker": "example-ledger",
4
+ "invoicePdfsBucket": "example-invoice-pdfs",
5
+ "calendarFeedsBucket": "example-calendar-feeds",
6
+ "calendarPublicWorker": "example-calendar-public",
7
+ "calendarPublicOrigin": "https://example-calendar-public.example.workers.dev",
8
+ "galleryFilesBucket": "example-gallery-files",
9
+ "galleryPublicBucket": "example-gallery-public",
10
+ "galleryPublicWorker": "example-gallery-public",
11
+ "galleryPublicOrigin": "https://example-gallery-public.example.workers.dev",
12
+ "workersDevDomain": "example.workers.dev",
13
+ "ledgerAdminEmail": "owner@example.com",
14
+ "accessTeamDomain": "https://example.cloudflareaccess.com"
15
+ },
16
+ "sites": []
17
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "extends": ["$app/tsconfig", "./.generated/tsconfig.json"],
3
+ "compilerOptions": {
4
+ "strict": true,
5
+ "noUnusedLocals": true,
6
+ "types": ["node", "$app/types"]
7
+ },
8
+ "include": [
9
+ ".svelte-kit/ambient.d.ts",
10
+ ".svelte-kit/env.d.ts",
11
+ ".svelte-kit/non-ambient.d.ts",
12
+ ".svelte-kit/types/**/$types.d.ts",
13
+ "vite.config.ts",
14
+ ".generated/routes/**/*.ts",
15
+ ".generated/routes/**/*.svelte",
16
+ ".generated/*.d.ts",
17
+ "src/**/*.ts",
18
+ "src/**/*.svelte"
19
+ ],
20
+ "exclude": ["node_modules/**"]
21
+ }
@@ -0,0 +1,5 @@
1
+ // The site's Vite configuration is the shared one; the import is a relative path because Vite's config
2
+ // loader cannot load TypeScript from a package by name.
3
+ import { hearthlogConfig } from './node_modules/@hearthlog/tooling/src/vite/config.ts';
4
+
5
+ export default hearthlogConfig();
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.