@upstart.gg/sdk 0.0.104 → 0.0.106
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/dist/shared/ajv.d.ts +2 -0
- package/dist/shared/ajv.d.ts.map +1 -1
- package/dist/shared/ajv.js +1 -1
- package/dist/shared/attributes.js +1 -1
- package/dist/shared/brick-manifest.js +1 -1
- package/dist/shared/bricks/manifests/accordion.manifest.js +1 -1
- package/dist/shared/bricks/manifests/all-manifests.js +1 -1
- package/dist/shared/bricks/manifests/button.manifest.js +1 -1
- package/dist/shared/bricks/manifests/card.manifest.js +1 -1
- package/dist/shared/bricks/manifests/carousel.manifest.js +1 -1
- package/dist/shared/bricks/manifests/container.manifest.js +1 -1
- package/dist/shared/bricks/manifests/divider.manifest.js +1 -1
- package/dist/shared/bricks/manifests/footer.manifest.d.ts +1 -1
- package/dist/shared/bricks/manifests/footer.manifest.d.ts.map +1 -1
- package/dist/shared/bricks/manifests/footer.manifest.js +1 -1
- package/dist/shared/bricks/manifests/form.manifest.js +1 -1
- package/dist/shared/bricks/manifests/hero.manifest.js +1 -1
- package/dist/shared/bricks/manifests/icon.manifest.js +1 -1
- package/dist/shared/bricks/manifests/image.manifest.js +1 -1
- package/dist/shared/bricks/manifests/images-gallery.manifest.js +1 -1
- package/dist/shared/bricks/manifests/map.manifest.js +1 -1
- package/dist/shared/bricks/manifests/navbar.manifest.js +1 -1
- package/dist/shared/bricks/manifests/sidebar.manifest.js +1 -1
- package/dist/shared/bricks/manifests/social-links.manifest.js +1 -1
- package/dist/shared/bricks/manifests/testimonials.manifest.js +1 -1
- package/dist/shared/bricks/manifests/text.manifest.js +1 -1
- package/dist/shared/bricks/manifests/timeline.manifest.js +1 -1
- package/dist/shared/bricks/manifests/video.manifest.js +1 -1
- package/dist/shared/bricks/props/border.d.ts.map +1 -1
- package/dist/shared/bricks/props/border.js +1 -1
- package/dist/shared/bricks/props/container.js +1 -1
- package/dist/shared/bricks/props/effects.js +1 -1
- package/dist/shared/bricks.d.ts.map +1 -1
- package/dist/shared/bricks.js +1 -1
- package/dist/shared/{chunk-TCZBR3ZU.js → chunk-2DI5SIVV.js} +1 -1
- package/dist/shared/{chunk-O22VV7YR.js → chunk-33FU4KGU.js} +1 -1
- package/dist/shared/{chunk-WCNVFVDK.js → chunk-3ZGRY444.js} +1 -1
- package/dist/shared/{chunk-CUCUHPQ7.js → chunk-6OKXZL6R.js} +1 -1
- package/dist/shared/chunk-7E67XSKP.js +3 -0
- package/dist/shared/{chunk-LJQXN32B.js → chunk-AMGHA7QH.js} +1 -1
- package/dist/shared/{chunk-QALNFBY7.js → chunk-DC5DWF7B.js} +1 -1
- package/dist/shared/{chunk-I43NIQ2K.js → chunk-DY2YCYZ6.js} +1 -1
- package/dist/shared/{chunk-CEXHD4BO.js → chunk-E4UAVLKC.js} +2 -2
- package/dist/shared/{chunk-ZFTWLZ3G.js → chunk-EHH677K5.js} +1 -1
- package/dist/shared/{chunk-POYVTV5F.js → chunk-FD3KX2U7.js} +1 -1
- package/dist/shared/chunk-G3JO5DM5.js +3 -0
- package/dist/shared/{chunk-I5S2MPPR.js → chunk-H7OYUKBW.js} +1 -1
- package/dist/shared/{chunk-ATVHWZSA.js → chunk-HBM4DPIW.js} +1 -1
- package/dist/shared/chunk-HIBTEX2T.js +3 -0
- package/dist/shared/{chunk-E2EBTWJI.js → chunk-I3HSLGFA.js} +1 -1
- package/dist/shared/{chunk-UISES3HA.js → chunk-IXJX7EQ3.js} +1 -1
- package/dist/shared/{chunk-5IEGQ7YT.js → chunk-JAAPJQNK.js} +1 -1
- package/dist/shared/{chunk-UK6H3FDX.js → chunk-JDBVMPSI.js} +1 -1
- package/dist/shared/{chunk-F6MLW6DO.js → chunk-JH3NRO6M.js} +1 -1
- package/dist/shared/{chunk-ZNVRYEO7.js → chunk-L3TKLJKK.js} +1 -1
- package/dist/shared/{chunk-TEPFFY32.js → chunk-LOFXGDAK.js} +1 -1
- package/dist/shared/chunk-O3FJP65T.js +3 -0
- package/dist/shared/{chunk-7L3UOEMR.js → chunk-PX7QSNLO.js} +1 -1
- package/dist/shared/{chunk-22KRCQK5.js → chunk-U76JDFWJ.js} +1 -1
- package/dist/shared/{chunk-CW5FWW5W.js → chunk-UYZP24VV.js} +1 -1
- package/dist/shared/chunk-X42WBJTN.js +3 -0
- package/dist/shared/{chunk-OQIFFJ7I.js → chunk-XB3X4P3I.js} +1 -1
- package/dist/shared/chunk-XDCGA4WT.js +3 -0
- package/dist/shared/chunk-YGHBFXR6.js +3 -0
- package/dist/shared/{chunk-WEQRYCPD.js → chunk-ZWYLKIBI.js} +1 -1
- package/dist/shared/datasources/external/rss/fetcher.d.ts +1 -1
- package/dist/shared/datasources/external/rss/fetcher.d.ts.map +1 -1
- package/dist/shared/images.js +1 -1
- package/dist/shared/page.js +1 -1
- package/dist/shared/responsive.js +1 -1
- package/dist/shared/site.js +1 -1
- package/dist/shared/sitemap.js +1 -1
- package/dist/shared/theme.js +1 -1
- package/dist/shared/utils/schema.d.ts +6 -8
- package/dist/shared/utils/schema.d.ts.map +1 -1
- package/dist/shared/utils/schema.js +1 -1
- package/package.json +5 -9
- package/dist/shared/chunk-F63ANNAK.js +0 -3
- package/dist/shared/chunk-GPKRRX3D.js +0 -3
- package/dist/shared/chunk-HQQYIKTE.js +0 -3
- package/dist/shared/chunk-JFDOR3UH.js +0 -3
- package/dist/shared/chunk-OD2PRCLH.js +0 -3
- package/dist/shared/chunk-PK6UAFPW.js +0 -3
- package/dist/shared/chunk-VDHLON5R.js +0 -3
- package/src/node/cli/api.ts +0 -101
- package/src/node/cli/commands/cmd-build.ts +0 -64
- package/src/node/cli/commands/login/cmd-login.ts +0 -111
- package/src/node/cli/commands/logout/cmd-logout.ts +0 -11
- package/src/node/cli/commands/publish/cmd-publish.ts +0 -135
- package/src/node/cli/commands/publish/parse-gitignore.ts +0 -278
- package/src/node/cli/commands/publish/uploader.ts +0 -333
- package/src/node/cli/constants.ts +0 -14
- package/src/node/cli/is-logged-in.ts +0 -28
- package/src/node/cli/program.ts +0 -77
- package/src/node/cli/store.ts +0 -64
- package/src/node/cli/tests/api.test.ts +0 -161
- package/src/node/cli/types.ts +0 -34
- package/src/node/cli/utils.ts +0 -20
- package/src/node/shared/config.ts +0 -69
- package/src/node/shared/logger.ts +0 -44
- package/src/shared/ajv.ts +0 -103
- package/src/shared/analytics/init.ts +0 -14
- package/src/shared/analytics/track.ts +0 -21
- package/src/shared/analytics/types.ts +0 -13
- package/src/shared/attributes.ts +0 -211
- package/src/shared/brick-manifest.ts +0 -110
- package/src/shared/bricks/manifests/accordion.manifest.ts +0 -179
- package/src/shared/bricks/manifests/all-manifests.ts +0 -92
- package/src/shared/bricks/manifests/button.manifest.ts +0 -145
- package/src/shared/bricks/manifests/card.manifest.ts +0 -269
- package/src/shared/bricks/manifests/carousel.manifest.ts +0 -106
- package/src/shared/bricks/manifests/container.manifest.ts +0 -357
- package/src/shared/bricks/manifests/divider.manifest.ts +0 -121
- package/src/shared/bricks/manifests/footer.manifest.ts +0 -487
- package/src/shared/bricks/manifests/form.manifest.ts +0 -112
- package/src/shared/bricks/manifests/hero.manifest.ts +0 -132
- package/src/shared/bricks/manifests/icon.manifest.ts +0 -130
- package/src/shared/bricks/manifests/image.manifest.ts +0 -203
- package/src/shared/bricks/manifests/images-gallery.manifest.ts +0 -227
- package/src/shared/bricks/manifests/map.manifest.ts +0 -75
- package/src/shared/bricks/manifests/navbar.manifest.ts +0 -344
- package/src/shared/bricks/manifests/sidebar.manifest.ts +0 -90
- package/src/shared/bricks/manifests/social-links.manifest.ts +0 -370
- package/src/shared/bricks/manifests/testimonials.manifest.ts +0 -397
- package/src/shared/bricks/manifests/tests/header.manifest.test.ts +0 -10
- package/src/shared/bricks/manifests/text.manifest.ts +0 -164
- package/src/shared/bricks/manifests/timeline.manifest.ts +0 -456
- package/src/shared/bricks/manifests/video.manifest.ts +0 -59
- package/src/shared/bricks/props/_style-presets.ts +0 -352
- package/src/shared/bricks/props/align.ts +0 -59
- package/src/shared/bricks/props/background.ts +0 -118
- package/src/shared/bricks/props/boolean.ts +0 -11
- package/src/shared/bricks/props/border.ts +0 -84
- package/src/shared/bricks/props/color.ts +0 -24
- package/src/shared/bricks/props/common.ts +0 -37
- package/src/shared/bricks/props/container.ts +0 -356
- package/src/shared/bricks/props/css-length.ts +0 -25
- package/src/shared/bricks/props/datasource.ts +0 -60
- package/src/shared/bricks/props/date.ts +0 -24
- package/src/shared/bricks/props/effects.ts +0 -123
- package/src/shared/bricks/props/enum.ts +0 -42
- package/src/shared/bricks/props/file.ts +0 -12
- package/src/shared/bricks/props/geolocation.ts +0 -30
- package/src/shared/bricks/props/helpers.ts +0 -101
- package/src/shared/bricks/props/image.ts +0 -90
- package/src/shared/bricks/props/number.ts +0 -16
- package/src/shared/bricks/props/padding.ts +0 -21
- package/src/shared/bricks/props/position.ts +0 -27
- package/src/shared/bricks/props/preset.ts +0 -136
- package/src/shared/bricks/props/string.ts +0 -56
- package/src/shared/bricks/props/tests/align.test.ts +0 -37
- package/src/shared/bricks/props/tests/background.test.ts +0 -102
- package/src/shared/bricks/props/tests/border.test.ts +0 -38
- package/src/shared/bricks/props/tests/effects.test.ts +0 -37
- package/src/shared/bricks/props/tests/helpers.test.ts +0 -133
- package/src/shared/bricks/props/tests/image.test.ts +0 -71
- package/src/shared/bricks/props/tests/padding.ts +0 -12
- package/src/shared/bricks/props/tests/string.test.ts +0 -79
- package/src/shared/bricks/props/text.ts +0 -66
- package/src/shared/bricks/props/types.ts +0 -57
- package/src/shared/bricks.ts +0 -232
- package/src/shared/context.ts +0 -39
- package/src/shared/datarecords/external/airtable/handler.ts +0 -21
- package/src/shared/datarecords/external/airtable/options.ts +0 -22
- package/src/shared/datarecords/external/generic-webhook/handler.ts +0 -10
- package/src/shared/datarecords/external/generic-webhook/options.ts +0 -13
- package/src/shared/datarecords/external/google/oauth/config.ts +0 -30
- package/src/shared/datarecords/external/google/sheets/handler.ts +0 -26
- package/src/shared/datarecords/external/google/sheets/options.ts +0 -9
- package/src/shared/datarecords/types.ts +0 -120
- package/src/shared/datarecords.ts +0 -5
- package/src/shared/datasources/README.md +0 -3
- package/src/shared/datasources/external/facebook/posts/fetcher.ts +0 -52
- package/src/shared/datasources/external/facebook/posts/sample.ts +0 -35
- package/src/shared/datasources/external/facebook/posts/schema.ts +0 -33
- package/src/shared/datasources/external/facebook/posts/tests/fetcher.test.ts +0 -73
- package/src/shared/datasources/external/http-json/fetcher.ts +0 -28
- package/src/shared/datasources/external/http-json/options.ts +0 -12
- package/src/shared/datasources/external/http-json/schema.ts +0 -6
- package/src/shared/datasources/external/http-json/tests/fetcher.test.ts +0 -70
- package/src/shared/datasources/external/instagram/feed/fetcher.ts +0 -33
- package/src/shared/datasources/external/instagram/feed/sample.ts +0 -22
- package/src/shared/datasources/external/instagram/feed/schema.ts +0 -23
- package/src/shared/datasources/external/instagram/feed/tests/fetcher.test.ts +0 -64
- package/src/shared/datasources/external/mastodon/account/fetcher.ts +0 -24
- package/src/shared/datasources/external/mastodon/account/sample.ts +0 -33
- package/src/shared/datasources/external/mastodon/account/schema.ts +0 -45
- package/src/shared/datasources/external/mastodon/account/tests/fetcher.test.ts +0 -47
- package/src/shared/datasources/external/mastodon/options.ts +0 -11
- package/src/shared/datasources/external/mastodon/status/fetcher.ts +0 -35
- package/src/shared/datasources/external/mastodon/status/sample.array.ts +0 -59
- package/src/shared/datasources/external/mastodon/status/sample.single.ts +0 -55
- package/src/shared/datasources/external/mastodon/status/schema.ts +0 -130
- package/src/shared/datasources/external/mastodon/status/tests/fetcher.test.ts +0 -74
- package/src/shared/datasources/external/meta/oauth/config.ts +0 -16
- package/src/shared/datasources/external/meta/options.ts +0 -11
- package/src/shared/datasources/external/rss/fetcher.ts +0 -29
- package/src/shared/datasources/external/rss/options.ts +0 -11
- package/src/shared/datasources/external/rss/sample.ts +0 -22
- package/src/shared/datasources/external/rss/schema.ts +0 -42
- package/src/shared/datasources/external/threads/media/fetcher.ts +0 -53
- package/src/shared/datasources/external/threads/media/sample.ts +0 -44
- package/src/shared/datasources/external/threads/media/schema.ts +0 -37
- package/src/shared/datasources/external/tiktok/oauth/config.ts +0 -17
- package/src/shared/datasources/external/tiktok/video/fetcher.ts +0 -39
- package/src/shared/datasources/external/tiktok/video/options.ts +0 -12
- package/src/shared/datasources/external/tiktok/video/sample.ts +0 -26
- package/src/shared/datasources/external/tiktok/video/schema.ts +0 -27
- package/src/shared/datasources/external/youtube/list/fetcher.ts +0 -37
- package/src/shared/datasources/external/youtube/list/options.ts +0 -15
- package/src/shared/datasources/external/youtube/list/sample.ts +0 -33
- package/src/shared/datasources/external/youtube/list/schema.ts +0 -38
- package/src/shared/datasources/external/youtube/oauth/config.ts +0 -15
- package/src/shared/datasources/fetcher.ts +0 -17
- package/src/shared/datasources/internal/blog/schema.ts +0 -69
- package/src/shared/datasources/internal/changelog/schema.ts +0 -48
- package/src/shared/datasources/internal/contact-info/schema.ts +0 -20
- package/src/shared/datasources/internal/cv/schema.ts +0 -217
- package/src/shared/datasources/internal/faq/schema.ts +0 -27
- package/src/shared/datasources/internal/job-board/schema.ts +0 -228
- package/src/shared/datasources/internal/links/schema.ts +0 -15
- package/src/shared/datasources/internal/recipes/schema.ts +0 -42
- package/src/shared/datasources/internal/restaurant/schema.ts +0 -225
- package/src/shared/datasources/provider-options.ts +0 -7
- package/src/shared/datasources/samples.ts +0 -26
- package/src/shared/datasources/schemas.ts +0 -45
- package/src/shared/datasources/types.ts +0 -276
- package/src/shared/datasources/utils.ts +0 -16
- package/src/shared/datasources.ts +0 -42
- package/src/shared/env.ts +0 -23
- package/src/shared/errors.ts +0 -1
- package/src/shared/images.ts +0 -44
- package/src/shared/index.ts +0 -3
- package/src/shared/layout-constants.ts +0 -25
- package/src/shared/manifest.ts +0 -50
- package/src/shared/oauth.ts +0 -16
- package/src/shared/page.ts +0 -61
- package/src/shared/prompt.ts +0 -9
- package/src/shared/responsive.ts +0 -5
- package/src/shared/site.ts +0 -97
- package/src/shared/sitemap.ts +0 -66
- package/src/shared/social-icons.ts +0 -307
- package/src/shared/tests/attributes.test.ts +0 -37
- package/src/shared/theme.ts +0 -245
- package/src/shared/themes/README.md +0 -34
- package/src/shared/themes/color-system.ts +0 -127
- package/src/shared/utils/canvas-data-uri.ts +0 -2
- package/src/shared/utils/invariant.ts +0 -25
- package/src/shared/utils/json-date.ts +0 -8
- package/src/shared/utils/merge.ts +0 -12
- package/src/shared/utils/object-hash.ts +0 -7
- package/src/shared/utils/schema.ts +0 -35
- package/src/shared/utils/try-catch.ts +0 -12
- package/src/shared/utils/typed-ref.ts +0 -41
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { AirtableOptions } from "./options";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* WARNING: not tested yet!!
|
|
5
|
-
*
|
|
6
|
-
* @todo test this function in a real environment
|
|
7
|
-
*/
|
|
8
|
-
export default async function airtableHandler(formData: FormData, options: AirtableOptions) {
|
|
9
|
-
const result = await fetch(
|
|
10
|
-
`https://api.airtable.com/v0/${options.baseId}/${encodeURIComponent(options.tableIdOrName)}`,
|
|
11
|
-
{
|
|
12
|
-
method: "POST",
|
|
13
|
-
body: JSON.stringify(formData),
|
|
14
|
-
headers: {
|
|
15
|
-
Authorization: `Bearer ${options.accessToken}`,
|
|
16
|
-
"Content-Type": "application/json",
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
);
|
|
20
|
-
return result.ok;
|
|
21
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
|
|
3
|
-
export const airtableOptions = Type.Object({
|
|
4
|
-
accessToken: Type.String({
|
|
5
|
-
description: "Airtable Personal Token or OAuth Access Token",
|
|
6
|
-
}),
|
|
7
|
-
baseId: Type.String({
|
|
8
|
-
pattern: "^app[A-Za-z0-9]+$",
|
|
9
|
-
description: 'Airtable Base ID starting with "app"',
|
|
10
|
-
}),
|
|
11
|
-
tableIdOrName: Type.Union([
|
|
12
|
-
Type.String({
|
|
13
|
-
pattern: "^tbl[A-Za-z0-9]+$",
|
|
14
|
-
description: 'Airtable Table ID starting with "tbl"',
|
|
15
|
-
}),
|
|
16
|
-
Type.String({
|
|
17
|
-
description: "Table name as shown in Airtable interface",
|
|
18
|
-
}),
|
|
19
|
-
]),
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
export type AirtableOptions = Static<typeof airtableOptions>;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { GenericWebhookOptions } from "./options";
|
|
2
|
-
|
|
3
|
-
export default async function genericWebhookHandler(formData: FormData, options: GenericWebhookOptions) {
|
|
4
|
-
const result = await fetch(options.url, {
|
|
5
|
-
method: "POST",
|
|
6
|
-
body: JSON.stringify(formData),
|
|
7
|
-
headers: options.headers,
|
|
8
|
-
});
|
|
9
|
-
return result.ok;
|
|
10
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
|
|
3
|
-
export const genericWebhookOptions = Type.Object({
|
|
4
|
-
url: Type.String({ format: "uri", title: "Webhook URL" }),
|
|
5
|
-
headers: Type.Optional(
|
|
6
|
-
Type.Record(Type.String(), Type.String(), {
|
|
7
|
-
title: "Headers",
|
|
8
|
-
description: "Additional headers to include in the webhook request",
|
|
9
|
-
}),
|
|
10
|
-
),
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
export type GenericWebhookOptions = Static<typeof genericWebhookOptions>;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
|
|
3
|
-
const googleOAuthTokenSchema = Type.Object({
|
|
4
|
-
access_token: Type.String(),
|
|
5
|
-
token_type: Type.String(), // Usually "Bearer"
|
|
6
|
-
expires_in: Type.Number(), // Seconds until token expires, typically 3600 (1 hour)
|
|
7
|
-
refresh_token: Type.Optional(Type.String()), // Only present in first OAuth exchange
|
|
8
|
-
scope: Type.String(), // Space-separated list of granted scopes
|
|
9
|
-
id_token: Type.Optional(Type.String()), // JWT token containing user info, if requested
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export type GoogleOAuthToken = Static<typeof googleOAuthTokenSchema>;
|
|
13
|
-
|
|
14
|
-
// You might also want to define the decoded id_token structure:
|
|
15
|
-
const googleIdTokenSchema = Type.Object({
|
|
16
|
-
iss: Type.String(), // Issuer (usually 'https://accounts.google.com')
|
|
17
|
-
sub: Type.String(), // Unique Google ID for the user
|
|
18
|
-
aud: Type.String(), // Your client ID
|
|
19
|
-
iat: Type.Number(), // Issued at (timestamp)
|
|
20
|
-
exp: Type.Number(), // Expiration time (timestamp)
|
|
21
|
-
email: Type.Optional(Type.String()),
|
|
22
|
-
email_verified: Type.Optional(Type.Boolean()),
|
|
23
|
-
name: Type.Optional(Type.String()),
|
|
24
|
-
picture: Type.Optional(Type.String()),
|
|
25
|
-
given_name: Type.Optional(Type.String()),
|
|
26
|
-
family_name: Type.Optional(Type.String()),
|
|
27
|
-
locale: Type.Optional(Type.String()),
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
export type GoogleIdToken = Static<typeof googleIdTokenSchema>;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { GoogleSheetsOptions } from "./options";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* WARNING: not tested yet!!
|
|
5
|
-
*
|
|
6
|
-
* @todo test this function in a real environment
|
|
7
|
-
*/
|
|
8
|
-
export default async function googleSheetsHandler(
|
|
9
|
-
formData: FormData,
|
|
10
|
-
options: GoogleSheetsOptions,
|
|
11
|
-
accessToken: string,
|
|
12
|
-
) {
|
|
13
|
-
const url = `https://sheets.googleapis.com/v4/spreadsheets/${options.spreadsheetId}/values/A:Z:append?valueInputOption=RAW`;
|
|
14
|
-
|
|
15
|
-
const result = await fetch(url, {
|
|
16
|
-
method: "POST",
|
|
17
|
-
body: JSON.stringify({
|
|
18
|
-
values: [formData], // Wrap the row values in an array since API expects 2D array
|
|
19
|
-
}),
|
|
20
|
-
headers: {
|
|
21
|
-
Authorization: `Bearer ${accessToken}`,
|
|
22
|
-
"Content-Type": "application/json",
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
return result.ok;
|
|
26
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
|
|
3
|
-
export const googleSheetsOptions = Type.Object({
|
|
4
|
-
spreadsheetId: Type.String(),
|
|
5
|
-
// If targeting specific sheet
|
|
6
|
-
sheetName: Type.Optional(Type.String()),
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
export type GoogleSheetsOptions = Static<typeof googleSheetsOptions>;
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
import { airtableOptions } from "./external/airtable/options";
|
|
3
|
-
import { googleSheetsOptions } from "./external/google/sheets/options";
|
|
4
|
-
import { genericWebhookOptions } from "./external/generic-webhook/options";
|
|
5
|
-
|
|
6
|
-
export const connectorSchema = Type.Union([
|
|
7
|
-
Type.Literal("airtable"),
|
|
8
|
-
Type.Literal("google-sheets"),
|
|
9
|
-
// a generic webhook
|
|
10
|
-
Type.Literal("generic-webhook"),
|
|
11
|
-
// saved to Upstart platform
|
|
12
|
-
Type.Literal("internal"),
|
|
13
|
-
]);
|
|
14
|
-
|
|
15
|
-
export type DatarecordConnector = Static<typeof connectorSchema>;
|
|
16
|
-
|
|
17
|
-
const internalDatarecord = Type.Object(
|
|
18
|
-
{
|
|
19
|
-
provider: Type.Literal("internal"),
|
|
20
|
-
// options: Type.Optional(Type.Any()),
|
|
21
|
-
schema: Type.Any({
|
|
22
|
-
title: "Schema",
|
|
23
|
-
description:
|
|
24
|
-
"JSON Schema of the datarecord. Always of type 'object' and representing a row that will be saved.",
|
|
25
|
-
examples: [
|
|
26
|
-
{
|
|
27
|
-
type: "object",
|
|
28
|
-
properties: {
|
|
29
|
-
firstname: { type: "string", title: "Firstname" },
|
|
30
|
-
lastname: { type: "string", title: "Lastname" },
|
|
31
|
-
email: { type: "string", format: "email", title: "Email" },
|
|
32
|
-
},
|
|
33
|
-
required: ["email"],
|
|
34
|
-
title: "Newsletter Subscription",
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
}),
|
|
38
|
-
indexes: Type.Array(
|
|
39
|
-
Type.Object({
|
|
40
|
-
name: Type.String({ title: "Index name" }),
|
|
41
|
-
fields: Type.Array(Type.String(), { title: "Fields to index" }),
|
|
42
|
-
unique: Type.Optional(Type.Boolean({ title: "Unique index", default: false })),
|
|
43
|
-
}),
|
|
44
|
-
{
|
|
45
|
-
title: "Indexes",
|
|
46
|
-
description:
|
|
47
|
-
"IMPORTANT: Indexes to create on the datarecord. use it to enforce uniqueness or improve query performance.",
|
|
48
|
-
},
|
|
49
|
-
),
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
examples: [
|
|
53
|
-
{
|
|
54
|
-
provider: "internal",
|
|
55
|
-
schema: {
|
|
56
|
-
type: "object",
|
|
57
|
-
properties: {
|
|
58
|
-
firstname: { type: "string", title: "Firstname" },
|
|
59
|
-
lastname: { type: "string", title: "Lastname" },
|
|
60
|
-
email: { type: "string", format: "email", title: "Email" },
|
|
61
|
-
},
|
|
62
|
-
required: ["email"],
|
|
63
|
-
title: "Newsletter Subscription",
|
|
64
|
-
},
|
|
65
|
-
indexes: [
|
|
66
|
-
{
|
|
67
|
-
name: "email_index",
|
|
68
|
-
fields: ["email"],
|
|
69
|
-
unique: true,
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
export const datarecordsConnectors = Type.Union([
|
|
78
|
-
Type.Object({
|
|
79
|
-
provider: Type.Literal("airtable"),
|
|
80
|
-
options: airtableOptions,
|
|
81
|
-
}),
|
|
82
|
-
Type.Object({
|
|
83
|
-
provider: Type.Literal("google-sheets"),
|
|
84
|
-
options: googleSheetsOptions,
|
|
85
|
-
}),
|
|
86
|
-
Type.Object({
|
|
87
|
-
provider: Type.Literal("generic-webhook"),
|
|
88
|
-
options: genericWebhookOptions,
|
|
89
|
-
}),
|
|
90
|
-
internalDatarecord,
|
|
91
|
-
]);
|
|
92
|
-
|
|
93
|
-
const datarecordMetadata = Type.Object({
|
|
94
|
-
id: Type.String({
|
|
95
|
-
title: "Datarecord ID",
|
|
96
|
-
comment: "A unique identifier for the datarecord, e.g., 'newsletter_subscriptions'",
|
|
97
|
-
}),
|
|
98
|
-
label: Type.String({
|
|
99
|
-
title: "Name of the datarecord",
|
|
100
|
-
comment: "For example, 'Newsletter Subscriptions'",
|
|
101
|
-
}),
|
|
102
|
-
description: Type.Optional(Type.String({ title: "Description of the datarecord" })),
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const datarecordManifest = Type.Composite([datarecordsConnectors, datarecordMetadata]);
|
|
106
|
-
|
|
107
|
-
export const internalDatarecordManifest = Type.Composite([datarecordMetadata, internalDatarecord]);
|
|
108
|
-
|
|
109
|
-
export type DatarecordManifest = Static<typeof datarecordManifest>;
|
|
110
|
-
|
|
111
|
-
export const datarecordsMap = Type.Record(Type.String(), datarecordManifest, {
|
|
112
|
-
title: "Datarecords map",
|
|
113
|
-
description: "The map of Datarecords available",
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
export type DatarecordsMap = Static<typeof datarecordsMap>;
|
|
117
|
-
|
|
118
|
-
export type DatarecordResolved<T extends DatarecordsMap> = {
|
|
119
|
-
[K in keyof T]: unknown;
|
|
120
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { facebookPostSchema, type FacebookPostSchema } from "./schema";
|
|
2
|
-
import type { MetaFullOAuthConfig } from "../../meta/oauth/config";
|
|
3
|
-
import { UnauthorizedError } from "~/shared/errors";
|
|
4
|
-
import type { MetaOptions } from "../../meta/options";
|
|
5
|
-
import { stringifyObjectValues } from "../../../utils";
|
|
6
|
-
import type { DatasourceFetcher } from "~/shared/datasources/fetcher";
|
|
7
|
-
|
|
8
|
-
const fetchFacebookPostDatasource: DatasourceFetcher<
|
|
9
|
-
FacebookPostSchema,
|
|
10
|
-
MetaFullOAuthConfig,
|
|
11
|
-
MetaOptions
|
|
12
|
-
> = async ({ options, oauth }) => {
|
|
13
|
-
const params = new URLSearchParams({
|
|
14
|
-
...stringifyObjectValues(options),
|
|
15
|
-
fields: [
|
|
16
|
-
"from",
|
|
17
|
-
"permalink_url",
|
|
18
|
-
"name",
|
|
19
|
-
"description",
|
|
20
|
-
"caption",
|
|
21
|
-
"id",
|
|
22
|
-
"is_hidden",
|
|
23
|
-
"message",
|
|
24
|
-
"application",
|
|
25
|
-
"object_id",
|
|
26
|
-
"link",
|
|
27
|
-
"is_published",
|
|
28
|
-
"properties",
|
|
29
|
-
"status_type",
|
|
30
|
-
"story",
|
|
31
|
-
"type",
|
|
32
|
-
"actions",
|
|
33
|
-
"call_to_action",
|
|
34
|
-
"child_attachments",
|
|
35
|
-
].join(","),
|
|
36
|
-
access_token: oauth.config.accessToken,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const response = await fetch(`https://graph.facebook.com/me/posts?${params}`);
|
|
40
|
-
|
|
41
|
-
if (!response.ok) {
|
|
42
|
-
if (response.status === 401) {
|
|
43
|
-
throw new UnauthorizedError(`fetchFacebookPostDatasource Error: Unauthorized.`);
|
|
44
|
-
}
|
|
45
|
-
throw new Error(`fetchFacebookPostDatasource Error: Response status: ${response.status}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const post = (await response.json()) as FacebookPostSchema;
|
|
49
|
-
return post;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export default fetchFacebookPostDatasource;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { FacebookPostSchema } from "./schema";
|
|
2
|
-
|
|
3
|
-
export const sample = {
|
|
4
|
-
data: [
|
|
5
|
-
{
|
|
6
|
-
from: {
|
|
7
|
-
name: "Facebook",
|
|
8
|
-
id: "20531316728",
|
|
9
|
-
},
|
|
10
|
-
id: "20531316728_10154052815206729",
|
|
11
|
-
permalink_url: "https://www.facebook.com/facebook/posts/10154052815206729",
|
|
12
|
-
is_hidden: false,
|
|
13
|
-
message: "Great photo!",
|
|
14
|
-
object_id: "10154052815196729",
|
|
15
|
-
link: "https://www.facebook.com/photo.php?fbid=10154052815196729&set=a.10150278999681729.345701.20531316728&type=3",
|
|
16
|
-
is_published: true,
|
|
17
|
-
status_type: "added_photos",
|
|
18
|
-
type: "photo",
|
|
19
|
-
actions: [
|
|
20
|
-
{
|
|
21
|
-
name: "Comment",
|
|
22
|
-
link: "https://www.facebook.com/20531316728/posts/10154052815206729",
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: "Like",
|
|
26
|
-
link: "https://www.facebook.com/20531316728/posts/10154052815206729",
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
paging: {
|
|
32
|
-
next: "url",
|
|
33
|
-
previous: "url",
|
|
34
|
-
},
|
|
35
|
-
} satisfies FacebookPostSchema;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
|
|
3
|
-
export const facebookPostSchema = Type.Object({
|
|
4
|
-
data: Type.Array(
|
|
5
|
-
Type.Object({
|
|
6
|
-
from: Type.Object({
|
|
7
|
-
name: Type.String(),
|
|
8
|
-
id: Type.String(),
|
|
9
|
-
}),
|
|
10
|
-
id: Type.String(),
|
|
11
|
-
permalink_url: Type.String(),
|
|
12
|
-
is_hidden: Type.Boolean(),
|
|
13
|
-
message: Type.Optional(Type.String()),
|
|
14
|
-
object_id: Type.String(),
|
|
15
|
-
link: Type.String(),
|
|
16
|
-
is_published: Type.Boolean(),
|
|
17
|
-
status_type: Type.String(),
|
|
18
|
-
type: Type.String(),
|
|
19
|
-
actions: Type.Array(
|
|
20
|
-
Type.Object({
|
|
21
|
-
name: Type.String(),
|
|
22
|
-
link: Type.String(),
|
|
23
|
-
}),
|
|
24
|
-
),
|
|
25
|
-
}),
|
|
26
|
-
),
|
|
27
|
-
paging: Type.Object({
|
|
28
|
-
previous: Type.Optional(Type.String()),
|
|
29
|
-
next: Type.Optional(Type.String()),
|
|
30
|
-
}),
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
export type FacebookPostSchema = Static<typeof facebookPostSchema>;
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
import fetchFacebookPostDatasource from "../fetcher";
|
|
3
|
-
import { UnauthorizedError } from "~/shared/errors";
|
|
4
|
-
import type { MetaOAuthConfig } from "~/shared/datasources/external/meta/oauth/config";
|
|
5
|
-
import type { MetaOptions } from "~/shared/datasources/external/meta/options";
|
|
6
|
-
import type { DatasourceFetcherParams } from "~/shared/datasources/fetcher";
|
|
7
|
-
|
|
8
|
-
// Mock the fetch function
|
|
9
|
-
global.fetch = vi.fn();
|
|
10
|
-
|
|
11
|
-
describe("fetchFacebookPostDatasource", () => {
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
vi.resetAllMocks();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it("should fetch Facebook posts successfully", async () => {
|
|
17
|
-
const mockResponse = {
|
|
18
|
-
data: [
|
|
19
|
-
{
|
|
20
|
-
object_id: "123",
|
|
21
|
-
id: "123",
|
|
22
|
-
message: "Test post",
|
|
23
|
-
from: { name: "Test User", id: "456" },
|
|
24
|
-
permalink_url: "https://facebook.com/post/123",
|
|
25
|
-
link: "https://facebook.com/post/123",
|
|
26
|
-
is_hidden: false,
|
|
27
|
-
is_published: true,
|
|
28
|
-
type: "status",
|
|
29
|
-
status_type: "mobile_status_update",
|
|
30
|
-
actions: [{ name: "Comment", link: "https://facebook.com/post/123" }],
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
paging: { next: "https://graph.facebook.com/me/posts?after=123" },
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
(global.fetch as any).mockResolvedValueOnce({
|
|
37
|
-
ok: true,
|
|
38
|
-
json: () => Promise.resolve(mockResponse),
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// @ts-ignore
|
|
42
|
-
const result = await fetchFacebookPostDatasource({
|
|
43
|
-
options: { limit: 10 },
|
|
44
|
-
oauth: { config: { accessToken: "test-token" } },
|
|
45
|
-
// @ts-ignore
|
|
46
|
-
attr: {
|
|
47
|
-
id: "me",
|
|
48
|
-
siteId: "123",
|
|
49
|
-
},
|
|
50
|
-
} as DatasourceFetcherParams<MetaOAuthConfig, MetaOptions>);
|
|
51
|
-
|
|
52
|
-
expect(result).toEqual(mockResponse);
|
|
53
|
-
expect(global.fetch).toHaveBeenCalledWith(
|
|
54
|
-
expect.stringContaining("https://graph.facebook.com/me/posts?"),
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("should throw UnauthorizedError on unauthorized response", async () => {
|
|
59
|
-
(global.fetch as any).mockResolvedValueOnce({
|
|
60
|
-
ok: false,
|
|
61
|
-
status: 401,
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
await expect(
|
|
65
|
-
// @ts-ignore
|
|
66
|
-
fetchFacebookPostDatasource({
|
|
67
|
-
options: { limit: 10 },
|
|
68
|
-
oauth: { config: { accessToken: "invalid-token" } },
|
|
69
|
-
attr: {},
|
|
70
|
-
} as DatasourceFetcherParams<MetaOAuthConfig, MetaOptions>),
|
|
71
|
-
).rejects.toThrow(UnauthorizedError);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { DatasourceFetcher } from "../../fetcher";
|
|
2
|
-
import { createPlaceholderReplacer, placeholderRx } from "../../utils";
|
|
3
|
-
import type { HttpJsonOptions } from "./options";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* For this fetcher, validation is done outside of the fetcher.
|
|
7
|
-
*/
|
|
8
|
-
const fetchHttpJSON: DatasourceFetcher<unknown, null, HttpJsonOptions> = async ({ options, attr }) => {
|
|
9
|
-
const replacer = createPlaceholderReplacer(attr);
|
|
10
|
-
const url = options.url.replace(placeholderRx, replacer);
|
|
11
|
-
const headers: Record<string, string> = {};
|
|
12
|
-
|
|
13
|
-
if (options.headers) {
|
|
14
|
-
for (const [key, value] of Object.entries(options.headers ?? {})) {
|
|
15
|
-
headers[key] = (value as string).replace(placeholderRx, replacer);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const response = await fetch(url, { headers });
|
|
20
|
-
|
|
21
|
-
if (!response.ok) {
|
|
22
|
-
throw new Error(`fetchHttpJSON Error: Response status: ${response.status}`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return response.json();
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export default fetchHttpJSON;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
import { providerOptions } from "../../provider-options";
|
|
3
|
-
|
|
4
|
-
export const httpJsonOptions = Type.Composite([
|
|
5
|
-
providerOptions,
|
|
6
|
-
Type.Object({
|
|
7
|
-
url: Type.String({ format: "uri" }),
|
|
8
|
-
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
9
|
-
}),
|
|
10
|
-
]);
|
|
11
|
-
|
|
12
|
-
export type HttpJsonOptions = Static<typeof httpJsonOptions>;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
|
|
3
|
-
export const jsonObjectSchema = Type.Object({}, { additionalProperties: true });
|
|
4
|
-
export const jsonArraySchema = Type.Array(jsonObjectSchema, { title: "Http JSON" });
|
|
5
|
-
|
|
6
|
-
export type JSONArraySchema = Static<typeof jsonArraySchema>;
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
import fetchHttpJSON from "../fetcher";
|
|
3
|
-
import type { HttpJsonOptions } from "../options";
|
|
4
|
-
import type { DatasourceFetcherParams } from "~/shared/datasources/fetcher";
|
|
5
|
-
|
|
6
|
-
// Mock the fetch function
|
|
7
|
-
global.fetch = vi.fn();
|
|
8
|
-
|
|
9
|
-
describe("fetchHttpJSON", () => {
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
vi.resetAllMocks();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("should fetch JSON data successfully", async () => {
|
|
15
|
-
const mockResponse = { data: "test" };
|
|
16
|
-
|
|
17
|
-
(global.fetch as any).mockResolvedValueOnce({
|
|
18
|
-
ok: true,
|
|
19
|
-
json: () => Promise.resolve(mockResponse),
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const result = await fetchHttpJSON({
|
|
23
|
-
options: { url: "https://api.example.com/data" },
|
|
24
|
-
attr: {},
|
|
25
|
-
oauth: null,
|
|
26
|
-
} as DatasourceFetcherParams<null, HttpJsonOptions>);
|
|
27
|
-
|
|
28
|
-
expect(result).toEqual(mockResponse);
|
|
29
|
-
expect(global.fetch).toHaveBeenCalledWith("https://api.example.com/data", { headers: {} });
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("should replace placeholders in URL and headers", async () => {
|
|
33
|
-
const mockResponse = { data: "test" };
|
|
34
|
-
|
|
35
|
-
(global.fetch as any).mockResolvedValueOnce({
|
|
36
|
-
ok: true,
|
|
37
|
-
json: () => Promise.resolve(mockResponse),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const result = await fetchHttpJSON({
|
|
41
|
-
options: {
|
|
42
|
-
url: "https://api.example.com/{{dataType}}",
|
|
43
|
-
headers: { "X-API-Key": "{{apiKey}}" },
|
|
44
|
-
},
|
|
45
|
-
attr: { dataType: "users", apiKey: "secret-key" },
|
|
46
|
-
env: {},
|
|
47
|
-
oauth: null,
|
|
48
|
-
} as unknown as DatasourceFetcherParams<null, HttpJsonOptions>);
|
|
49
|
-
|
|
50
|
-
expect(result).toEqual(mockResponse);
|
|
51
|
-
expect(global.fetch).toHaveBeenCalledWith("https://api.example.com/users", {
|
|
52
|
-
headers: { "X-API-Key": "secret-key" },
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("should throw error on non-OK response", async () => {
|
|
57
|
-
(global.fetch as any).mockResolvedValueOnce({
|
|
58
|
-
ok: false,
|
|
59
|
-
status: 404,
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
await expect(
|
|
63
|
-
fetchHttpJSON({
|
|
64
|
-
options: { url: "https://api.example.com/notfound" },
|
|
65
|
-
attr: {},
|
|
66
|
-
oauth: null,
|
|
67
|
-
} as DatasourceFetcherParams<null, HttpJsonOptions>),
|
|
68
|
-
).rejects.toThrow("fetchHttpJSON Error: Response status: 404");
|
|
69
|
-
});
|
|
70
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { InstagramFeedSchema } from "./schema";
|
|
2
|
-
import type { MetaFullOAuthConfig } from "~/shared/datasources/external/meta/oauth/config";
|
|
3
|
-
import { UnauthorizedError } from "~/shared/errors";
|
|
4
|
-
import type { MetaOptions } from "~/shared/datasources/external/meta/options";
|
|
5
|
-
import { stringifyObjectValues } from "~/shared/datasources/utils";
|
|
6
|
-
import type { DatasourceFetcher } from "~/shared/datasources/fetcher";
|
|
7
|
-
|
|
8
|
-
const fetchInstagramFeedDatasource: DatasourceFetcher<
|
|
9
|
-
InstagramFeedSchema,
|
|
10
|
-
MetaFullOAuthConfig,
|
|
11
|
-
MetaOptions
|
|
12
|
-
> = async ({ options, oauth }) => {
|
|
13
|
-
const params = new URLSearchParams({
|
|
14
|
-
...stringifyObjectValues(options),
|
|
15
|
-
access_token: oauth.config.accessToken,
|
|
16
|
-
fields: ["id", "caption", "timestamp", "thumbnail_url", "media_url", "permalink", "media_type"].join(","),
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const response = await fetch(`https://graph.instagram.com/me/media?${params.toString()}`);
|
|
20
|
-
|
|
21
|
-
if (!response.ok) {
|
|
22
|
-
if (response.status === 401) {
|
|
23
|
-
throw new UnauthorizedError(`fetchInstagramFeedDatasource Error: Unauthorized.`);
|
|
24
|
-
}
|
|
25
|
-
throw new Error(`fetchInstagramFeedDatasource Error: Response status: ${response.status}`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const feed = (await response.json()) as InstagramFeedSchema;
|
|
29
|
-
|
|
30
|
-
return feed;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export default fetchInstagramFeedDatasource;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { InstagramFeedSchema } from "./schema";
|
|
2
|
-
|
|
3
|
-
export const sample = {
|
|
4
|
-
data: [
|
|
5
|
-
{
|
|
6
|
-
id: "17895695668004550",
|
|
7
|
-
caption: "Caption",
|
|
8
|
-
timestamp: "2021-08-26T19:00:00+0000",
|
|
9
|
-
media_url: "https://www.instagram.com/p/CTB8Vz7p9d4/",
|
|
10
|
-
permalink: "https://www.instagram.com/p/CTB8Vz7p9d4/",
|
|
11
|
-
media_type: "IMAGE",
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
id: "17895695668004551",
|
|
15
|
-
caption: "Caption",
|
|
16
|
-
timestamp: "2021-08-26T19:00:00+0000",
|
|
17
|
-
media_url: "https://www.instagram.com/p/CTB8Vz7p9d4/",
|
|
18
|
-
permalink: "https://www.instagram.com/p/CTB8Vz7p9d4/",
|
|
19
|
-
media_type: "VIDEO",
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
} as InstagramFeedSchema;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
|
|
3
|
-
export const instagramFeedSchema = Type.Object({
|
|
4
|
-
data: Type.Array(
|
|
5
|
-
Type.Object({
|
|
6
|
-
id: Type.String(),
|
|
7
|
-
caption: Type.String(),
|
|
8
|
-
timestamp: Type.String(),
|
|
9
|
-
media_url: Type.String(),
|
|
10
|
-
permalink: Type.String(),
|
|
11
|
-
media_type: Type.Union([Type.Literal("IMAGE"), Type.Literal("VIDEO"), Type.Literal("CAROUSEL_ALBUM")]),
|
|
12
|
-
}),
|
|
13
|
-
),
|
|
14
|
-
paging: Type.Object({
|
|
15
|
-
cursors: Type.Object({
|
|
16
|
-
before: Type.Optional(Type.String()),
|
|
17
|
-
after: Type.Optional(Type.String()),
|
|
18
|
-
}),
|
|
19
|
-
next: Type.Optional(Type.String()),
|
|
20
|
-
}),
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
export type InstagramFeedSchema = Static<typeof instagramFeedSchema>;
|