@appsemble/utils 0.21.2 → 0.22.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.
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
- # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.21.2/config/assets/logo.svg) Appsemble Utilities
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.22.0/config/assets/logo.svg) Appsemble Utilities
2
2
 
3
3
  > Internal utility functions used across multiple Appsemble projects.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@appsemble/utils)](https://www.npmjs.com/package/@appsemble/utils)
6
- [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.21.2/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.21.2)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.22.0/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.22.0)
7
7
  [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://prettier.io)
8
8
 
9
9
  ## Table of Contents
@@ -26,5 +26,5 @@ not guaranteed.
26
26
 
27
27
  ## License
28
28
 
29
- [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.21.2/LICENSE.md) ©
29
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.22.0/LICENSE.md) ©
30
30
  [Appsemble](https://appsemble.com)
@@ -72,6 +72,7 @@ export const ActionDefinition = {
72
72
  { $ref: '#/components/schemas/TeamMembersActionDefinition' },
73
73
  { $ref: '#/components/schemas/ThrowActionDefinition' },
74
74
  { $ref: '#/components/schemas/UserLoginActionDefinition' },
75
+ { $ref: '#/components/schemas/UserLogoutActionDefinition' },
75
76
  { $ref: '#/components/schemas/UserRegisterActionDefinition' },
76
77
  { $ref: '#/components/schemas/UserUpdateActionDefinition' },
77
78
  ],
@@ -1,7 +1,7 @@
1
1
  import { normalized } from '../../../constants/index.js';
2
2
  export const Asset = {
3
3
  type: 'object',
4
- description: 'The response object of an asset create call.',
4
+ description: 'The response object of an asset publish call.',
5
5
  additionalProperties: false,
6
6
  properties: {
7
7
  id: {
@@ -61,6 +61,7 @@ name of the resource and how it should behave.
61
61
  properties: {
62
62
  resource: { type: 'string' },
63
63
  create: referenceAction,
64
+ patch: referenceAction,
64
65
  update: referenceAction,
65
66
  delete: referenceAction,
66
67
  },
@@ -171,6 +172,28 @@ name of the resource and how it should behave.
171
172
  },
172
173
  },
173
174
  },
175
+ patch: {
176
+ type: 'object',
177
+ description: "Overrides for 'patch' requests.",
178
+ additionalProperties: false,
179
+ properties: {
180
+ roles,
181
+ query,
182
+ method: {
183
+ type: 'string',
184
+ default: 'PATCH',
185
+ description: 'HTTP method to use for this type of request.',
186
+ },
187
+ url: {
188
+ type: 'string',
189
+ default: '/api/apps/{appId}/{resource}/{id}',
190
+ description: 'URL to use for this type of request.',
191
+ },
192
+ hooks: {
193
+ $ref: '#/components/schemas/ResourceHooksDefinition',
194
+ },
195
+ },
196
+ },
174
197
  update: {
175
198
  type: 'object',
176
199
  description: "Overrides for 'update' requests.",
@@ -0,0 +1 @@
1
+ export declare const UserLogoutActionDefinition: import("openapi-types").OpenAPIV3.SchemaObject;
@@ -0,0 +1,14 @@
1
+ import { BaseActionDefinition } from './BaseActionDefinition.js';
2
+ import { extendJSONSchema } from './utils.js';
3
+ export const UserLogoutActionDefinition = extendJSONSchema(BaseActionDefinition, {
4
+ type: 'object',
5
+ additionalProperties: false,
6
+ required: ['type'],
7
+ properties: {
8
+ type: {
9
+ enum: ['user.logout'],
10
+ description: 'Allow the users to logout of the application.',
11
+ },
12
+ },
13
+ });
14
+ //# sourceMappingURL=UserLogoutActionDefinition.js.map
@@ -112,6 +112,7 @@ export * from './Theme.js';
112
112
  export * from './ThrowActionDefinition.js';
113
113
  export * from './User.js';
114
114
  export * from './UserEmail.js';
115
+ export * from './UserLogoutActionDefinition.js';
115
116
  export * from './UserLoginActionDefinition.js';
116
117
  export * from './UserRegisterActionDefinition.js';
117
118
  export * from './UserUpdateActionDefinition.js';
@@ -112,6 +112,7 @@ export * from './Theme.js';
112
112
  export * from './ThrowActionDefinition.js';
113
113
  export * from './User.js';
114
114
  export * from './UserEmail.js';
115
+ export * from './UserLogoutActionDefinition.js';
115
116
  export * from './UserLoginActionDefinition.js';
116
117
  export * from './UserRegisterActionDefinition.js';
117
118
  export * from './UserUpdateActionDefinition.js';
@@ -11,6 +11,7 @@ export const cli = {
11
11
  scopes: {
12
12
  'apps:write': 'Create and update apps',
13
13
  'blocks:write': 'Register and update blocks, and publish new block versions.',
14
+ 'blocks:delete': 'Delete specific block versions.',
14
15
  'organizations:write': 'Create and manage organizations.',
15
16
  'resources:read': 'Read app resources on behalf of a user.',
16
17
  'resources:write': 'Modify app resources on behalf of a user.',
@@ -0,0 +1,2 @@
1
+ import { type OpenAPIV3 } from 'openapi-types';
2
+ export declare const paths: OpenAPIV3.PathsObject;
@@ -0,0 +1,38 @@
1
+ export const paths = {
2
+ '/api/apps/{appId}/quotas/email': {
3
+ get: {
4
+ tags: ['app'],
5
+ operationId: 'getAppEmailQuota',
6
+ parameters: [{ $ref: '#/components/parameters/appId' }],
7
+ security: [{ studio: [] }, {}],
8
+ responses: {
9
+ 200: {
10
+ description: 'Email quota for an app',
11
+ content: {
12
+ 'application/json': {
13
+ schema: {
14
+ type: 'object',
15
+ properties: {
16
+ used: {
17
+ type: 'number',
18
+ description: 'Number of emails sent today',
19
+ },
20
+ limit: {
21
+ type: 'number',
22
+ description: 'Maximum number of emails that can be sent today',
23
+ },
24
+ reset: {
25
+ type: 'string',
26
+ format: 'date-time',
27
+ description: 'Date and time when the quota resets',
28
+ },
29
+ },
30
+ },
31
+ },
32
+ },
33
+ },
34
+ },
35
+ },
36
+ },
37
+ };
38
+ //# sourceMappingURL=appQuotas.js.map
@@ -102,6 +102,17 @@ export const paths = {
102
102
  },
103
103
  },
104
104
  },
105
+ delete: {
106
+ tags: ['block', 'delete'],
107
+ description: 'Delete a single block version.',
108
+ operationId: 'removeBlockVersion',
109
+ responses: {
110
+ 204: {
111
+ description: 'Block version has successfully been deleted',
112
+ },
113
+ },
114
+ security: [{ cli: ['blocks:delete'] }],
115
+ },
105
116
  },
106
117
  '/api/blocks/@{organizationId}/{blockId}/versions/{blockVersion}/asset': {
107
118
  parameters: [
@@ -1,6 +1,7 @@
1
1
  import { paths as action } from './action.js';
2
2
  import { paths as translations } from './appMessages.js';
3
3
  import { paths as appOAuth2Secrets } from './appOAuth2Secrets.js';
4
+ import { paths as appQuotas } from './appQuotas.js';
4
5
  import { paths as apps } from './apps.js';
5
6
  import { paths as appSamlSecrets } from './appSamlSecrets.js';
6
7
  import { paths as scimEndpoints } from './appScimEndpoints.js';
@@ -30,6 +31,7 @@ export const paths = {
30
31
  ...scimEndpoints,
31
32
  ...appsembleMessages,
32
33
  ...appSSLSecrets,
34
+ ...appQuotas,
33
35
  ...assets,
34
36
  ...blocks,
35
37
  ...emails,
@@ -125,6 +125,17 @@ export const paths = {
125
125
  },
126
126
  security: [{ studio: [] }, { cli: ['organizations:write'] }],
127
127
  },
128
+ delete: {
129
+ tags: ['organization'],
130
+ description: 'Delete an organization.',
131
+ operationId: 'deleteOrganization',
132
+ responses: {
133
+ 200: {
134
+ description: 'successfully deleted organization',
135
+ },
136
+ },
137
+ security: [{ studio: [] }, {}],
138
+ },
128
139
  },
129
140
  '/api/organizations/{organizationId}/icon': {
130
141
  parameters: [{ $ref: '#/components/parameters/organizationId' }],
package/api/paths/user.js CHANGED
@@ -476,5 +476,44 @@ export const paths = {
476
476
  },
477
477
  },
478
478
  },
479
+ '/api/subscribed': {
480
+ get: {
481
+ tags: ['user'],
482
+ description: 'Get a list of active and verified users subscribed to the appsemble newsletter',
483
+ operationId: 'getSubscribedUsers',
484
+ responses: {
485
+ 200: { description: 'List of subscribed users' },
486
+ 401: { description: 'Invalid or missing admin API secret' },
487
+ },
488
+ },
489
+ },
490
+ '/api/unsubscribe': {
491
+ post: {
492
+ tags: ['user'],
493
+ description: 'Unsubscribe a user from the newsletter',
494
+ operationId: 'unsubscribe',
495
+ responses: {
496
+ 201: { description: 'Unsubscribed successfully' },
497
+ 401: { description: 'Invalid or missing admin API secret' },
498
+ },
499
+ requestBody: {
500
+ required: true,
501
+ content: {
502
+ 'application/json': {
503
+ schema: {
504
+ type: 'object',
505
+ required: ['email'],
506
+ properties: {
507
+ email: {
508
+ type: 'string',
509
+ format: 'email',
510
+ },
511
+ },
512
+ },
513
+ },
514
+ },
515
+ },
516
+ },
517
+ },
479
518
  };
480
519
  //# sourceMappingURL=user.js.map
@@ -26,53 +26,61 @@ export declare enum Permission {
26
26
  * The permission to edit the name and logo of an organization.
27
27
  */
28
28
  EditOrganization = 5,
29
+ /**
30
+ * The permission to delete an organization if it doesn't have any apps.
31
+ */
32
+ DeleteOrganization = 6,
29
33
  /**
30
34
  * The permission to invite new members into an organization,
31
35
  * removing existing invites, and resending invites.
32
36
  */
33
- InviteMember = 6,
37
+ InviteMember = 7,
34
38
  /**
35
39
  * The permission to create and delete assets.
36
40
  */
37
- ManageAssets = 7,
41
+ ManageAssets = 8,
38
42
  /**
39
43
  * The permission to remove organization members.
40
44
  */
41
- ManageMembers = 8,
45
+ ManageMembers = 9,
42
46
  /**
43
47
  * The permission to create, edit, and delete resources.
44
48
  */
45
- ManageResources = 9,
49
+ ManageResources = 10,
46
50
  /**
47
51
  * The permission to change the roles of organization members.
48
52
  */
49
- ManageRoles = 10,
53
+ ManageRoles = 11,
50
54
  /**
51
55
  * The permission to create and delete teams and manage its members.
52
56
  */
53
- ManageTeams = 11,
57
+ ManageTeams = 12,
54
58
  /**
55
59
  * The permission to publish blocks for an organization.
56
60
  */
57
- PublishBlocks = 12,
61
+ PublishBlocks = 13,
62
+ /**
63
+ * The permission to delete blocks for an organization.
64
+ */
65
+ DeleteBlocks = 14,
58
66
  /**
59
67
  * The permission to send manual push notifications for an app.
60
68
  */
61
- PushNotifications = 13,
69
+ PushNotifications = 15,
62
70
  /**
63
71
  * The permission to read assets.
64
72
  */
65
- ReadAssets = 14,
73
+ ReadAssets = 16,
66
74
  /**
67
75
  * The permission to read resources.
68
76
  */
69
- ReadResources = 15,
77
+ ReadResources = 17,
70
78
  /**
71
79
  * The permission to view private apps of an organization.
72
80
  */
73
- ViewApps = 16,
81
+ ViewApps = 18,
74
82
  /**
75
83
  * The permission to view the list of members in an organization.
76
84
  */
77
- ViewMembers = 17
85
+ ViewMembers = 19
78
86
  }
@@ -27,54 +27,62 @@ export var Permission;
27
27
  * The permission to edit the name and logo of an organization.
28
28
  */
29
29
  Permission[Permission["EditOrganization"] = 5] = "EditOrganization";
30
+ /**
31
+ * The permission to delete an organization if it doesn't have any apps.
32
+ */
33
+ Permission[Permission["DeleteOrganization"] = 6] = "DeleteOrganization";
30
34
  /**
31
35
  * The permission to invite new members into an organization,
32
36
  * removing existing invites, and resending invites.
33
37
  */
34
- Permission[Permission["InviteMember"] = 6] = "InviteMember";
38
+ Permission[Permission["InviteMember"] = 7] = "InviteMember";
35
39
  /**
36
40
  * The permission to create and delete assets.
37
41
  */
38
- Permission[Permission["ManageAssets"] = 7] = "ManageAssets";
42
+ Permission[Permission["ManageAssets"] = 8] = "ManageAssets";
39
43
  /**
40
44
  * The permission to remove organization members.
41
45
  */
42
- Permission[Permission["ManageMembers"] = 8] = "ManageMembers";
46
+ Permission[Permission["ManageMembers"] = 9] = "ManageMembers";
43
47
  /**
44
48
  * The permission to create, edit, and delete resources.
45
49
  */
46
- Permission[Permission["ManageResources"] = 9] = "ManageResources";
50
+ Permission[Permission["ManageResources"] = 10] = "ManageResources";
47
51
  /**
48
52
  * The permission to change the roles of organization members.
49
53
  */
50
- Permission[Permission["ManageRoles"] = 10] = "ManageRoles";
54
+ Permission[Permission["ManageRoles"] = 11] = "ManageRoles";
51
55
  /**
52
56
  * The permission to create and delete teams and manage its members.
53
57
  */
54
- Permission[Permission["ManageTeams"] = 11] = "ManageTeams";
58
+ Permission[Permission["ManageTeams"] = 12] = "ManageTeams";
55
59
  /**
56
60
  * The permission to publish blocks for an organization.
57
61
  */
58
- Permission[Permission["PublishBlocks"] = 12] = "PublishBlocks";
62
+ Permission[Permission["PublishBlocks"] = 13] = "PublishBlocks";
63
+ /**
64
+ * The permission to delete blocks for an organization.
65
+ */
66
+ Permission[Permission["DeleteBlocks"] = 14] = "DeleteBlocks";
59
67
  /**
60
68
  * The permission to send manual push notifications for an app.
61
69
  */
62
- Permission[Permission["PushNotifications"] = 13] = "PushNotifications";
70
+ Permission[Permission["PushNotifications"] = 15] = "PushNotifications";
63
71
  /**
64
72
  * The permission to read assets.
65
73
  */
66
- Permission[Permission["ReadAssets"] = 14] = "ReadAssets";
74
+ Permission[Permission["ReadAssets"] = 16] = "ReadAssets";
67
75
  /**
68
76
  * The permission to read resources.
69
77
  */
70
- Permission[Permission["ReadResources"] = 15] = "ReadResources";
78
+ Permission[Permission["ReadResources"] = 17] = "ReadResources";
71
79
  /**
72
80
  * The permission to view private apps of an organization.
73
81
  */
74
- Permission[Permission["ViewApps"] = 16] = "ViewApps";
82
+ Permission[Permission["ViewApps"] = 18] = "ViewApps";
75
83
  /**
76
84
  * The permission to view the list of members in an organization.
77
85
  */
78
- Permission[Permission["ViewMembers"] = 17] = "ViewMembers";
86
+ Permission[Permission["ViewMembers"] = 19] = "ViewMembers";
79
87
  })(Permission || (Permission = {}));
80
88
  //# sourceMappingURL=Permission.js.map
@@ -21,10 +21,12 @@ const Maintainer = [
21
21
  Permission.InviteMember,
22
22
  Permission.ManageTeams,
23
23
  Permission.PublishBlocks,
24
+ Permission.DeleteBlocks,
24
25
  ];
25
26
  const Owner = [
26
27
  ...Maintainer,
27
28
  Permission.EditOrganization,
29
+ Permission.DeleteOrganization,
28
30
  Permission.ManageMembers,
29
31
  Permission.ManageRoles,
30
32
  ];
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * All known OAuth2 scopes for client credentials.
3
3
  */
4
- export declare const scopes: readonly ["apps:write", "blocks:write", "organizations:write", "resources:read", "resources:write", "assets:write", "teams:read", "teams:write"];
4
+ export declare const scopes: readonly ["apps:write", "blocks:write", "blocks:delete", "organizations:write", "resources:read", "resources:write", "assets:write", "teams:read", "teams:write"];
@@ -4,6 +4,7 @@
4
4
  export const scopes = [
5
5
  'apps:write',
6
6
  'blocks:write',
7
+ 'blocks:delete',
7
8
  'organizations:write',
8
9
  'resources:read',
9
10
  'resources:write',
@@ -4,6 +4,7 @@ export function formatRequestAction({ method = 'GET', query, ...action }, data,
4
4
  url: String(remap(action.url, data, context)),
5
5
  headers: {},
6
6
  params: remap(query, data, context),
7
+ responseType: 'arraybuffer',
7
8
  };
8
9
  }
9
10
  //# sourceMappingURL=formatRequestAction.js.map
package/index.d.ts CHANGED
@@ -23,5 +23,6 @@ export * from './string.js';
23
23
  export * from './theme.js';
24
24
  export * from './langmap.js';
25
25
  export * from './i18n.js';
26
+ export * from './serverActions.js';
26
27
  export * from './validation.js';
27
28
  export * from './convertToCsv.js';
package/index.js CHANGED
@@ -23,6 +23,7 @@ export * from './string.js';
23
23
  export * from './theme.js';
24
24
  export * from './langmap.js';
25
25
  export * from './i18n.js';
26
+ export * from './serverActions.js';
26
27
  export * from './validation.js';
27
28
  export * from './convertToCsv.js';
28
29
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appsemble/utils",
3
- "version": "0.21.2",
3
+ "version": "0.22.0",
4
4
  "description": "Utility functions used in Appsemble internally",
5
5
  "keywords": [
6
6
  "app",
@@ -21,6 +21,12 @@
21
21
  "author": "Appsemble <info@appsemble.com> (https://appsemble.com)",
22
22
  "sideEffects": false,
23
23
  "type": "module",
24
+ "exports": {
25
+ ".": [
26
+ "./index.js",
27
+ "./index.ts"
28
+ ]
29
+ },
24
30
  "files": [
25
31
  "**/*.d.ts",
26
32
  "**/*.js",
@@ -31,7 +37,7 @@
31
37
  "test": "vitest"
32
38
  },
33
39
  "dependencies": {
34
- "@appsemble/types": "0.21.2",
40
+ "@appsemble/types": "0.22.0",
35
41
  "axios": "^1.0.0",
36
42
  "cron-parser": "^4.0.0",
37
43
  "date-fns": "^2.0.0",
@@ -3,7 +3,28 @@ export const conditionalRemappers = {
3
3
  type: 'object',
4
4
  description: `Check if condition results in a truthy value.
5
5
 
6
- Returns value of then if condition is truthy, otherwise it returns the value of else.
6
+ Returns value of \`then\` if condition is truthy, otherwise it returns the value of \`else\`.
7
+
8
+ For example:
9
+
10
+ \`\`\`yaml
11
+ if:
12
+ condition: { equals: [{ prop: inputValue }, 4] }
13
+ then:
14
+ static: You guessed right!
15
+ else:
16
+ static: You guessed wrong!
17
+ \`\`\`
18
+
19
+ If the \`inputValue\` is \`4\`, it goes to the \`then\` remapper and returns:
20
+ \`\`\`
21
+ You guessed right!
22
+ \`\`\`
23
+
24
+ If the \`inputValue\` is something other than \`4\`, it goes to the \`else\` remapper and returns:
25
+ \`\`\`
26
+ You guessed wrong!
27
+ \`\`\`
7
28
  `,
8
29
  additionalProperties: false,
9
30
  required: ['condition', 'then', 'else'],
@@ -30,13 +51,35 @@ Returns value of then if condition is truthy, otherwise it returns the value of
30
51
  description: `Compare all computed remapper values against each other.
31
52
 
32
53
  Returns \`true\` if all entries are equal, otherwise \`false\`.
54
+
55
+ In the following example, if the \`inputValue\` and \`expectedValue\` are of the same value, the
56
+ condition will return \`true\` and the \`then\` remapper will fire.
57
+
58
+ \`\`\`yaml
59
+ condition:
60
+ equals:
61
+ - prop: inputValue
62
+ - prop: expectedValue
63
+ \`\`\`
33
64
  `,
34
65
  },
35
66
  gt: {
36
67
  type: 'array',
37
- description: `Compare the first computed remapper value with the second computed remapper value.
68
+ description: `**(gt = Greater than)**
69
+
70
+ Compare the first computed remapper value with the second computed remapper value.
71
+
72
+ Returns \`true\` if the first entry is greater than the second entry.
73
+
74
+ For example, if \`stock\` is more than 5 here, it returns \`true\`.
38
75
 
39
- Returns \`true\` if the first entry is greater than the second entry.`,
76
+ \`\`\`yaml
77
+ condition:
78
+ gt:
79
+ - prop: stock
80
+ - 5
81
+ \`\`\`
82
+ `,
40
83
  minItems: 2,
41
84
  maxItems: 2,
42
85
  items: {
@@ -45,9 +88,21 @@ Returns \`true\` if the first entry is greater than the second entry.`,
45
88
  },
46
89
  lt: {
47
90
  type: 'array',
48
- description: `Compare the first computed remapper value with the second computed remapper value.
91
+ description: `**(lt = Lesser than)
92
+
93
+ Compare the first computed remapper value with the second computed remapper value.
94
+
95
+ Returns \`true\` if the first entry is lesser than the second entry.
49
96
 
50
- Returns \`true\` if the first entry is lesser than the second entry.`,
97
+ For example, if \`stock\` is less than 5 here, it returns \`true\`.
98
+
99
+ \`\`\`yaml
100
+ condition:
101
+ lt:
102
+ - prop: stock
103
+ - 5
104
+ \`\`\`
105
+ `,
51
106
  minItems: 2,
52
107
  maxItems: 2,
53
108
  items: {
@@ -64,6 +119,15 @@ Returns \`true\` if the first entry is lesser than the second entry.`,
64
119
  Returns \`false\` if all entries are equal to the first entry, otherwise \`true\`.
65
120
 
66
121
  If only one remapper or none is passed, the remapper value gets computed and then inverted.
122
+
123
+ If \`number\` in the following example is something other than 4, the condition returns \`true\`.
124
+
125
+ \`\`\`yaml
126
+ condition:
127
+ not:
128
+ - prop: number
129
+ - 4
130
+ \`\`\`
67
131
  `,
68
132
  },
69
133
  match: {
@@ -71,6 +135,21 @@ If only one remapper or none is passed, the remapper value gets computed and the
71
135
  description: `Check if any case results in a truthy value.
72
136
 
73
137
  Returns the value of the first case where the condition equals true, otherwise returns null.
138
+
139
+ In the following example, let's say the \`Gem\` is a "Ruby". The match remapper then returns
140
+ \`value: 75\`.
141
+
142
+ \`\`\`yaml
143
+ match:
144
+ - case: { equals: [{ prop: Gem }, Diamond] }
145
+ value: 100
146
+ - case: { equals: [{ prop: Gem }, Ruby] }
147
+ value: 75
148
+ - case: { equals: [{ prop: Gem }, Gold] }
149
+ value: 50
150
+ - case: { equals: [{ prop: Gem }, Sapphire] }
151
+ value: 25
152
+ \`\`\`
74
153
  `,
75
154
  items: {
76
155
  type: 'object',
@@ -4,6 +4,40 @@ export const dataRemappers = {
4
4
  description: `Get the current array.map’s index or length.
5
5
 
6
6
  Returns nothing when not in the context of \`array.map’s\`.
7
+
8
+ For example:
9
+
10
+ Input:
11
+ \`\`\`json
12
+ ["a", "b", "c"]
13
+ \`\`\`
14
+
15
+ This remapper definition maps through the input array and creates an object with the length of the
16
+ array and the current index of the loop:
17
+ \`\`\`yaml
18
+ array.map:
19
+ object.from:
20
+ length: { array: length }
21
+ index: { array: index }
22
+ \`\`\`
23
+
24
+ Result:
25
+ \`\`\`json
26
+ [
27
+ {
28
+ "index": 0,
29
+ "length": 3
30
+ },
31
+ {
32
+ "index": 1,
33
+ "length": 3
34
+ },
35
+ {
36
+ "index": 2,
37
+ "length": 3
38
+ }
39
+ ]
40
+ \`\`\`
7
41
  `,
8
42
  },
9
43
  app: {
@@ -260,7 +294,18 @@ Result:
260
294
  `,
261
295
  },
262
296
  static: {
263
- description: 'Use a static value.',
297
+ description: `Create a static value
298
+
299
+ \`\`\`yaml
300
+ static: Hello!
301
+ \`\`\`
302
+
303
+ Returns the following string:
304
+
305
+ \`\`\`
306
+ Hello!
307
+ \`\`\`
308
+ `,
264
309
  },
265
310
  translate: {
266
311
  type: 'string',
@@ -1,15 +1,101 @@
1
1
  export const dateRemappers = {
2
2
  'date.add': {
3
3
  type: 'string',
4
- description: 'Add the specified value to a given date.',
4
+ description: `Adds a specified date value to the provided date.
5
+
6
+ The value to add should be specified according to the
7
+ [parse-duration](https://www.npmjs.com/package/parse-duration) API. If you want to add a day to a
8
+ date for example, the syntax would be \`date.add: 1d\`.
9
+
10
+ Full list of supported unit types:
11
+ - nanoseconds (ns)
12
+ - microseconds (μs)
13
+ - milliseconds (ms)
14
+ - seconds (s, sec)
15
+ - minutes (m, min)
16
+ - hours (h, hr)
17
+ - days (d)
18
+ - weeks (w, wk)
19
+ - months
20
+ - years (y, yr)
21
+
22
+ For example:
23
+
24
+ Date now:
25
+ \`\`\`json
26
+ 2023-06-30T14:50:19.601Z
27
+ \`\`\`
28
+
29
+ Remapper definition:
30
+ \`\`\`yaml
31
+ [{ date.now: null }, { date.add: 1w } , { date.format: null }]
32
+ \`\`\`
33
+
34
+ Result:
35
+ \`\`\`json
36
+ 2023-07-07T14:50:19.601Z
37
+ \`\`\`
38
+
39
+ `,
5
40
  },
6
41
  'date.format': {
7
- enum: [null],
8
- description: 'Format a date according to rfc3339.',
42
+ enum: ['string', null],
43
+ description: `Format a date according to the RFC3339 format.
44
+
45
+ Here is an example of a RFC3339 complicit date:
46
+ \`2002-10-02T15:00:00Z\`
47
+
48
+ In an app definition, it’s best to use this when you want to display a date in a specific format.
49
+ For example, if your app has a form with a Datepicker field the incoming data will be formatted
50
+ as a simple date format. If you want to format it to the RFC3339 format, you can use this remapper.
51
+
52
+ When you submit a form with a DateField, the internal output looks like this:
53
+
54
+ \`\`\`js
55
+ 2023-07-03
56
+ \`\`\`
57
+
58
+ You can then format the date so that it uses the RFC3339 format.
59
+
60
+ \`\`\`yaml
61
+ date.format: null
62
+ \`\`\`
63
+
64
+ Result:
65
+ \`\`\`js
66
+ "2023-07-02T22:00:00.000Z"
67
+ \`\`\`
68
+
69
+ The remapper can also be used to format a date or timestamp using a custom format.
70
+
71
+ \`\`\`js
72
+ "2023-07-02T22:00:00.000Z"
73
+ \`\`\`
74
+
75
+ You can then format the date with any supported pattern, please refer to https://date-fns.org/docs/format for the supported patterns.
76
+
77
+ \`\`\`yaml
78
+ date.format: yyyy-MM-dd
79
+ \`\`\`
80
+
81
+ Result:
82
+ \`\`\`js
83
+ 2023-07-03
84
+ \`\`\`
85
+ `,
9
86
  },
10
87
  'date.now': {
11
88
  enum: [null],
12
- description: 'Returns the current date.',
89
+ description: `Returns the current date as a JavaScript Date object.
90
+ \`\`\`yaml
91
+ date.now: null
92
+ \`\`\`
93
+
94
+ Result:
95
+ \`\`\`js
96
+ "Mon Jul 03 2023 11:47:18 GMT+0200 (Midden-Europese zomertijd)"
97
+ \`\`\`
98
+ `,
13
99
  },
14
100
  'date.parse': {
15
101
  type: 'string',
@@ -1,7 +1,27 @@
1
1
  export const randomRemappers = {
2
2
  'random.choice': {
3
3
  enum: [null],
4
- description: 'Pick and return a random entry from an array. If the input is not an array, the input is returned as-is.',
4
+ description: `Pick and return a random entry from an array. If the input is not an array, the input is returned as-is.
5
+ For example:
6
+
7
+ If you input the following array:
8
+ \`\`\`json
9
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
10
+ \`\`\`
11
+
12
+ \`\`\`yaml
13
+ random.choice: null
14
+ \`\`\`
15
+
16
+ The result could return any one of these numbers.
17
+
18
+ You can also combine different data types in this array and have it work in the same way. If mixed in
19
+ strings, the result could be either one of the provided numbers or one of the provided strings.
20
+
21
+ \`\`\`json
22
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "Peter", "Patrick", "Michael", "Harry"]
23
+ \`\`\`
24
+ `,
5
25
  },
6
26
  'random.integer': {
7
27
  type: 'array',
@@ -10,7 +30,16 @@ export const randomRemappers = {
10
30
  items: {
11
31
  type: 'integer',
12
32
  },
13
- description: 'Pick and return a random integer between the provided lowest and highest values.',
33
+ description: `Pick and return a random integer between the provided lowest and highest values.
34
+ For example:
35
+ \`\`\`yaml
36
+ random.integer:
37
+ - 0
38
+ - 1000
39
+ \`\`\`
40
+
41
+ Returns a random integer between 0 and 1000.
42
+ `,
14
43
  },
15
44
  'random.float': {
16
45
  type: 'array',
@@ -19,7 +48,16 @@ export const randomRemappers = {
19
48
  items: {
20
49
  type: 'number',
21
50
  },
22
- description: 'Pick and return a random number between the provided lowest and highest values.',
51
+ description: `Pick and return a random float value between the provided lowest and highest values.
52
+ For example:
53
+ \`\`\`yaml
54
+ random.float:
55
+ - 0
56
+ - 1
57
+ \`\`\`
58
+
59
+ Returns a random float value between 0 and 1.
60
+ `,
23
61
  },
24
62
  'random.string': {
25
63
  type: 'object',
@@ -29,7 +67,16 @@ export const randomRemappers = {
29
67
  choice: { type: 'string', minLength: 1 },
30
68
  length: { type: 'integer', minimum: 1 },
31
69
  },
32
- description: 'Pick and return a random string from a given length using characters from a given input string.',
70
+ description: `Pick and return a random string from a given length using characters from a given input string defined in \`choice\`.
71
+ For example:
72
+ \`\`\`yaml
73
+ random.string:
74
+ choice: abcdefghijklmnopqrstuvwxyz0123456789
75
+ length: 6
76
+ \`\`\`
77
+
78
+ Returns a randomized string that is 6 characters long and consists of any characters in the \`choice\` field, like: \`g8ajss9\`.
79
+ `,
33
80
  },
34
81
  };
35
82
  //# sourceMappingURL=randoms.js.map
@@ -1,7 +1,47 @@
1
1
  export const unsortedRemappers = {
2
2
  ics: {
3
3
  type: 'object',
4
- description: 'Create a calendar event',
4
+ description: `Create a calendar event. This event can be downloaded as an \`.ics\` file and
5
+ uploaded to your agenda using the [download](../reference/action#download) action.
6
+
7
+ For example, the following input:
8
+ \`\`\`yaml
9
+ ics:
10
+ coordinates
11
+ object.from:
12
+ latitude: 38.897700545442646
13
+ longitude: -77.03655660152435
14
+ description: "Sprint planning meeting"
15
+ duration: 1d
16
+ end: 2023-07-19
17
+ location: The Oval Office.
18
+ start: 2023-07-18
19
+ title: Important Meeting
20
+ url: https://google.nl
21
+ \`\`\`
22
+
23
+ Creates the following ICS-formatted object:
24
+ \`\`\`
25
+ BEGIN:VCALENDAR
26
+ VERSION:2.0
27
+ CALSCALE:GREGORIAN
28
+ PRODID:http://remappers.appsemble.localhost:9999
29
+ METHOD:PUBLISH
30
+ X-PUBLISHED-TTL:PT1H
31
+ BEGIN:VEVENT
32
+ UID:b8TsbczhfpIxPM-3lNHQz
33
+ SUMMARY:Important Meeting
34
+ DTSTAMP:20230703T102029Z
35
+ DTSTART:20230717T220000Z
36
+ DTEND:20230718T220000Z
37
+ DESCRIPTION:Sprint planning meeting
38
+ URL:https://google.nl
39
+ GEO:38.897700545442646;-77.03655123710632
40
+ LOCATION:The Oval Office.
41
+ END:VEVENT
42
+ END:VCALENDAR
43
+ \`\`\`
44
+ `,
5
45
  additionalProperties: false,
6
46
  required: ['start', 'title'],
7
47
  properties: {
@@ -43,7 +83,51 @@ export const unsortedRemappers = {
43
83
  },
44
84
  },
45
85
  'null.strip': {
46
- description: 'Strip all null, undefined, and empty array values from an object.',
86
+ description: `Strip all null, undefined, and empty array values from an object or array.
87
+ For example, with the following input value:
88
+ \`\`\`json
89
+ [0, 4, null, null, "Peter", 0.4234, null]
90
+ \`\`\`
91
+ \`\`\`yaml
92
+ null.strip: null
93
+ \`\`\`
94
+
95
+ The null values will be removed, leaving a dense array:
96
+ \`\`\`json
97
+ [0, 4, "Peter", 0.4234]
98
+ \`\`\`
99
+
100
+ Instead of giving it \`null\` as option, you can also provide a \`depth\` property to specify how
101
+ deep to recurse into the object or array to remove null values.
102
+
103
+ For example, with the following input:
104
+ \`\`\`json
105
+ {
106
+ 0: [0, null, "Peter"],
107
+ 1: {
108
+ "array1": [4, null, 0.4234, null]
109
+ }
110
+ }
111
+ \`\`\`
112
+
113
+ You can specify to which degree of depth you want the null values to be removed.
114
+ With this remapper definition:
115
+ \`\`\`yaml
116
+ null.strip:
117
+ depth: 2
118
+ \`\`\`
119
+
120
+ It will only check two objects in for any null values. That means only the first array within the
121
+ object will be checked. The result looks like this:
122
+ \`\`\`json
123
+ {
124
+ 0: [0, "Peter"],
125
+ 1: {
126
+ "array1": [4, null, 0.4234, null]
127
+ }
128
+ }
129
+ \`\`\`
130
+ `,
47
131
  anyOf: [
48
132
  { enum: [null] },
49
133
  {
@@ -63,9 +147,110 @@ export const unsortedRemappers = {
63
147
  },
64
148
  log: {
65
149
  enum: ['info', 'warn', 'error'],
66
- description: `Logs its input data (returns it) and its context.
150
+ description: `Logs in the browser's console and returns the incoming data and the remapper function's context.
151
+
152
+ The context contains relevant info about the app, like the URL and locale, but also contains the
153
+ remapper’s history.
154
+
155
+ The options represent the level of logging that will show in the console.
67
156
 
68
- The value to set is the log level.`,
157
+ - \`input\`: The input data going into this remapper,
158
+ - \`context\`:
159
+ - \`root\`: The input data going into this remapper,
160
+ - \`appId\`: ID of the application,
161
+ - \`url\`: Absolute URL of the page where the remapper was fired,
162
+ - \`appUrl\`: Base URL of the application,
163
+ - \`pageData\`: Current page data of a FlowPage (See [page remapper](./data#page)),
164
+ - \`userInfo\`: User's information if they are logged in (See [user remapper](./data#user)),
165
+ - \`context\`:
166
+ - \`history\`: Complete list of this remapper’s history (See [history remapper](./history))
167
+ - \`history\`: Complete list of this remapper’s history (See [history remapper](./history))
168
+ - \`locale\`: The user’s locale,
169
+ - \`stepRef\`: In a loop page, gives the properties from the loop’s current data index (See [step remapper](./data#step))
170
+
171
+ For example:
172
+
173
+ \`\`\`json
174
+ {
175
+ "input": {
176
+ "name": "Peter",
177
+ "age": 49,
178
+ "birthday": "07-08-2023"
179
+ },
180
+ "context": {
181
+ "root": {
182
+ "name": "Peter",
183
+ "age": 49,
184
+ "birthday": "07-08-2023"
185
+ },
186
+ "appId": 49,
187
+ "url": "http://remappers.appsemble.localhost:9999/en/other",
188
+ "appUrl": "http://remappers.appsemble.localhost:9999",
189
+ "pageData": {
190
+ "triedAppsemble": false
191
+ },
192
+ "userInfo": {
193
+ "email": "example@hotmail.com",
194
+ "email_verified": true,
195
+ "name": "Example User 1",
196
+ "picture": "https://www.gravatar.com/avatar/f46b82357ce29bcd1099915946cda468?s=128&d=mp",
197
+ "sub": "0000-0000-0000-0000",
198
+ "locale": "en",
199
+ "zoneinfo": "Europe/Amsterdam"
200
+ },
201
+ "context": {
202
+ "history": [
203
+ [
204
+ 0,
205
+ 4,
206
+ null,
207
+ null,
208
+ "Peter",
209
+ 0.4234,
210
+ null
211
+ ],
212
+ {
213
+ "name": "Peter",
214
+ "age": 49
215
+ },
216
+ {
217
+ "name": "Peter",
218
+ "age": 49,
219
+ "birthday": "07-08-2023"
220
+ }
221
+ ]
222
+ },
223
+ "history": [
224
+ [
225
+ 0,
226
+ 4,
227
+ null,
228
+ null,
229
+ "Peter",
230
+ 0.4234,
231
+ null
232
+ ],
233
+ {
234
+ "name": "Peter",
235
+ "age": 49
236
+ },
237
+ {
238
+ "name": "Peter",
239
+ "age": 49,
240
+ "birthday": "07-08-2023"
241
+ }
242
+ ],
243
+ "locale": "en",
244
+ "stepRef": {
245
+ "current": {
246
+ "answerType": "multiple choice",
247
+ "question": "How much do you enjoy working here?"
248
+ }
249
+ }
250
+ }
251
+ }
252
+ \`\`\`
253
+ `,
69
254
  },
70
255
  };
71
256
  //# sourceMappingURL=unsorted.js.map
package/remap.js CHANGED
@@ -1,4 +1,4 @@
1
- import { addMilliseconds, parse, parseISO } from 'date-fns';
1
+ import { addMilliseconds, format, parse, parseISO } from 'date-fns';
2
2
  import equal from 'fast-deep-equal';
3
3
  import { createEvent } from 'ics';
4
4
  import parseDuration from 'parse-duration';
@@ -233,7 +233,7 @@ const mapperImplementations = {
233
233
  }
234
234
  return result;
235
235
  },
236
- 'date.parse': (format, input) => format ? parse(input, format, new Date()) : parseISO(input),
236
+ 'date.parse': (fmt, input) => (fmt ? parse(input, fmt, new Date()) : parseISO(input)),
237
237
  'date.now': () => new Date(),
238
238
  'date.add'(time, input) {
239
239
  const expireDuration = parseDuration(time);
@@ -248,7 +248,7 @@ const mapperImplementations = {
248
248
  : typeof input === 'number'
249
249
  ? new Date(input)
250
250
  : parseISO(String(input));
251
- return date.toJSON();
251
+ return args ? format(date, args) : date.toJSON();
252
252
  },
253
253
  'null.strip': (args, input) => stripNullValues(input, args || {}),
254
254
  'random.choice': (args, input) => Array.isArray(input) ? input[Math.floor(Math.random() * input.length)] : input,
package/remap.test.js CHANGED
@@ -183,6 +183,21 @@ describe('date.format', () => {
183
183
  mappers: { 'date.format': null },
184
184
  expected: '1970-01-01T00:00:00.000Z',
185
185
  },
186
+ 'format date objects to custom format': {
187
+ input: new Date('2020-01-02T03:04:05Z'),
188
+ mappers: { 'date.format': 'dd-MM-yyyy' },
189
+ expected: '02-01-2020',
190
+ },
191
+ 'format date strings to custom format': {
192
+ input: '2020-01-02T03:04:05Z',
193
+ mappers: { 'date.format': 'yyyy-MM-dd' },
194
+ expected: '2020-01-02',
195
+ },
196
+ 'format unix timestamps to custom format': {
197
+ input: 0,
198
+ mappers: { 'date.format': 'MM/dd/yyyy' },
199
+ expected: '01/01/1970',
200
+ },
186
201
  });
187
202
  });
188
203
  describe('log', () => {
package/theme.test.js CHANGED
@@ -1,4 +1,4 @@
1
- import bulmaPkg from 'bulma/package.json' assert { type: 'json' };
1
+ import bulmaPkg from 'bulma/package.json';
2
2
  import { createThemeURL, mergeThemes } from './theme.js';
3
3
  describe('mergeThemes', () => {
4
4
  it('should use the base theme as default', () => {
@@ -1,2 +0,0 @@
1
- declare const _default: import("vitest/dist/config.js").UserProjectConfigExport;
2
- export default _default;