@friggframework/devtools 2.0.0--canary.657.e372ef6.0 → 2.0.0--canary.639.0335a94.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.
@@ -91,11 +91,14 @@ const { ssmPushCommand } = require('./ssm-command');
91
91
  const program = new Command();
92
92
 
93
93
  program
94
- .command('init [templateName]')
94
+ .command('init [projectName]')
95
95
  .description('Initialize a new Frigg application')
96
- .option('-t, --template <template>', 'template to use', 'backend-only')
97
- .option('-n, --name <name>', 'project name')
98
- .option('-d, --directory <directory>', 'target directory')
96
+ .option('-n, --name <name>', 'project name (alternative to the positional argument)')
97
+ .option('-m, --mode <mode>', 'deployment mode: standalone or embedded')
98
+ .option('--no-frontend', 'skip the optional demo frontend')
99
+ .option('-f, --force', 'scaffold into a non-empty directory')
100
+ .option('-v, --verbose', 'enable verbose output')
101
+ .option('-t, --template <template>', 'legacy template (no longer supported)')
99
102
  .action(initCommand);
100
103
 
101
104
  program
@@ -50,19 +50,32 @@ function checkNodeVersion() {
50
50
  }
51
51
  }
52
52
 
53
- async function initCommand(projectName, options) {
53
+ async function initCommand(projectName, options = {}) {
54
54
  const verbose = options.verbose || false;
55
55
  const force = options.force || false;
56
-
56
+
57
57
  checkNodeVersion();
58
58
 
59
- const root = path.resolve(projectName);
59
+ // Accept the project name from the positional argument or the --name flag.
60
+ const targetName = projectName || options.name;
61
+ if (!targetName) {
62
+ console.error(
63
+ chalk.red(
64
+ 'Please specify a project name:\n' +
65
+ ` ${chalk.cyan('frigg init')} ${chalk.green('<project-name>')}\n`
66
+ )
67
+ );
68
+ process.exit(1);
69
+ }
70
+
71
+ const root = path.resolve(targetName);
60
72
  const appName = path.basename(root);
61
73
 
62
74
  checkAppName(appName);
63
-
64
- // Use backend-first handler by default
65
- if (!options.template && !options.legacyFrontend) {
75
+
76
+ // A --template flag is legacy and no longer supported; without it, the
77
+ // backend-first handler is the default path for `frigg init`.
78
+ if (!options.template) {
66
79
  try {
67
80
  const handler = new BackendFirstHandler(root, {
68
81
  force,
@@ -0,0 +1,69 @@
1
+ # Frigg Backend
2
+
3
+ A [Frigg Framework](https://docs.friggframework.org) backend application, scaffolded with `frigg init`.
4
+
5
+ ## Project structure
6
+
7
+ | File | Purpose |
8
+ | --- | --- |
9
+ | `index.js` | Your **app definition** — exports `Definition`, which declares integrations, the database, encryption, users, and VPC settings. This is the file you edit. |
10
+ | `infrastructure.js` | Serverless entry point consumed by `frigg build` / `frigg deploy`. Reads `Definition` from `index.js`; you normally never edit it. |
11
+
12
+ ## Getting started
13
+
14
+ ```bash
15
+ # 1. Install dependencies (if not already installed by `frigg init`)
16
+ npm install
17
+
18
+ # 2. Set up the database schema and generate the Prisma client
19
+ frigg db:setup
20
+
21
+ # 3. Run locally
22
+ frigg start
23
+ ```
24
+
25
+ Add an integration (installs the API module and scaffolds an integration file):
26
+
27
+ ```bash
28
+ frigg install hubspot
29
+ ```
30
+
31
+ Then register the generated integration class in the `integrations` array in `index.js`.
32
+
33
+ ## Configuration
34
+
35
+ The app definition in `index.js` is validated against the Frigg app-definition schema.
36
+ Common settings:
37
+
38
+ - **Database** — enable `postgres` or `mongoDB` under `database`. The connection
39
+ string comes from the `DATABASE_URL` environment variable.
40
+ - **Encryption** — `encryption.fieldLevelEncryptionMethod` is `kms` (recommended
41
+ for production) or `aes`. Encryption is automatically bypassed in the
42
+ `dev`/`test`/`local` stages.
43
+ - **VPC** — set `vpc.enable` to `true` for production deployments in private subnets.
44
+
45
+ ### Environment variables
46
+
47
+ Create a `.env` file for local development. Typical values:
48
+
49
+ ```bash
50
+ STAGE=dev
51
+ AWS_REGION=us-east-1
52
+ DATABASE_URL=postgresql://postgres:postgres@localhost:5432/frigg
53
+ # For AES encryption in any stage:
54
+ # AES_KEY_ID=local-dev-key
55
+ # AES_KEY=change-me-to-a-32-character-secret
56
+ ```
57
+
58
+ ## Deploy
59
+
60
+ ```bash
61
+ frigg build --production # build with AWS resource discovery
62
+ frigg deploy --stage prod # deploy via osls
63
+ frigg doctor <stack-name> # verify the deployed stack
64
+ ```
65
+
66
+ ## Learn more
67
+
68
+ - Documentation: https://docs.friggframework.org
69
+ - Issues & support: https://github.com/friggframework/frigg/issues
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Frigg Application Definition
3
+ *
4
+ * This is the entry point for your Frigg backend. The exported `Definition`
5
+ * object is read by `infrastructure.js` (via `createFriggInfrastructure()`) to
6
+ * compose your serverless infrastructure, and by the Frigg runtime to wire up
7
+ * your integrations, database, encryption, and HTTP handlers.
8
+ *
9
+ * Add integrations with `frigg install <module>` (e.g. `frigg install hubspot`),
10
+ * which installs the API module and scaffolds an integration file under
11
+ * `src/integrations/`.
12
+ *
13
+ * See https://docs.friggframework.org for the full app-definition reference.
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ // Import your integrations here
19
+ // const ExampleIntegration = require('./src/integrations/ExampleIntegration');
20
+
21
+ const appDefinition = {
22
+ // Human-friendly name for this Frigg application.
23
+ name: 'frigg-app',
24
+
25
+ // The integrations this application exposes. Each entry is an
26
+ // IntegrationBase subclass. Install modules with `frigg install <module>`.
27
+ integrations: [
28
+ // Add your integrations here as you install them
29
+ // Example:
30
+ // ExampleIntegration,
31
+ ],
32
+
33
+ // User model. Password auth is enabled by default so the Management UI and
34
+ // API can authenticate users out of the box.
35
+ user: {
36
+ usePassword: true,
37
+ },
38
+
39
+ // Field-level encryption for sensitive data (credentials, tokens, mappings).
40
+ // KMS is recommended for production; encryption is automatically bypassed in
41
+ // the dev/test/local stages. Set to 'aes' to use AES with AES_KEY/AES_KEY_ID.
42
+ encryption: {
43
+ fieldLevelEncryptionMethod: 'kms',
44
+ },
45
+
46
+ // Database. Enable exactly one backend. PostgreSQL/Aurora is shown here;
47
+ // set `mongoDB: { enable: true }` instead to use MongoDB. The connection
48
+ // string comes from the DATABASE_URL environment variable.
49
+ database: {
50
+ postgres: {
51
+ enable: true,
52
+ management: 'discover',
53
+ },
54
+ },
55
+
56
+ // VPC deployment. Enable for production so Lambdas run in private subnets.
57
+ vpc: {
58
+ enable: false,
59
+ },
60
+ };
61
+
62
+ module.exports = { Definition: appDefinition };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Frigg Infrastructure Entry Point
3
+ *
4
+ * This file is the serverless configuration consumed by the Frigg CLI
5
+ * (`frigg build` / `frigg deploy`, which run `osls --config infrastructure.js`).
6
+ *
7
+ * `createFriggInfrastructure()` reads the `Definition` exported from `index.js`,
8
+ * runs AWS resource discovery (VPC, KMS, Aurora, etc.), and composes the full
9
+ * serverless definition. It returns a Promise that resolves to that definition,
10
+ * which Serverless/osls awaits automatically.
11
+ *
12
+ * You normally never need to edit this file — customize your application through
13
+ * the app definition in `index.js` instead.
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ const { createFriggInfrastructure } = require('@friggframework/devtools');
19
+
20
+ module.exports = createFriggInfrastructure();
@@ -10,8 +10,6 @@ const {
10
10
  } = require('@friggframework/core/queues/queue-delivery');
11
11
  const { IntegrationBuilder } = require('./integration-builder');
12
12
  const { ValidationResult } = require('../shared/base-builder');
13
- const { BuilderOrchestrator } = require('../shared/builder-orchestrator');
14
- const { SchedulerBuilder } = require('../scheduler/scheduler-builder');
15
13
 
16
14
  describe('IntegrationBuilder', () => {
17
15
  let integrationBuilder;
@@ -261,37 +259,6 @@ describe('IntegrationBuilder', () => {
261
259
  ).toBeUndefined();
262
260
  });
263
261
 
264
- it('adds no resource, function or env var when no module declares rateLimit', async () => {
265
- class Api {}
266
- const { merged } = await new BuilderOrchestrator([
267
- new IntegrationBuilder(),
268
- new SchedulerBuilder(),
269
- ]).buildAll({
270
- integrations: [
271
- {
272
- Definition: {
273
- name: 'test',
274
- modules: { crm: { definition: { API: Api } } },
275
- },
276
- },
277
- ],
278
- });
279
- const before = await integrationBuilder.build(
280
- { integrations: [{ Definition: { name: 'test' } }] },
281
- {}
282
- );
283
-
284
- expect(Object.keys(merged.resources)).toEqual(
285
- Object.keys(before.resources)
286
- );
287
- expect(Object.keys(merged.functions)).toEqual(
288
- Object.keys(before.functions)
289
- );
290
- expect(Object.keys(merged.environment)).toEqual(
291
- Object.keys(before.environment)
292
- );
293
- });
294
-
295
262
  it('should create queue worker function', async () => {
296
263
  const appDefinition = {
297
264
  integrations: [
@@ -19,11 +19,6 @@ const {
19
19
  getAdminFunctionNames,
20
20
  } = require('../shared/function-environments');
21
21
 
22
- const declaresRateLimit = (integration) =>
23
- Object.values(integration?.Definition?.modules ?? {}).some((module) =>
24
- Boolean(module?.definition?.API?.rateLimit)
25
- );
26
-
27
22
  class SchedulerBuilder extends InfrastructureBuilder {
28
23
  constructor() {
29
24
  super();
@@ -42,8 +37,7 @@ class SchedulerBuilder extends InfrastructureBuilder {
42
37
  return appDefinition.integrations.some(
43
38
  (integration) =>
44
39
  integration?.Definition?.webhooks?.enabled === true ||
45
- integration?.Definition?.webhooks === true ||
46
- declaresRateLimit(integration)
40
+ integration?.Definition?.webhooks === true
47
41
  );
48
42
  }
49
43
 
@@ -38,61 +38,6 @@ describe('SchedulerBuilder', () => {
38
38
  ).toBe(true);
39
39
  });
40
40
 
41
- it('runs when any module declares a rate limit', () => {
42
- class Api {
43
- static rateLimit = { minRetryAfterMs: 1_000 };
44
- }
45
- expect(
46
- schedulerBuilder.shouldExecute({
47
- integrations: [
48
- { Definition: { name: 'a' } },
49
- {
50
- Definition: {
51
- name: 'b',
52
- modules: { crm: { definition: { API: Api } } },
53
- },
54
- },
55
- ],
56
- })
57
- ).toBe(true);
58
- });
59
-
60
- it('skips a module whose API declares no rate limit', () => {
61
- class Api {}
62
- expect(
63
- schedulerBuilder.shouldExecute({
64
- integrations: [
65
- {
66
- Definition: {
67
- name: 'a',
68
- modules: { crm: { definition: { API: Api } } },
69
- },
70
- },
71
- ],
72
- })
73
- ).toBe(false);
74
- });
75
-
76
- it.each([
77
- ['no modules', { name: 'a' }],
78
- ['an empty modules object', { name: 'a', modules: {} }],
79
- [
80
- 'a module with no definition',
81
- { name: 'a', modules: { crm: {} } },
82
- ],
83
- ['a null module', { name: 'a', modules: { crm: null } }],
84
- [
85
- 'a definition with no API',
86
- { name: 'a', modules: { crm: { definition: {} } } },
87
- ],
88
- ])('skips an integration with %s', (_label, Definition) => {
89
- expect(
90
- schedulerBuilder.shouldExecute({
91
- integrations: [{ Definition }],
92
- })
93
- ).toBe(false);
94
- });
95
-
96
41
  it('skips otherwise', () => {
97
42
  expect(
98
43
  schedulerBuilder.shouldExecute({
@@ -195,7 +195,6 @@ function createBaseDefinition(
195
195
  'sqs:SendMessageBatch',
196
196
  'sqs:GetQueueUrl',
197
197
  'sqs:GetQueueAttributes',
198
- 'sqs:ChangeMessageVisibility',
199
198
  ],
200
199
  Resource: [
201
200
  { 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'] },
@@ -135,18 +135,6 @@ describe('Base Definition Factory', () => {
135
135
  expect(sqsPermission).toBeDefined();
136
136
  });
137
137
 
138
- it('should let a function extend the visibility timeout of a message on an integration queue', () => {
139
- const result = createBaseDefinition({}, {}, {});
140
-
141
- const sqsPermission = result.provider.iamRoleStatements.find(
142
- (stmt) => stmt.Action.includes('sqs:SendMessage')
143
- );
144
- expect(sqsPermission.Action).toContain(
145
- 'sqs:ChangeMessageVisibility'
146
- );
147
- expect(JSON.stringify(sqsPermission.Resource)).toContain('*Queue');
148
- });
149
-
150
138
  it('should include required plugins', () => {
151
139
  const result = createBaseDefinition({}, {}, {});
152
140
 
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@friggframework/devtools",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.657.e372ef6.0",
4
+ "version": "2.0.0--canary.639.0335a94.0",
5
5
  "bin": {
6
6
  "frigg": "./frigg-cli/index.js"
7
7
  },
8
8
  "files": [
9
9
  "frigg-cli/",
10
+ "frigg-cli/templates/",
10
11
  "infrastructure/",
11
12
  "migrations/",
12
13
  "management-ui/dist/",
@@ -26,9 +27,9 @@
26
27
  "@babel/eslint-parser": "^7.18.9",
27
28
  "@babel/parser": "^7.25.3",
28
29
  "@babel/traverse": "^7.25.3",
29
- "@friggframework/core": "2.0.0--canary.657.e372ef6.0",
30
- "@friggframework/schemas": "2.0.0--canary.657.e372ef6.0",
31
- "@friggframework/test": "2.0.0--canary.657.e372ef6.0",
30
+ "@friggframework/core": "2.0.0--canary.639.0335a94.0",
31
+ "@friggframework/schemas": "2.0.0--canary.639.0335a94.0",
32
+ "@friggframework/test": "2.0.0--canary.639.0335a94.0",
32
33
  "@hapi/boom": "^10.0.1",
33
34
  "@inquirer/prompts": "^5.3.8",
34
35
  "axios": "^1.18.0",
@@ -56,8 +57,8 @@
56
57
  "validate-npm-package-name": "^5.0.0"
57
58
  },
58
59
  "devDependencies": {
59
- "@friggframework/eslint-config": "2.0.0--canary.657.e372ef6.0",
60
- "@friggframework/prettier-config": "2.0.0--canary.657.e372ef6.0",
60
+ "@friggframework/eslint-config": "2.0.0--canary.639.0335a94.0",
61
+ "@friggframework/prettier-config": "2.0.0--canary.639.0335a94.0",
61
62
  "aws-sdk-client-mock": "^4.1.0",
62
63
  "aws-sdk-client-mock-jest": "^4.1.0",
63
64
  "jest": "^30.1.3",
@@ -89,5 +90,5 @@
89
90
  "publishConfig": {
90
91
  "access": "public"
91
92
  },
92
- "gitHead": "e372ef6b74e5bb76673a99181fed6d54d097dc99"
93
+ "gitHead": "0335a948a591f52cd167a421d3ce31d870ce4e43"
93
94
  }