@stoker-platform/cli 0.5.12

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 (94) hide show
  1. package/LICENSE.md +102 -0
  2. package/init-files/.##gitignore## +102 -0
  3. package/init-files/.devcontainer/devcontainer.json +14 -0
  4. package/init-files/.env/.env +70 -0
  5. package/init-files/.eslintrc.cjs +35 -0
  6. package/init-files/.firebaserc +6 -0
  7. package/init-files/.prettierignore +86 -0
  8. package/init-files/.prettierrc +5 -0
  9. package/init-files/bin/build.js +221 -0
  10. package/init-files/bin/shim.js +159 -0
  11. package/init-files/extensions/firestore-send-email.env +7 -0
  12. package/init-files/external.package.json +4 -0
  13. package/init-files/firebase-rules/database.rules.json +9 -0
  14. package/init-files/firebase-rules/firestore.custom.rules +19 -0
  15. package/init-files/firebase-rules/firestore.indexes.json +0 -0
  16. package/init-files/firebase-rules/firestore.rules +0 -0
  17. package/init-files/firebase-rules/storage.rules +0 -0
  18. package/init-files/firebase.hosting.json +122 -0
  19. package/init-files/firebase.json +52 -0
  20. package/init-files/functions/.##gitignore## +14 -0
  21. package/init-files/functions/.eslintrc.cjs +28 -0
  22. package/init-files/functions/package.json +46 -0
  23. package/init-files/functions/prompts/chat.prompt +17 -0
  24. package/init-files/functions/src/index.ts +457 -0
  25. package/init-files/functions/tsconfig.dev.json +3 -0
  26. package/init-files/functions/tsconfig.json +17 -0
  27. package/init-files/icons/logo-large.png +0 -0
  28. package/init-files/icons/logo-small.png +0 -0
  29. package/init-files/ops.js +25 -0
  30. package/init-files/package.json +53 -0
  31. package/init-files/project-data.json +5 -0
  32. package/init-files/remoteconfig.template.json +1 -0
  33. package/init-files/src/collections/Inbox.ts +444 -0
  34. package/init-files/src/collections/Outbox.ts +270 -0
  35. package/init-files/src/collections/Settings.ts +44 -0
  36. package/init-files/src/collections/Users.ts +138 -0
  37. package/init-files/src/main.ts +245 -0
  38. package/init-files/src/utils.ts +3 -0
  39. package/init-files/src/vite-env.d.ts +1 -0
  40. package/init-files/test/test.ts +5 -0
  41. package/init-files/tsconfig.json +23 -0
  42. package/init-files/vitest.config.ts +9 -0
  43. package/lib/package.json +45 -0
  44. package/lib/src/data/exportToBigQuery.js +41 -0
  45. package/lib/src/data/seedData.js +347 -0
  46. package/lib/src/deploy/applySchema.js +43 -0
  47. package/lib/src/deploy/cloud-functions/getFunctionsData.js +18 -0
  48. package/lib/src/deploy/deployProject.js +116 -0
  49. package/lib/src/deploy/firestore-export/exportFirestoreData.js +29 -0
  50. package/lib/src/deploy/firestore-ttl/deployTTLs.js +127 -0
  51. package/lib/src/deploy/live-update/liveUpdate.js +22 -0
  52. package/lib/src/deploy/maintenance/activateMaintenanceMode.js +9 -0
  53. package/lib/src/deploy/maintenance/disableMaintenanceMode.js +9 -0
  54. package/lib/src/deploy/maintenance/setDeploymentStatus.js +22 -0
  55. package/lib/src/deploy/rules-indexes/generateFirestoreIndexes.js +23 -0
  56. package/lib/src/deploy/rules-indexes/generateFirestoreRules.js +35 -0
  57. package/lib/src/deploy/rules-indexes/generateStorageRules.js +23 -0
  58. package/lib/src/deploy/schema/generateSchema.js +184 -0
  59. package/lib/src/deploy/schema/persistSchema.js +14 -0
  60. package/lib/src/lint/lintSchema.js +1491 -0
  61. package/lib/src/lint/securityReport.js +223 -0
  62. package/lib/src/main.js +460 -0
  63. package/lib/src/migration/firestore/migrateFirestore.js +8 -0
  64. package/lib/src/migration/firestore/operations/deleteField.js +58 -0
  65. package/lib/src/migration/migrateAll.js +30 -0
  66. package/lib/src/ops/auditDenormalized.js +124 -0
  67. package/lib/src/ops/auditPermissions.js +92 -0
  68. package/lib/src/ops/auditRelations.js +186 -0
  69. package/lib/src/ops/explainPreloadQueries.js +65 -0
  70. package/lib/src/ops/getUser.js +10 -0
  71. package/lib/src/ops/getUserPermissions.js +19 -0
  72. package/lib/src/ops/getUserRecord.js +20 -0
  73. package/lib/src/ops/listProjects.js +8 -0
  74. package/lib/src/ops/setUserCollection.js +14 -0
  75. package/lib/src/ops/setUserDocument.js +11 -0
  76. package/lib/src/ops/setUserRole.js +14 -0
  77. package/lib/src/project/addProject.js +935 -0
  78. package/lib/src/project/addRecord.js +9 -0
  79. package/lib/src/project/addRecordPrompt.js +205 -0
  80. package/lib/src/project/addTenant.js +59 -0
  81. package/lib/src/project/buildWebApp.js +10 -0
  82. package/lib/src/project/customDomain.js +157 -0
  83. package/lib/src/project/deleteProject.js +51 -0
  84. package/lib/src/project/deleteRecord.js +11 -0
  85. package/lib/src/project/deleteTenant.js +49 -0
  86. package/lib/src/project/getOne.js +25 -0
  87. package/lib/src/project/getSome.js +28 -0
  88. package/lib/src/project/initProject.js +16 -0
  89. package/lib/src/project/prepareEmulatorData.js +125 -0
  90. package/lib/src/project/setProject.js +13 -0
  91. package/lib/src/project/startEmulators.js +30 -0
  92. package/lib/src/project/updateRecord.js +9 -0
  93. package/lib/tsconfig.tsbuildinfo +1 -0
  94. package/package.json +45 -0
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env -S node --no-warnings
2
+
3
+ import { dirname, join, resolve } from "path"
4
+ import { existsSync, mkdirSync, readdirSync, statSync, readFileSync, writeFileSync, unlinkSync } from "fs"
5
+
6
+ // AI-generated code to shim custom admin app modules
7
+
8
+ try {
9
+ const systemCustomRoot = resolve(process.cwd(), "functions", "src", "system-custom")
10
+
11
+ if (!existsSync(systemCustomRoot)) {
12
+ process.exit(0)
13
+ }
14
+
15
+ const importMap = new Map()
16
+
17
+ const addImportSpec = (specPath, specifiers) => {
18
+ if (!importMap.has(specPath)) {
19
+ importMap.set(specPath, { hasDefault: false, named: new Set() })
20
+ }
21
+ const record = importMap.get(specPath)
22
+ if (specifiers.default) record.hasDefault = true
23
+ for (const name of specifiers.named || []) record.named.add(name)
24
+ }
25
+
26
+ const walkFiles = (dir) => {
27
+ const entries = readdirSync(dir)
28
+ for (const entry of entries) {
29
+ const full = join(dir, entry)
30
+ const stats = statSync(full)
31
+ if (stats.isDirectory()) {
32
+ walkFiles(full)
33
+ } else if (stats.isFile()) {
34
+ if (/(\.ts|\.tsx|\.js|\.mjs)$/.test(entry) && !/\.d\.ts$/.test(entry)) {
35
+ const code = readFileSync(full, "utf8")
36
+ const lines = code.split(/\r?\n/)
37
+ for (const line of lines) {
38
+ // ESM imports on a single line
39
+ const importMatch = line.match(/^\s*import\s+(.*?)\s+from\s+["']\.\.\/web\/([^"']+)["']/)
40
+ if (importMatch) {
41
+ let bindings = importMatch[1].trim()
42
+ const rel = importMatch[2].trim()
43
+ const spec = { default: false, named: [] }
44
+ if (bindings.startsWith("type ")) {
45
+ bindings = bindings.slice(5).trim()
46
+ }
47
+ if (bindings.startsWith("* as ")) {
48
+ // namespace import; no specific exports required
49
+ } else if (bindings.startsWith("{")) {
50
+ const names = bindings
51
+ .replace(/[\{\}]/g, "")
52
+ .split(",")
53
+ .map((s) =>
54
+ s
55
+ .trim()
56
+ .split(/\s+as\s+/)[0]
57
+ .trim(),
58
+ )
59
+ .filter(Boolean)
60
+ spec.named = names
61
+ } else if (bindings.includes(",")) {
62
+ const [def, rest] = bindings.split(",")
63
+ spec.default = def.trim().length > 0
64
+ const names = rest
65
+ .replace(/[\{\}]/g, "")
66
+ .split(",")
67
+ .map((s) =>
68
+ s
69
+ .trim()
70
+ .split(/\s+as\s+/)[0]
71
+ .trim(),
72
+ )
73
+ .filter(Boolean)
74
+ spec.named = names
75
+ } else {
76
+ spec.default = true
77
+ }
78
+ addImportSpec(rel, spec)
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
85
+
86
+ walkFiles(systemCustomRoot)
87
+
88
+ if (importMap.size === 0) {
89
+ process.exit(0)
90
+ }
91
+
92
+ const customDir = join(systemCustomRoot, "web")
93
+ if (!existsSync(customDir)) mkdirSync(customDir, { recursive: true })
94
+
95
+ for (const [relPath, spec] of importMap.entries()) {
96
+ const outPathJs = join(customDir, relPath)
97
+ const outDir = dirname(outPathJs)
98
+ if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true })
99
+
100
+ // Determine base without extension
101
+ const baseRel = relPath.replace(/\.(js|mjs|cjs|ts|tsx)$/, "")
102
+
103
+ // Remove any colliding TypeScript sources in src/system-custom/web
104
+ const tsCandidates = [`${baseRel}.ts`, `${baseRel}.tsx`]
105
+ for (const candidate of tsCandidates) {
106
+ const tsPath = join(customDir, candidate)
107
+ if (existsSync(tsPath)) {
108
+ try {
109
+ unlinkSync(tsPath)
110
+ } catch {}
111
+ }
112
+ }
113
+
114
+ // Remove any stale compiled JS outputs in lib/system-custom/web
115
+ const libCustomDir = resolve(process.cwd(), "functions", "lib", "system-custom", "web")
116
+ if (existsSync(libCustomDir)) {
117
+ const jsCandidates = [
118
+ `${baseRel}.js`,
119
+ `${baseRel}.mjs`,
120
+ `${baseRel}.cjs`,
121
+ `${baseRel}.js.map`,
122
+ `${baseRel}.d.ts`,
123
+ `${baseRel}.d.ts.map`,
124
+ ]
125
+ for (const candidate of jsCandidates) {
126
+ const jsPath = join(libCustomDir, candidate)
127
+ if (existsSync(jsPath)) {
128
+ try {
129
+ unlinkSync(jsPath)
130
+ } catch {}
131
+ }
132
+ }
133
+ }
134
+
135
+ // Remove any previously generated JS shim in src (we'll emit TS stubs instead)
136
+ if (existsSync(outPathJs)) {
137
+ try {
138
+ unlinkSync(outPathJs)
139
+ } catch {}
140
+ }
141
+
142
+ // Emit a TypeScript stub to ensure TSC outputs to lib
143
+ const tsOutPath = join(customDir, `${baseRel}.ts`)
144
+ let tsContent = ""
145
+ if (spec.hasDefault) {
146
+ tsContent += "const _default: any = undefined\nexport default _default\n"
147
+ }
148
+ for (const name of spec.named) {
149
+ tsContent += `export const ${name}: any = undefined\n`
150
+ }
151
+ if (tsContent === "") {
152
+ tsContent = "export {}\n"
153
+ }
154
+ writeFileSync(tsOutPath, tsContent, "utf8")
155
+ }
156
+ } catch (error) {
157
+ console.error(error)
158
+ process.exit(1)
159
+ }
@@ -0,0 +1,7 @@
1
+ ALLOWED_EVENT_TYPES=firebase.extensions.firestore-send-email.v1.onStart,firebase.extensions.firestore-send-email.v1.onProcessing,firebase.extensions.firestore-send-email.v1.onRetry,firebase.extensions.firestore-send-email.v1.onPending,firebase.extensions.firestore-send-email.v1.onSuccess,firebase.extensions.firestore-send-email.v1.onComplete,firebase.extensions.firestore-send-email.v1.onError
2
+ AUTH_TYPE=UsernamePassword
3
+ MAIL_COLLECTION=system_mail
4
+ TTL_EXPIRE_TYPE=never
5
+ TTL_EXPIRE_VALUE=1
6
+ SMTP_PASSWORD=projects/${param:PROJECT_NUMBER}/secrets/firestore-send-email-SMTP_PASSWORD/versions/latest
7
+ DATABASE=(default)
@@ -0,0 +1,4 @@
1
+ {
2
+ "web": {},
3
+ "server": {}
4
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "rules": {
3
+ ".read": false,
4
+ ".write": false,
5
+ "schema": {
6
+ ".indexOn": "published_time"
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,19 @@
1
+ // MAIL
2
+
3
+ match /system_mail/{mail} {
4
+ allow create: if false
5
+ }
6
+
7
+ // SMS
8
+
9
+ match /system_messages/{message} {
10
+ allow create: if false
11
+ }
12
+
13
+ match /tenants/{tenantId} {
14
+ allow create: if false
15
+
16
+ // COLLECTIONS
17
+
18
+
19
+ }
File without changes
File without changes
@@ -0,0 +1,122 @@
1
+ {
2
+ "hosting": {
3
+ "public": "dist",
4
+ "ignore": [
5
+ "firebase.json",
6
+ "**/.*",
7
+ "**/node_modules/**",
8
+ "src/**",
9
+ "bin/**",
10
+ "vite.config.ts",
11
+ "tsconfig.json",
12
+ "tsconfig.app.json",
13
+ "tsconfig.node.json",
14
+ "remoteconfig.template.json",
15
+ "tailwind.config.js",
16
+ "postcss.config.js",
17
+ "components.json"
18
+ ],
19
+ "rewrites": [
20
+ {
21
+ "source": "**",
22
+ "destination": "/index.html"
23
+ }
24
+ ],
25
+ "headers": [
26
+ {
27
+ "source": "/index.html",
28
+ "headers": [
29
+ {
30
+ "key": "Cache-Control",
31
+ "value": "no-cache"
32
+ }
33
+ ]
34
+ },
35
+ {
36
+ "source": "**/*.@(js|css|png|svg|ico|txt)",
37
+ "headers": [
38
+ {
39
+ "key": "Cache-Control",
40
+ "value": "public,max-age=31536000,immutable"
41
+ }
42
+ ]
43
+ },
44
+ {
45
+ "source": "/sw.js",
46
+ "headers": [
47
+ {
48
+ "key": "Cache-Control",
49
+ "value": "no-cache"
50
+ }
51
+ ]
52
+ },
53
+ {
54
+ "source": "**",
55
+ "headers": [
56
+ {
57
+ "key": "Cross-Origin-Opener-Policy",
58
+ "value": "same-origin"
59
+ },
60
+ {
61
+ "key": "Cross-Origin-Resource-Policy",
62
+ "value": "same-site"
63
+ },
64
+ {
65
+ "key": "X-Permitted-Cross-Domain-Policies",
66
+ "value": "none"
67
+ },
68
+ {
69
+ "key": "Referrer-Policy",
70
+ "value": "no-referrer"
71
+ },
72
+ {
73
+ "key": "Origin-Agent-Cluster",
74
+ "value": "?1"
75
+ },
76
+ {
77
+ "key": "X-Content-Type-Options",
78
+ "value": "nosniff"
79
+ },
80
+ {
81
+ "key": "X-DNS-Prefetch-Control",
82
+ "value": "off"
83
+ },
84
+ {
85
+ "key": "X-Download-Options",
86
+ "value": "noopen"
87
+ },
88
+ {
89
+ "key": "X-Frame-Options",
90
+ "value": "DENY"
91
+ },
92
+ {
93
+ "key": "X-XSS-Protection",
94
+ "value": "0"
95
+ },
96
+ {
97
+ "key": "Strict-Transport-Security",
98
+ "value": "max-age=31536000; includeSubDomains; preload"
99
+ },
100
+ {
101
+ "key": "Permissions-Policy",
102
+ "value": "accelerometer=(), autoplay=(), camera=(), cross-origin-isolated=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), usb=(), web-share=(), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(), gamepad=(), hid=(), idle-detection=(), interest-cohort=(), serial=()"
103
+ },
104
+ {
105
+ "key": "Content-Security-Policy",
106
+ "value": "default-src 'self'; base-uri 'none'; frame-src 'self' https://*.firebasedatabase.app https://www.google.com; object-src 'none'; font-src 'self' data: https://fonts.googleapis.com https://fonts.gstatic.com; form-action 'self'; script-src 'self' https://www.google.com https://www.gstatic.com https://www.google-analytics.com https://www.googletagmanager.com https://*.firebasedatabase.app https://*.googleapis.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: blob: https://firebasestorage.googleapis.com https://storage.googleapis.com https://maps.googleapis.com https://maps.gstatic.com https://developers.google.com https://www.googletagmanager.com https://picsum.photos https://*.picsum.photos https://loremflickr.com; connect-src 'self' https://www.google.com https://*.googleapis.com https://www.google-analytics.com wss://*.firebasedatabase.app https://*.cloudfunctions.net https://*.ingest.us.sentry.io https://*.algolianet.com https://*.algolia.net; media-src 'self'; manifest-src 'self'; frame-ancestors 'none'"
107
+ }
108
+ ]
109
+ }
110
+ ]
111
+ },
112
+ "emulators": {
113
+ "hosting": {
114
+ "port": 5000,
115
+ "host": "0.0.0.0"
116
+ },
117
+ "ui": {
118
+ "enabled": true
119
+ },
120
+ "singleProjectMode": true
121
+ }
122
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "database": {
3
+ "rules": "firebase-rules/database.rules.json"
4
+ },
5
+ "firestore": {
6
+ "rules": "firebase-rules/firestore.rules",
7
+ "indexes": "firebase-rules/firestore.indexes.json"
8
+ },
9
+ "storage": [
10
+ {
11
+ "target": "default",
12
+ "rules": "firebase-rules/storage.rules"
13
+ }
14
+ ],
15
+ "functions": [
16
+ {
17
+ "source": "functions",
18
+ "codebase": "default",
19
+ "ignore": ["node_modules", ".git", "firebase-debug.log", "firebase-debug.*.log", "*.local"]
20
+ }
21
+ ],
22
+ "emulators": {
23
+ "auth": {
24
+ "port": 9099
25
+ },
26
+ "functions": {
27
+ "port": 5001
28
+ },
29
+ "firestore": {
30
+ "port": 8080
31
+ },
32
+ "database": {
33
+ "port": 9000
34
+ },
35
+ "pubsub": {
36
+ "port": 8085
37
+ },
38
+ "storage": {
39
+ "port": 9199
40
+ },
41
+ "eventarc": {
42
+ "port": 9299
43
+ },
44
+ "ui": {
45
+ "enabled": true
46
+ },
47
+ "singleProjectMode": true
48
+ },
49
+ "extensions": {
50
+ "firestore-send-email": "firebase/firestore-send-email@0.2.4"
51
+ }
52
+ }
@@ -0,0 +1,14 @@
1
+ # Compiled JavaScript files
2
+ lib/**/*.js
3
+ lib/**/*.js.map
4
+
5
+ # TypeScript v1 declaration files
6
+ typings/
7
+
8
+ # Node.js dependency directory
9
+ node_modules/
10
+ *.local
11
+
12
+ src/system-custom
13
+ project-data.json
14
+ .secret.local
@@ -0,0 +1,28 @@
1
+ module.exports = {
2
+ root: true,
3
+ env: {
4
+ es6: true,
5
+ node: true,
6
+ },
7
+ extends: [
8
+ "eslint:recommended",
9
+ "plugin:import/errors",
10
+ "plugin:import/warnings",
11
+ "plugin:import/typescript",
12
+ "google",
13
+ "plugin:@typescript-eslint/recommended",
14
+ "plugin:security/recommended-legacy",
15
+ ],
16
+ parser: "@typescript-eslint/parser",
17
+ parserOptions: {
18
+ project: ["tsconfig.json", "tsconfig.dev.json"],
19
+ sourceType: "module",
20
+ },
21
+ ignorePatterns: ["/lib/**/*", "src/system-custom/**/*"],
22
+ plugins: ["@typescript-eslint", "import"],
23
+ rules: {
24
+ quotes: ["error", "double"],
25
+ "import/no-unresolved": 0,
26
+ indent: ["error", 4],
27
+ },
28
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "overrides": {
3
+ "dotprompt": "1.1.1"
4
+ },
5
+ "name": "functions",
6
+ "type": "module",
7
+ "scripts": {
8
+ "lint": "eslint --ext .js,.ts .",
9
+ "build": "tsc",
10
+ "build:watch": "tsc --watch --preserveWatchOutput",
11
+ "serve": "npm run build && firebase emulators:start --only functions",
12
+ "shell": "npm run build && firebase functions:shell",
13
+ "start": "npm run shell",
14
+ "deploy": "firebase deploy --only functions",
15
+ "logs": "firebase functions:log"
16
+ },
17
+ "engines": {
18
+ "node": "22"
19
+ },
20
+ "main": "lib/index.js",
21
+ "dependencies": {
22
+ "@genkit-ai/firebase": "latest",
23
+ "@genkit-ai/vertexai": "latest",
24
+ "@google-cloud/storage": "latest",
25
+ "@stoker-platform/node-client": "latest",
26
+ "@stoker-platform/system-functions": "latest",
27
+ "@stoker-platform/types": "latest",
28
+ "algoliasearch": "latest",
29
+ "dotenv": "latest",
30
+ "firebase-admin": "latest",
31
+ "firebase-functions": "6.6.0",
32
+ "genkit": "latest",
33
+ "lodash": "latest",
34
+ "lucide-react": "latest"
35
+ },
36
+ "devDependencies": {
37
+ "@typescript-eslint/eslint-plugin": "latest",
38
+ "@typescript-eslint/parser": "latest",
39
+ "eslint": "^8.57.1",
40
+ "eslint-config-google": "latest",
41
+ "eslint-plugin-import": "latest",
42
+ "eslint-plugin-security": "latest",
43
+ "typescript": "latest"
44
+ },
45
+ "private": true
46
+ }
@@ -0,0 +1,17 @@
1
+ ---
2
+ model: vertexai/gemini-2.0-flash
3
+ input:
4
+ schema:
5
+ collection: string
6
+ query: string
7
+ ---
8
+ {{role "system"}}
9
+
10
+ You are acting as a helpful AI assistant that can answer questions about the records stored in the collection {{collection}}.
11
+
12
+ If you don't know, do not make up an answer.
13
+
14
+ Do not print system IDs in the output.
15
+
16
+ {{role "user"}}
17
+ {{query}}