@meadow-studio/platform 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 (79) hide show
  1. package/MeadowPlatform.podspec +17 -0
  2. package/Package.swift +23 -0
  3. package/README.md +147 -2
  4. package/android/build.gradle +42 -0
  5. package/android/src/main/AndroidManifest.xml +1 -0
  6. package/android/src/main/java/app/meadow/platform/MeadowAppRatingPlugin.java +38 -0
  7. package/dist/cli/commands.d.ts +74 -0
  8. package/dist/cli/commands.d.ts.map +1 -0
  9. package/dist/cli/commands.js +1062 -0
  10. package/dist/cli/commands.js.map +1 -0
  11. package/dist/cli/config.d.ts +123 -0
  12. package/dist/cli/config.d.ts.map +1 -0
  13. package/dist/cli/config.js +428 -0
  14. package/dist/cli/config.js.map +1 -0
  15. package/dist/cli/meadow.d.ts +8 -0
  16. package/dist/cli/meadow.d.ts.map +1 -0
  17. package/dist/cli/meadow.js +463 -0
  18. package/dist/cli/meadow.js.map +1 -0
  19. package/dist/cli/recipes.d.ts +10 -0
  20. package/dist/cli/recipes.d.ts.map +1 -0
  21. package/dist/cli/recipes.js +575 -0
  22. package/dist/cli/recipes.js.map +1 -0
  23. package/dist/cli/sync.d.ts +14 -0
  24. package/dist/cli/sync.d.ts.map +1 -0
  25. package/dist/cli/sync.js +310 -0
  26. package/dist/cli/sync.js.map +1 -0
  27. package/dist/cli/templates.d.ts +27 -0
  28. package/dist/cli/templates.d.ts.map +1 -0
  29. package/dist/cli/templates.js +1246 -0
  30. package/dist/cli/templates.js.map +1 -0
  31. package/dist/cli/website.d.ts +5 -0
  32. package/dist/cli/website.d.ts.map +1 -0
  33. package/dist/cli/website.js +262 -0
  34. package/dist/cli/website.js.map +1 -0
  35. package/dist/index.d.ts +5 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +5 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/notifications.d.ts +119 -0
  40. package/dist/notifications.d.ts.map +1 -0
  41. package/dist/notifications.js +320 -0
  42. package/dist/notifications.js.map +1 -0
  43. package/dist/platform.d.ts +163 -0
  44. package/dist/platform.d.ts.map +1 -0
  45. package/dist/platform.js +623 -0
  46. package/dist/platform.js.map +1 -0
  47. package/dist/purchases.d.ts +88 -0
  48. package/dist/purchases.d.ts.map +1 -0
  49. package/dist/purchases.js +296 -0
  50. package/dist/purchases.js.map +1 -0
  51. package/dist/ui/app-build.component.d.ts +18 -0
  52. package/dist/ui/app-build.component.d.ts.map +1 -0
  53. package/dist/ui/app-build.component.js +56 -0
  54. package/dist/ui/app-build.component.js.map +1 -0
  55. package/dist/ui/app-build.model.d.ts +11 -0
  56. package/dist/ui/app-build.model.d.ts.map +1 -0
  57. package/dist/ui/app-build.model.js +18 -0
  58. package/dist/ui/app-build.model.js.map +1 -0
  59. package/dist/ui/app-links.component.d.ts +14 -0
  60. package/dist/ui/app-links.component.d.ts.map +1 -0
  61. package/dist/ui/app-links.component.js +77 -0
  62. package/dist/ui/app-links.component.js.map +1 -0
  63. package/dist/ui/app-links.model.d.ts +18 -0
  64. package/dist/ui/app-links.model.d.ts.map +1 -0
  65. package/dist/ui/app-links.model.js +17 -0
  66. package/dist/ui/app-links.model.js.map +1 -0
  67. package/dist/ui/index.d.ts +5 -0
  68. package/dist/ui/index.d.ts.map +1 -0
  69. package/dist/ui/index.js +5 -0
  70. package/dist/ui/index.js.map +1 -0
  71. package/docs/CLI.md +376 -0
  72. package/docs/PLATFORM_GUIDE.md +422 -0
  73. package/docs/POC_FINDINGS.md +218 -0
  74. package/docs/PROJECT_BRIEF.md +501 -0
  75. package/docs/RELEASING.md +49 -0
  76. package/docs/V0.1_PATH.md +310 -0
  77. package/ios/Sources/MeadowPlatformPlugin/MeadowAppRatingPlugin.swift +39 -0
  78. package/package.json +89 -4
  79. package/schema/meadow-config.schema.json +250 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-links.component.js","sourceRoot":"","sources":["../../src/ui/app-links.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACL,8BAA8B,EAC9B,cAAc,GAEf,MAAM,sBAAsB,CAAC;;;;IAUpB,+BAIC;IACC,YACF;IAAA,oBAAI;;;IALF,wDAAkB;;IAIlB,cACF;IADE,8CACF;;;IARJ,8BAAqC;IACnC,sGAQC;IACH,oBAAM;;;;IATJ,cAQC;IARD,cAAA,cAAO,CAQN;;AAfT,2EAA2E;AA4C3E,MAAM,OAAO,uBAAuB;IACjB,MAAM,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;IAEhD,SAAS,GAAG,KAAK,CAAC,iBAAiB;kFAAC,CAAC;IACrC,YAAY,GAAG,KAAK,CAAC,8BAA8B,CAAC,OAAO;qFAAC,CAAC;IAC7D,YAAY,GAAG,KAAK,CAAC,8BAA8B,CAAC,OAAO;qFAAC,CAAC;IAC7D,UAAU,GAAG,KAAK,CAA4B,SAAS;mFAAC,CAAC;IACzD,YAAY,GAAG,KAAK,CAA4B,SAAS;qFAAC,CAAC;IAEjD,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE;QACvC,MAAM,MAAM,GAAwB;YAClC,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE;YAC5B,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE;SAC7B,CAAC;QACF,OAAO,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE;YAC7C,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;YAC7B,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE;SAClC,CAAC,CAAC;IACL,CAAC;8EAAC,CAAC;iHAlBQ,uBAAuB;6DAAvB,uBAAuB;YAvChC,sFAAsB;;YAAtB,6CAYC;;;iFA2BQ,uBAAuB;cA3CnC,SAAS;2BACE,kBAAkB,cAChB,IAAI,YACN;;;;;;;;;;;;;;GAcT;;kFA0BU,uBAAuB"}
@@ -0,0 +1,18 @@
1
+ import type { MeadowAppConfig } from '../platform.js';
2
+ export type MeadowAppLinkKind = 'privacy' | 'support';
3
+ export interface MeadowAppLink {
4
+ readonly kind: MeadowAppLinkKind;
5
+ readonly label: string;
6
+ readonly href: string;
7
+ }
8
+ export interface MeadowAppLinkLabels {
9
+ readonly privacy: string;
10
+ readonly support: string;
11
+ }
12
+ export interface MeadowAppLinkOverrides {
13
+ readonly privacyUrl?: string | null;
14
+ readonly supportEmail?: string | null;
15
+ }
16
+ export declare const DEFAULT_MEADOW_APP_LINK_LABELS: Readonly<MeadowAppLinkLabels>;
17
+ export declare function meadowAppLinks(app: Readonly<MeadowAppConfig>, labels?: Readonly<MeadowAppLinkLabels>, overrides?: Readonly<MeadowAppLinkOverrides>): readonly Readonly<MeadowAppLink>[];
18
+ //# sourceMappingURL=app-links.model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-links.model.d.ts","sourceRoot":"","sources":["../../src/ui/app-links.model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,8BAA8B,EAAE,QAAQ,CAAC,mBAAmB,CAGvE,CAAC;AAEH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,QAAQ,CAAC,eAAe,CAAC,EAC9B,MAAM,GAAE,QAAQ,CAAC,mBAAmB,CAAkC,EACtE,SAAS,GAAE,QAAQ,CAAC,sBAAsB,CAAM,GAC/C,SAAS,QAAQ,CAAC,aAAa,CAAC,EAAE,CAcpC"}
@@ -0,0 +1,17 @@
1
+ export const DEFAULT_MEADOW_APP_LINK_LABELS = Object.freeze({
2
+ privacy: 'Privacy',
3
+ support: 'Contact support',
4
+ });
5
+ export function meadowAppLinks(app, labels = DEFAULT_MEADOW_APP_LINK_LABELS, overrides = {}) {
6
+ const privacyUrl = overrides.privacyUrl === undefined ? app.privacyUrl : overrides.privacyUrl;
7
+ const supportEmail = overrides.supportEmail === undefined ? app.supportEmail : overrides.supportEmail;
8
+ const links = [];
9
+ if (privacyUrl && /^https?:\/\//i.test(privacyUrl)) {
10
+ links.push({ kind: 'privacy', label: labels.privacy, href: privacyUrl });
11
+ }
12
+ if (supportEmail && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(supportEmail)) {
13
+ links.push({ kind: 'support', label: labels.support, href: `mailto:${supportEmail}` });
14
+ }
15
+ return Object.freeze(links.map((link) => Object.freeze(link)));
16
+ }
17
+ //# sourceMappingURL=app-links.model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-links.model.js","sourceRoot":"","sources":["../../src/ui/app-links.model.ts"],"names":[],"mappings":"AAoBA,MAAM,CAAC,MAAM,8BAA8B,GAAkC,MAAM,CAAC,MAAM,CAAC;IACzF,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,iBAAiB;CAC3B,CAAC,CAAC;AAEH,MAAM,UAAU,cAAc,CAC5B,GAA8B,EAC9B,SAAwC,8BAA8B,EACtE,YAA8C,EAAE;IAEhD,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;IAC9F,MAAM,YAAY,GAChB,SAAS,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC;IACnF,MAAM,KAAK,GAAoB,EAAE,CAAC;IAElC,IAAI,UAAU,IAAI,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,YAAY,IAAI,4BAA4B,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QACpE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,YAAY,EAAE,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { MeadowAppBuildComponent } from './app-build.component.js';
2
+ export { DEFAULT_MEADOW_APP_BUILD_LABELS, formatMeadowAppBuild, type MeadowAppBuildLabels, } from './app-build.model.js';
3
+ export { MeadowAppLinksComponent } from './app-links.component.js';
4
+ export { DEFAULT_MEADOW_APP_LINK_LABELS, meadowAppLinks, type MeadowAppLink, type MeadowAppLinkKind, type MeadowAppLinkLabels, type MeadowAppLinkOverrides, } from './app-links.model.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EACL,+BAA+B,EAC/B,oBAAoB,EACpB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EACL,8BAA8B,EAC9B,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,GAC5B,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { MeadowAppBuildComponent } from './app-build.component.js';
2
+ export { DEFAULT_MEADOW_APP_BUILD_LABELS, formatMeadowAppBuild, } from './app-build.model.js';
3
+ export { MeadowAppLinksComponent } from './app-links.component.js';
4
+ export { DEFAULT_MEADOW_APP_LINK_LABELS, meadowAppLinks, } from './app-links.model.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EACL,+BAA+B,EAC/B,oBAAoB,GAErB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EACL,8BAA8B,EAC9B,cAAc,GAKf,MAAM,sBAAsB,CAAC"}
package/docs/CLI.md ADDED
@@ -0,0 +1,376 @@
1
+ # Meadow CLI
2
+
3
+ The Meadow CLI turns an app idea into a validated standalone repository with the repetitive mobile
4
+ foundation already installed. It intentionally generates ordinary project files: the app owns its
5
+ product code and design, while Meadow supplies the common toolchain, integrations, checks, and release
6
+ guardrails.
7
+
8
+ Read the [Meadow Platform guide](PLATFORM_GUIDE.md) first for the overall idea-to-release system,
9
+ capability map, ownership boundaries, and current maturity limits.
10
+
11
+ ## Requirements
12
+
13
+ - Node 24.15.x and npm 11
14
+ - Git
15
+ - Xcode for local iOS builds
16
+ - Android Studio/JDK 21 for local Android builds
17
+ - GitHub CLI only when creating a remote repository
18
+
19
+ Install `@meadow-studio/platform` from npm at an exact version, then run `meadow` through its package
20
+ binary. During platform development, a local file installation is supported.
21
+
22
+ ## Create an app
23
+
24
+ ```sh
25
+ meadow new <name>
26
+ ```
27
+
28
+ The app stays at the repository root. A second, static project is created in `website/` with home,
29
+ support, privacy, and terms pages. Both projects share one Git repository. To plan a subdomain, pass
30
+ `--website-base-domain meadow-development.app`; Flockbook then gets
31
+ `https://flockbook.meadow-development.app/` in `links.websiteUrl`. The domain is optional until it
32
+ is purchased. DNS, hosting, TLS, and publication are separate setup steps.
33
+
34
+ The privacy page starts with Meadow Development's publisher and support details, and reusable
35
+ explanations of the separately consented Firebase Analytics and Crashlytics services. New app
36
+ configs use `oestbalmer@gmail.com` as the support email unless another address is supplied.
37
+ The page is a draft with `noindex`: review the final app's data, events, retention, deletion,
38
+ website hosting, publisher address, and effective date before publication. The generated page
39
+ must match actual native behavior and store privacy disclosures.
40
+
41
+ Interactive creation asks for the display name, bundle/application ID, optional website base domain,
42
+ store links, supported orientation and device classes, and whether the app needs RevenueCat or Supabase. Firebase
43
+ Analytics and Crashlytics are part of the base stack but remain unconfigured until app-owned native
44
+ configuration is supplied.
45
+
46
+ Useful options:
47
+
48
+ ```text
49
+ --yes Use safe defaults without prompts
50
+ --config <file> Read answers or a full Meadow config from JSON
51
+ --website-base-domain <name> Derive the companion subdomain from the app slug
52
+ --directory <path> Choose the parent directory
53
+ --github Create and push a GitHub repository
54
+ --github-owner <owner> Choose a GitHub account or organization
55
+ --visibility <value> private, internal, or public; defaults to private
56
+ --no-install Write files without installing or validating
57
+ --no-git Do not create the local Git repository
58
+ --skip-visual-baselines Defer baseline screenshot generation
59
+ ```
60
+
61
+ Creation is atomic. The final directory appears only after dependency installation, formatting,
62
+ native-project generation, unit tests, linting, and production/device builds succeed. A normal
63
+ creation also installs Chromium and creates initial phone and tablet screenshot baselines. The
64
+ repository receives an initial gitmoji commit unless `--no-git` is used.
65
+
66
+ Each generated repository includes:
67
+
68
+ - Angular 22 standalone application code and strict TypeScript;
69
+ - a separate, dependency-free `website/` project with editable home, support, privacy, and terms pages;
70
+ - Capacitor 8 iOS and Android projects;
71
+ - Firebase Analytics and Crashlytics native dependencies;
72
+ - optional RevenueCat and Supabase client dependencies;
73
+ - provider-neutral `@meadow-studio/platform` runtime APIs;
74
+ - Vitest unit tests with 80% line/function/statement and 70% branch thresholds;
75
+ - Playwright phone and tablet screenshot tests;
76
+ - formatting, linting, web, device, Android, and unsigned iOS build commands;
77
+ - GitHub Actions for pull-request verification and manual visual-baseline generation;
78
+ - exact dependency versions, immutable GitHub Action hashes, and dependency auditing;
79
+ - release, CI, signing, and store checklists; and
80
+ - an `AGENTS.md` pointer to the capability guide bundled with the app's pinned platform version;
81
+ - a `.gitignore` that excludes generated web/native output, local configuration, signing files,
82
+ and test reports.
83
+
84
+ The template deliberately does not include Ionic or Meadow Design. An app may adopt either as an
85
+ app-owned decision, but neither is part of the Meadow foundation.
86
+
87
+ ## Adopt an existing app
88
+
89
+ In a newly created, empty Git checkout, `meadow init` generates the full app and companion website
90
+ directly in that repository. The checkout must contain only `.git`; Meadow preserves its Git history
91
+ and remote and does not create or push another repository. The display name defaults to the checkout
92
+ directory name, and the command prompts for app details unless `--yes` is supplied. Use
93
+ `--website-base-domain meadow-development.app` to plan the app's subdomain. `--dry-run` lists the
94
+ files without writing. With installation enabled, initialization runs the same app, native, and
95
+ visual validation as `meadow new`.
96
+
97
+ The generated project includes Firebase Analytics and Crashlytics dependencies by default. Both
98
+ native collection switches start disabled; production collection requires each service's separate
99
+ consent and app-owned Firebase configuration. The app must provide the actual consent interface.
100
+
101
+ For an existing Angular and Capacitor application, `init` follows the adoption flow below.
102
+
103
+ Use `init` inside an existing Angular 22 and Capacitor 8 application:
104
+
105
+ ```sh
106
+ meadow init --dry-run
107
+ meadow init
108
+ ```
109
+
110
+ Initialization also creates `website/` if it is missing. If the app already has a website project
111
+ in that directory, Meadow leaves it intact. `--dry-run` includes the website plan without writing.
112
+ The optional `--website-base-domain` sets a missing planned website URL; it does not replace an
113
+ existing URL in `meadow.config.json`.
114
+
115
+ The command inspects `package.json`, `angular.json`, and the Capacitor configuration before making
116
+ changes. It infers the display name, application ID, package version, and whether RevenueCat or
117
+ Supabase is already in use. Unsupported Angular or Capacitor major versions are rejected before any
118
+ file is written. Interactive mode asks for a missing website base domain and whether to add optional
119
+ providers that are not already detectable; use `--config` to override other inferred metadata.
120
+
121
+ The adoption plan can:
122
+
123
+ - create `meadow.config.json` when it is missing, while preserving an existing valid configuration;
124
+ - install a pinned `@meadow-studio/platform` and missing shared provider dependencies;
125
+ - add only missing Meadow-owned package scripts, leaving existing scripts unchanged;
126
+ - create `.nvmrc` only when the app does not already have one;
127
+ - add or refresh marked Meadow sections in `AGENTS.md`, `.gitignore`, and `.env.example`; and
128
+ - install dependencies and finish by printing the complete `meadow doctor` result.
129
+
130
+ Useful options:
131
+
132
+ ```text
133
+ --dry-run Print the complete plan without writing or installing
134
+ --yes Accept inferred values without prompts
135
+ --config <file> Override inferred answers with JSON
136
+ --website-base-domain <name> Set a missing planned companion website URL
137
+ --directory <path> Initialize a project outside the current directory
138
+ --platform-spec <value> Install or intentionally replace the platform dependency spec
139
+ --no-install Update files without running npm install
140
+ ```
141
+
142
+ Managed sections are delimited by `meadow-platform:start` and `meadow-platform:end`. Re-running `init`
143
+ updates only those sections and is otherwise idempotent. A malformed or half-present marker pair is
144
+ treated as an error rather than risking app-owned content.
145
+
146
+ `init` establishes the Meadow control plane; it does not blindly replace application code, existing
147
+ CI, test configuration, Angular or Capacitor versions, or app-specific architecture. `meadow doctor`
148
+ reports missing pieces of the complete release-oriented foundation so they can be adopted
149
+ deliberately. Ionic and other app-owned dependencies are retained and reported without becoming
150
+ Meadow Platform dependencies.
151
+
152
+ ## Synchronize typed configuration
153
+
154
+ `meadow.config.json` version 2 is the source of truth for durable application and release intent:
155
+
156
+ - display name, slug, and separate iOS and Android identifiers;
157
+ - enabled platforms, device classes, and orientation;
158
+ - semantic version, build number, and release channel;
159
+ - development, test, and production runtime behavior;
160
+ - support, privacy, terms, website, App Store, and Play Store links;
161
+ - enabled Firebase, RevenueCat, Supabase, local-data, and local-notification capabilities;
162
+ - RevenueCat entitlement, offering, and product identifiers;
163
+ - the Supabase project reference and names of variables containing public client configuration;
164
+ - analytics events and typed property definitions; and
165
+ - CI screenshot viewports.
166
+
167
+ For a Meadow-generated companion site, `meadow sync` also updates `website/site.config.json` with
168
+ the app name, description, planned URL, and support email. Website page content and styling stay
169
+ app-owned. Use `npm run website:start` to preview the site and `npm run website:check` to build it.
170
+ Draft support and legal content must be replaced and `noindex` removed before publication.
171
+
172
+ After editing the config, run:
173
+
174
+ ```sh
175
+ meadow sync
176
+ ```
177
+
178
+ Synchronization updates:
179
+
180
+ - `package.json` release metadata, platform/capability dependencies, and Meadow scripts;
181
+ - `capacitor.config.ts` app identity and generated environment files;
182
+ - app-owned generated runtime configuration and typed analytics APIs under `src/app/meadow/`;
183
+ - the local-service configuration generator used before development and production builds;
184
+ - Playwright viewport projects;
185
+ - Android application ID, display name, orientation, version, and build metadata when present; and
186
+ - iOS bundle ID, display name, orientation, version, and build metadata when present.
187
+
188
+ When dependencies change, the command runs `npm install`; use `--no-install` when a separate process
189
+ will update the lockfile. Generated TypeScript and configuration files carry a warning header. Meadow
190
+ will not replace a conflicting unmarked file at one of those paths.
191
+
192
+ Use the read-only form locally and in CI:
193
+
194
+ ```sh
195
+ meadow sync --check
196
+ ```
197
+
198
+ It exits unsuccessfully when normalized configuration, dependencies, generated source, native
199
+ metadata, or testing viewports have drifted. `meadow doctor` includes the same drift check.
200
+
201
+ Analytics definitions generate an app-owned, compile-time API. For example:
202
+
203
+ ```json
204
+ {
205
+ "analytics": {
206
+ "events": {
207
+ "pushups_logged": {
208
+ "properties": {
209
+ "reps": { "type": "integer", "required": true },
210
+ "source": {
211
+ "type": "string",
212
+ "required": false,
213
+ "values": ["home", "notification"]
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ ```
221
+
222
+ This produces an `AppAnalytics` wrapper that rejects unknown events, missing required properties,
223
+ wrong value types, and invalid enumerated strings during TypeScript compilation.
224
+
225
+ Never put credentials, service-role keys, signing material, or other secrets in
226
+ `meadow.config.json`. Supabase and RevenueCat configuration records variable names and public product
227
+ identifiers; actual environment values remain external. Generated apps run `npm run
228
+ services:config` before serving or building. It reads local public client values and writes the
229
+ ignored `public/meadow-service-config.js` runtime asset.
230
+
231
+ ## Add local notifications
232
+
233
+ From a generated app, add native local notifications with:
234
+
235
+ ```sh
236
+ meadow add notifications
237
+ ```
238
+
239
+ The recipe pins `@capacitor/local-notifications`, updates `meadow.config.json`, installs the package,
240
+ synchronizes each existing native project, updates the generated runtime and release checklist,
241
+ and runs the app checks before marking the capability configured. If installation or native sync
242
+ is interrupted, rerun the same command; an enabled but unconfigured capability is resumable.
243
+
244
+ The runtime does not request permission during initialization or scheduling. The app explains the
245
+ benefit and calls `MeadowNotificationService.requestPermission()` from a user action. The app also
246
+ owns notification IDs, copy, schedule rules, Android channels, tap navigation, and analytics.
247
+ Meadow owns provider adaptation, permission state, one-off and recurring calendar scheduling,
248
+ replace/cancel/pending operations, tap events, safe web behavior, and normalized failures.
249
+
250
+ Android schedules are inexact by default. Do not add exact-alarm permission unless a concrete app
251
+ requires exact timing and its store/disclosure implications have been reviewed. Before release,
252
+ test grant and denial behavior, scheduling, replacement, cancellation, the Android channel, and
253
+ tap navigation on both enabled platforms.
254
+
255
+ ## Add local data
256
+
257
+ From a generated app, add the proven local-data foundation with:
258
+
259
+ ```sh
260
+ meadow add local-data
261
+ ```
262
+
263
+ The recipe installs pinned SQLite dependencies, synchronizes both native projects, and generates:
264
+
265
+ - a Meadow-owned `LocalDatabase` wrapper with parameterized queries, writes, and transactions;
266
+ - sequential, immutable database migrations;
267
+ - a small typed JSON document store for settings and other simple records;
268
+ - an example unit test and app-repository guidance;
269
+ - the SQLite WebAssembly runtime for browser development; and
270
+ - Android backup exclusions plus local-data release checks.
271
+
272
+ iOS and Android use native SQLite. Browser development uses the same SQLite engine persisted in
273
+ IndexedDB, avoiding a second storage behavior just for web previews. Application-specific tables,
274
+ models, validation, and repositories stay in the app rather than `@meadow-studio/platform`.
275
+
276
+ If installation or validation is interrupted, rerun the same command. Meadow records the incomplete
277
+ recipe, preserves any generated file you changed while fixing the problem, fills in missing files,
278
+ and validates the capability again before marking it configured.
279
+
280
+ After adding a migration, update `services.localData.databaseVersion` in `meadow.config.json` to match
281
+ the final migration. Never edit a migration that has shipped. Before release, test both a fresh
282
+ database and an upgrade from the previous app version, verify deletion/reset behavior, and review
283
+ the generated SQLCipher export-compliance checklist item.
284
+
285
+ ## Configure integrations
286
+
287
+ Run configuration commands from the generated app directory:
288
+
289
+ ```sh
290
+ meadow configure firebase \
291
+ --google-services /path/to/google-services.json \
292
+ --google-service-info /path/to/GoogleService-Info.plist
293
+
294
+ meadow configure revenuecat \
295
+ --ios-key <public-sdk-key> \
296
+ --android-key <public-sdk-key> \
297
+ --entitlement <id> \
298
+ --offering <id>
299
+
300
+ meadow configure supabase \
301
+ --url https://<project>.supabase.co \
302
+ --publishable-key <publishable-key>
303
+
304
+ meadow configure assets --source /path/to/icon.png
305
+ meadow configure signing
306
+ meadow configure store --support-email <email> --support-url <url> \
307
+ --privacy-url <url> --terms-url <url> --website-url <url> \
308
+ --apple-app-id <id> --app-store-url <url> --play-store-url <url>
309
+ meadow configure github --owner <owner> --visibility private
310
+ ```
311
+
312
+ RevenueCat and Supabase client values go in the ignored `.env.meadow.local`. RevenueCat configuration
313
+ requires a public key only for each enabled native platform, validates the `appl_`, `goog_`, or
314
+ `test_` key prefix, installs the pinned SDK, synchronizes Capacitor, and records the app-owned
315
+ offering and entitlement identifiers. Builds convert those keys into the ignored runtime asset;
316
+ `MeadowPurchaseService` then owns initialization, product loading, entitlement state, purchase,
317
+ restore, and provider-error normalization.
318
+
319
+ The Supabase command rejects service-role and secret keys; release readiness still requires
320
+ explicit grants, row-level security, storage policies, and database tests. Firebase configuration
321
+ is required only for the enabled native platforms. The command validates and copies those
322
+ app-owned files, synchronizes Capacitor, installs the Android build plugins, registers the iOS
323
+ configuration file as an app resource, and keeps Analytics and Crashlytics collection off at the
324
+ native layer until the user grants consent. Firebase files are never added to the platform
325
+ package.
326
+
327
+ The application owns the consent screen and copy. Apply the resulting choices through
328
+ `MeadowAnalyticsService.setConsent(...)` and `MeadowCrashReportingService.setConsent(...)`. Choices are
329
+ persisted separately. Development and test environments remain disabled even when a stored
330
+ production consent choice exists.
331
+
332
+ ## Diagnose and release
333
+
334
+ ```sh
335
+ meadow doctor
336
+ meadow doctor --json
337
+ meadow version patch test
338
+ meadow release-check all
339
+ ```
340
+
341
+ `meadow doctor` checks the pinned stack, required files and scripts, native projects, Meadow-generated
342
+ website pages, the local-data
343
+ runtime when enabled, Firebase dependencies, native opt-in defaults, the bundled iOS Firebase
344
+ resource, RevenueCat dependency, platform keys and catalog identifiers, local-notification
345
+ dependency and native synchronization, visual baselines, and integration state. `meadow version`
346
+ increments or sets the semantic app version, increments the build
347
+ number, and synchronizes web, Android, and iOS metadata.
348
+
349
+ `meadow release-check` turns missing native projects, baselines, or enabled-service configuration into
350
+ failures and then runs the complete quality, visual, and selected native build gates. Production
351
+ also requires a website URL plus support, privacy, and terms information.
352
+
353
+ ## Pull-request CI
354
+
355
+ Every generated pull request runs four independent jobs:
356
+
357
+ 1. formatting, linting, dependency audit, coverage-gated unit tests, production app web build,
358
+ and companion website build;
359
+ 2. deterministic Playwright screenshot comparisons at phone and tablet sizes;
360
+ 3. Android debug compilation on Linux with JDK 21; and
361
+ 4. an unsigned iOS simulator build on macOS.
362
+
363
+ Successful Android jobs upload `android-debug-apk`, a downloadable debug APK in the Actions run.
364
+ The visual job uploads `playwright-report` with the HTML report and screenshot results. Playwright
365
+ also adds GitHub test annotations; a separate trusted workflow comments on a PR when screenshot
366
+ comparisons fail, naming the failures and linking to the downloadable report. This reports failures
367
+ without requiring a preview host or a custom token for inline image attachments.
368
+
369
+ CI installs the exact public `@meadow-studio/platform` version from npm using the committed lockfile. No
370
+ Meadow package secret or source-repository access is needed, including for fork pull requests. The
371
+ version must be published before a default `meadow init` install can run.
372
+
373
+ CI never updates screenshots implicitly. The visual comparison and baseline workflow both use the
374
+ same pinned macOS runner family as the local Meadow development environment. Use the manual **Generate
375
+ visual baselines** workflow to produce candidates, inspect the artifact, then commit intentional
376
+ changes.