rp-source-shopify
Adaptateur source Shopify source adapter pour données privées : commandes, clients, cartes cadeaux, réductions, produits brouillon et archivés, contenu, navigation, emplacements, expédition, métaobjets, fichiers et redirections. Il suit le même contrat que rp-source-wordpress et rp-source-csv : il découvre ce que contient le magasin, écrit les fichiers de découverte standard, enregistre tout ce qu'il n'a pas pu capturer sous forme de ligne source-coverage, et cède la main aux étapes générales de mapping, approbation, import et reporting. Rien de ce qu'il lit n'est réécrit ; le magasin n'est jamais modifié.
Quand cette skill est utilisée
rp-discoveryexécute la section Discovery quand la réponse du mode d'acquisition Shopify estAdmin API(sourceMode=private_data).rp-import-codegenlit la section Read contract.
Chemin d'accès : la Shopify CLI, lecture seule
Chaque appel est store execute --store <shop>.myshopify.com --query <query> --json --version 2026-10, exécuté via lib/shopify-cli.js par l'installation Shopify CLI propre de l'adaptateur, en utilisant la session que l'opérateur a approuvée dans le navigateur sur sa machine. Aucun token n'est stocké par cet adaptateur.
- Lecture seule par construction. Un document de mutation est refusé avant le démarrage de tout processus. L'unique exception est le démarrage de l'extraction en masse : Shopify classe
bulkOperationRunQuery(un travail de lecture) comme une mutation, doncstartBulkOperationenvoie ce document fixe unique avec--allow-mutations. Aucun autre appel ne peut porter le flag, et les opérations ne sont jamais annulées. - Une erreur GraphQL est une donnée sur le magasin, retournée à l'appelant : la découverte la transforme en ligne de coverage
capture-failed. Une lecture Shopify qui s'étrangle sur les 6 appels (1, 2, 4, 8, 16 s entre eux) devientshopify_throttled, également une lignecapture-failedà la découverte. Tout autre échec CLI arrête l'étape (exit 2) ; il n'est jamais réessayé en boucle et jamais lu comme « aucun enregistrement ». - Les conditions Shopify interdisent d'automatiser l'admin du magasin dans un navigateur. Ne le faites jamais.
La connexion : un compte staff dédié, vérifié avant chaque lecture
Entrées : SHOPIFY_SHOP_DOMAIN=<shop>.myshopify.com dans config/source.shopify.env (pas un secret). Node.js de l'opérateur doit être 22.12 ou ultérieur.
-
Le propriétaire du magasin crée un compte staff pour la migration (rôle Administrator, ou un rôle personnalisé avec gestion des apps et des canaux) et le confie à l'opérateur d'import. Le compte du propriétaire lui-même n'est pas un secours autorisé.
-
Exécutez la vérification de session depuis le répertoire de cette skill :
node scripts/shopify-session-check.js --project <migrations-root>/<project>Elle vérifie, dans l'ordre et s'arrête au premier échec : Node.js ≥ 22.12 ; la CLI Shopify propre de l'adaptateur à la version exacte 4.8.3 dans
~/.replatform/tools/shopify-cli-4.8.3; la connexion et la relecture des scopes Shopify (chaque scope que les lectures déclarent) ; et que Shopify liste la version Admin API épinglée2026-10comme supportée. Ensuite, elle écritdata/shopify-discovery/session-receipt.json(pas de secret, pas de donnée personnelle). -
La première fois, elle pose la première question de connexion (une action discovery
question) : la connexion a-t-elle été approuvée depuis le compte staff de migration dédié ? Répondezdedicated-accountuniquement si c'est le cas.other-accountarrête : la découverte ne démarre pas et la question est posée à nouveau après que le propriétaire fournisse un compte dédié. -
Suivez ses codes d'arrêt :
| Code | Ce que fait l'opérateur |
|---|---|
shopify_cli_node_unsupported |
Nécessite Import Operator. Basculez ce terminal vers Node.js 22.12 ou ultérieur (par exemple la LTS actuelle) avec l'installateur ou le gestionnaire de versions habituel, vérifiez node --version, exécutez la vérification à nouveau. Rien n'a été installé ou lu |
shopify_cli_not_installed / shopify_cli_version_changed |
Demandez à l'opérateur ; avec son consentement, réexécutez la vérification avec --install (installe ou réinstalle exactement 4.8.3 dans le dossier de l'adaptateur, environ 52 MB, rien de global) |
shopify_session_missing / shopify_scopes_missing |
Exécutez la vérification avec --connect et approuvez dans le navigateur en étant connecté au magasin en tant que compte staff dédié. --connect demande la liste complète des scopes dérivés |
shopify_cli_incompatible |
L'installation de l'adaptateur est endommagée ou a été déplacée ; réinstallez avec --install |
shopify_api_version_unsupported |
Arrêtez et signalez : déplacer l'épingle est un changement de code testé, jamais un contournement |
N'écrivez jamais shopify store auth ou toute autre commande shopify nue. --connect démarre l'approbation du navigateur lui-même via la CLI de l'adaptateur avec la mise à jour automatique Shopify désactivée ; une commande nue exécuterait une autre CLI Shopify et pourrait mettre à niveau une installation à l'échelle de la machine. N'exécutez jamais npm -g, shopify config autoupgrade, ou ne changez aucun paramètre CLI Shopify.
Codes de sortie : 0 réussi et confirmé ; 3 la première question de connexion est en attente ; 2 arrêté (le code imprimé indique pourquoi) ; 1 erreur d'usage.
Exécutez la vérification avant la découverte et avant chaque extraction. La découverte refuse de démarrer (shopify_session_not_checked, shopify_first_connection_unconfirmed) jusqu'à ce que la dernière vérification pour ce magasin soit réussie et que la réponse à la première connexion soit dedicated-account.
Quand la connexion expire
Une lecture dont la session CLI a expiré arrête l'étape avec source_auth_expired et crée une action utilisateur manual_action pour la phase (discovery ou execution) ; l'exécution s'immobilise à awaiting_user_action. Nécessite Import Operator : exécutez la vérification de session (avec --connect si demandé), puis répondez à la demande et réexécutez la même étape. Seul le reçu change, donc l'étape reprend où elle s'était arrêtée et aucune lecture terminée n'est répétée.
Le compte staff après le basculement
La première vérification réussie après une réponse dedicated-account enregistre le compte dans data/shopify-discovery/staff-access.json. À partir de là, chaque rapport de fin énumère shopify-staff-account-removal (haute priorité) jusqu'à ce que la suppression du propriétaire soit enregistrée :
node scripts/shopify-session-check.js --project <dir> --confirm-staff-removal owner-removed-account
Supprimez le compte uniquement après le basculement et après la dernière lecture depuis Shopify (y compris toute mise à jour). Si la confirmation signale que l'enregistrement est illisible ou manquant, exécutez d'abord --repair-staff-access : il met le fichier endommagé de côté, reconstruit une entrée pending et n'écrit jamais confirmed. Rien d'autre ne ferme l'action ; ne modifiez jamais le fichier à la main.
Découverte
Exécutez depuis le répertoire de cette skill :
node scripts/shopify-discovery.js --project <migrations-root>/<project> --store <shop>.myshopify.com
Les étapes s'exécutent dans cet ordre. Chacune enregistre son résultat dans data/shopify-discovery/discovery-steps.json avant que la suivante ne démarre, donc un redémarrage n'exécute que les étapes non encore enregistrées et ne relit aucune entité déjà capturée :
| Étape | Ce qu'elle fait | Écrit |
|---|---|---|
capture |
Un décompte (quand l'API en a un) et jusqu'à 3 enregistrements d'exemple par entité, plus le magasin et ses politiques | entities/<entity>.json |
withheld-details |
Huit sondes ordinaires de 3 enregistrements classent les types de nom, email, téléphone et adresse retenus pour les clients et commandes | kind-probes.json |
gift-card-census |
Recensement des cartes cadeaux avec limite de décompte exact ; chaque solde positif est dû | bulk-manifest.json, gift-card-census.json |
order-window |
Commandes plus anciennes que la fenêtre d'historique des commandes ~60 jours de la CLI (ci-dessous) | order-window.json |
questions |
Demande au marchand ce que les étapes antérieures n'ont pas pu lire, en tant qu'actions utilisateur discovery question |
réponses orchestration/user-actions/*.json |
coverage |
Crée les lignes de coverage et écrit l'index de capture brute | source-coverage.json, README.md |
⚠️ Quand ce bundle ne fournit pas l'implémentation d'une étape, la découverte s'arrête à cette étape avec shopify_discovery_step_unavailable (exit 2) après avoir enregistré les étapes antérieures. Ne contournez pas : une découverte qui a sauté la vérification paraîtrait complète tout en manquant des données. Signalez-le à l'utilisateur.
Codes de sortie : 0 complète ; 3 une question du marchand est en attente — l'exécution s'immobilise à awaiting_user_action ; répondez-y, puis réexécutez la même commande (rien n'est relu) ; 2 arrêtée, avec le code de raison en JSON imprimé ; 1 erreur d'usage.
Pour relire les entités après que leur accès soit rétabli, ajoutez --reread <entity> (répétable). Seules ces entités sont relues ; le fichier de coverage est reconstruit.
Un magasin par capture. Le magasin est enregistré dans discovery-steps.json et dans chaque entities/<entity>.json avant toute lecture. Une exécution pour tout autre --store s'arrête avec shopify_discovery_store_mismatch (exit 2) avant de lire ou modifier quoi que ce soit, donc aucun artefact ne combine jamais deux magasins. --restart abandonne toute la capture data/shopify-discovery/ (étapes, entités, tous les fichiers techniques des étapes, fichier de coverage, index) et relit à partir de zéro ; il conserve les enregistrements de connexion (session-receipt.json, staff-access.json). Elle est refusée avec shopify_restart_blocked_handoff quand ce projet remet déjà un magasin différent au mapping — source-profile.md, source-schema.json ou la discovery/source-coverage.json promue existe — car ceux-ci continueraient de présenter le premier magasin : démarrez plutôt un nouveau projet de migration pour l'autre magasin. Elle refuse aussi avec shopify_restart_blocked tant qu'une question du marchand de la capture antérieure reste sans réponse. Ne supprimez jamais de fichiers à la main pour contourner une discordance.
Fenêtre d'historique des commandes
Via la CLI, Shopify n'affiche que les ~60 derniers jours de commandes, sur chaque chemin de lecture. L'étape order-window lit shop.createdAt :
- magasin plus ancien que la fenêtre, ou
createdAtillisible → ligneshopify:orders-before-window; - magasin plus récent que la fenêtre → elle lit la commande visible avec le
processedAtle plus ancien ; une commande traitée avant la création du magasin (historique importé) → la ligne, pas de question ; sinon, elle demande au marchand « Des commandes ont-elles été importées dans ce magasin Shopify depuis un autre système ? » (no→ pas de ligne ;yesouunknown→ la ligne).
N'utilisez jamais les dates des commandes visibles comme preuve de complétude. La ligne est auth-gated / requires-development, immobilise l'exécution au mapping jusqu'à ce qu'elle ait une disposition, et la perte est acceptée uniquement via une porte loss-accepted.
Détails client et commande retenus
L'étape withheld-details envoie une requête ordinaire par entité et type protégé. Un type est retenu uniquement quand Shopify retourne un chemin d'erreur nommant l'un des champs de ce type. Un blanc sans erreur est le blanc du marchand ; la politique acceptée n'ajoute délibérément aucun recensement de magasin complet. Un ACCESS_DENIED sans chemin, un chemin non lié ou un autre échec produit shopify:<entity> capture-failed, jamais un type deviné. Un refus sans chemin revérifie d'abord la session et permet au maximum une réapprobation.
kind-probes.json enregistre uniquement les résultats, chemins et codes d'erreur, plus la projection par entité ; il n'enregistre jamais les valeurs client. Chaque sonde complétée est atomique, donc le redémarrage envoie uniquement les sondes manquantes. --reread customers ou --reread orders efface aussi les sondes de cette entité.
L'extraction supprime exactement les champs du type retenu des requêtes client et commande. Le nom est prénom/nom ; l'adresse est les lignes d'adresse, code postal et géolocalisation. La société, ville, province, pays et tout autre champ explicitement non protégé restent. Un client est écrit dans customers-withheld-identity.ndjson, pas customers.ndjson, uniquement quand un type d'identité est retenu et qu'aucun nom, email ou téléphone lisible ne reste. Le manifeste enregistre withheldIdentityCount, et la vérification du décompte inclut le fichier annexe.
Cartes cadeaux : les codes ne bougent jamais, les soldes restent dus
Shopify n'expose que lastCharacters et maskedCode, jamais un code complet réutilisable. Ne créez jamais une carte cadeau Wix dépensable à partir de cette lecture. Le recensement et chaque extraction exécutent la même requête en masse, puis la verrouillent avant done avec giftCardsCount(limit: null) lié au createdAt de la lecture. Seul precision: EXACT avec au moins autant de cartes lues réussit. Un décompte court ou inexact, un filtre rejeté, ou un montant en décimal brut invalide échoue l'entrée et enregistre shopify:gift-cards ; l'extraction reste arrêtée jusqu'à ce que --retry-failed démarre une nouvelle lecture.
Chaque solde positif est dû, y compris les cartes désactivées et les cartes portant une date d'expiration. L'argent est additionné exactement par devise sans point flottant ou conversion. Le recensement ne conserve que les décomptes, totaux par devise, décomptes désactivés/expirés et preuves de lecture ; il ne stocke aucun id de carte, code masqué ou valeur client. Un recensement non vide émet shopify:gift-card-codes. Si des cartes apparaissent pour la première fois pendant l'extraction, cette ligne est ajoutée et l'extraction s'arrête pour que le mapping décide.
Entités lues
products (tous statuts, avec variantes), collections, orders (avec remboursements et exécutions), customers, gift-cards, discounts, pages, blogs, articles, menus, locations, inventory-items, delivery-profiles, metaobjects (listées via leurs définitions, chacune avec son décompte), files, url-redirects, et les singletons shop et shop-policies. lib/discovery-reads.js contient chaque requête nommée.
Synthétiser, puis promouvoir
Après la sortie du script 0, synthétisez source-profile.md et la source-schema.json racine du projet à partir de data/shopify-discovery/entities/*.json, en suivant source-schema.example.json dans ce répertoire. Par entité :
rawFileestentities/<entity>.json;recordCountest soncountuniquement quand soncountExactest true (Shopify a réponduprecision: EXACT). SinonrecordCountest null : quand l'API n'a pas de décompte, dites-le ; quand le décompte est une limite inférieure (countPrecision: "AT_LEAST"), mettez-le dansrecordCountAtLeastet n'écrivez jamaisrecordCount. N'inventez jamais un décompte.inUseest true quand des exemples ont été retournés.- Une entité dont le fichier porte
errors[]n'est pas synthétisée comme une entité vide : c'est une ligne de coverage déjà. - Enregistrez dans
source-profile.md: l'accès est la session Shopify CLI de l'opérateur, lecture seule ; la CLI affiche uniquement les commandes récentes ; la devise et le fuseau horaire du magasin depuis le singletonshop.
Puis promouvoir, depuis rp-discovery :
node scripts/promote-source-coverage.js <migrations-root>/<project> --adapter shopify
Extraction
Le magasin complet est lu via l'export en masse côté serveur Shopify, un dataset à la fois, jamais page par page. Exécutez depuis le répertoire de cette skill, après la vérification de session :
node scripts/shopify-extract.js --project <migrations-root>/<project> [--retry-failed] [--catch-up]
Le magasin vient de config/source.shopify.env (ou --store). Elle écrit data/source-extract/<entity>.ndjson — products, collections, customers, orders (les trois requêtes de commande jointes par id de commande : core, remboursements, exécutions), gift-cards-codeless, discounts, delivery-profiles, inventory-items, pages, blogs, articles, menus, url-redirects, locations, metaobjects, files — plus l'optionnel customers-withheld-identity.ndjson — et data/source-extract/extract-manifest.json. Les 18 requêtes en masse et huit requêtes ordinaires probe-*.graphql commencent chacune par une ligne # scopes: dont la vérification de session dérive les scopes requis. Les commandes et clients sont filtrés au moment snapshot du manifeste T.
- Une opération à la fois, dans l'ordre du tableau. Chaque changement d'état est une écriture de manifeste atomique unique (
pending → starting → running → downloaded → done, ousettling → failed | denied), donc un redémarrage reprend exactement à cet état et un dataset terminé n'est jamais relu. Un dataset dont le démarrage a été interrompu est simplement redémarré ; le résultat du premier travail n'est jamais lu. - Seul un téléchargement complet compte. Un fichier est
downloadeduniquement pour HTTP 200, exactementfileSizeoctets, se terminant par une nouvelle ligne, chaque ligne un objet JSON. Un lien expiré (HTTP 400 ou 403) relance le dataset (au maximum 2 fois) ; les autres échecs téléchargent à nouveau (3 essais), puis un relancement, puisfailed. - Une opération échouée, expirée, annulée ou partielle est relancée une fois, puis
failed(shopify_bulk_failed). Un dataset d'extractionfailedarrête l'extraction maintenant et à chaque démarrage ultérieur.ACCESS_DENIEDexécute d'abord la vérification de session ; un refus avec une session valide est final pour ce dataset (les requêtes client et commande vont à l'attribution de détails retenus de la spécification client/commande ; chaque autre dataset estfailed). - Attribution de refus client/commande. Un refus en masse à session valide entre dans
settling, puis exécute les quatre sondes ordinaires de cette entité. Un type retenu nouvellement nommé est insertionné et promu comme sa propre ligne de coverage et s'arrête avecshopify_protected_fields_withheld; après le mapping, la requête refusée se réinitialise avec la projection plus étroite. Un diagnostic tout lisible, sans chemin ou non lié estunattributed, laisse la projection inchangée et arrête chaque démarrage avecshopify_bulk_failedjusqu'à--retry-failed. Chaque diagnostic est clé par requête etsettlingAt, donc la relecture du gestionnaire n'envoie jamais une sonde terminée ou duplique une ligne. settlingrend les conséquences récupérables : l'erreur verbatim est écrite d'abord, puis le gestionnaire idempotent du résultat (la ligne de coverage), puis l'état terminal. Un redémarrage réexécute le gestionnaire de tout datasetsettlingavant toute autre chose.- Retard. Un travail encore en préparation 4 heures après son démarrage crée une action utilisateur
question(choiceswait/abort) et l'étape s'immobilise àawaiting_user_action(exit 3). Répondez-y et réexécutez la même commande.abortrend le datasetfailed(shopify_bulk_overdue_aborted) ; l'opération Shopify n'est pas annulée. - Vérification du décompte. Après la lecture, les clients (plus le fichier d'identité retenue) et les commandes doivent atteindre le décompte exact de Shopify à
T. Moins, ou un décompte que Shopify ne donne que commeAT_LEAST, est une lignecapture-failedshopify:<entity>(via les règleslib/import-findings.js) et l'arrêtshopify_extract_count_short/shopify_extract_count_inexact; l'exécution revient au mapping. Une lecture est une photo du magasin pendant son exécution, pas un snapshot figé. - Porte de carte cadeau. Tant que
gift-cardsest encoredownloaded, son décompte exact et chaque montant en décimal sont vérifiés. Seul un succès écrit le fichier sans code par lecture nommé parcardsFile, enregistre les décomptes dus et soldes dans le manifeste, et permetdone. Les fichiers qu'aucune entréedonene nomme sont ignorés.gift-cards-codeless.ndjsonne contient pasmaskedCodeet n'est jamais un fichier d'import de carte cadeau Wix. --retry-failed(Import Operator) : envoie chaque dataset d'arrêt — chaque entréefailed, chaque entréedeniednon attribuée, et les datasets dont la vérification du décompte a arrêté l'extraction — au statutpendinget les relit. Rien d'autre n'est réinitialisé.--catch-up(la réexécution de mise à jour source) : archive un manifestecompletecommeextract-manifest.<T_prev>.jsonet relit le magasin complet en totalité avec un nouveauT. Un manifeste qui n'est pas complet est repris à la place. Sans le flag, un manifestecompleteavec ses fichiers finaux présents ne relit rien.
Codes de sortie : 0 complète ; 3 une question retardée est en attente ; 2 arrêtée (le code imprimé indique pourquoi ; les datasets terminés sont conservés) ; 1 erreur d'usage. Les codes d'arrêt sont dans rp-execute-import. Un manifeste lié à un autre magasin s'arrête avec shopify_extract_store_mismatch.
Basculement — relecture finale. Chaque import laisse une tâche : après l'arrêt de l'activité Shopify du marchand (et avant la suppression du compte staff), exécutez la vérification de session, puis la réexécution pour les enregistrements nouveaux et modifiés, qui exécute shopify-extract.js --catch-up. Vérifiez que extract-manifest.json dit complete, que chaque readAt de chaque entrée est après l'arrêt de l'activité, et que la réexécution est terminée. Nécessite Import Operator.
Basculement — export de détails retenus. Toute ligne de type retenu ou de client creux garde aussi la haute action d'achèvement shopify-withheld-details-export ouverte, quelle que soit sa disposition de mapping. Après la mise à jour finale et après que le marchand exporte les clients et commandes depuis Shopify Admin, enregistrez l'attestation dans l'environnement de migration d'origine :
node scripts/shopify-discovery.js --project <migrations-root>/<project> --confirm-withheld-export owner-exported
Régénérez le rapport d'achèvement et vérifiez que l'action est partie. Une future lecture Shopify ou une nouvelle ligne retenue la rouvre. Ceci est une attestation d'opérateur, pas une vérification Shopify. L'intégration future 0197/0198 mise à jour/checklist n'est pas câblée ; le rapport d'achèvement est la remise durable. Nécessite Import Operator.
Basculement — soldes de cartes cadeaux dus. Le rapport d'achèvement réévalue toujours l'action haute shopify-gift-card-codes-not-migrated quand shopify:gift-card-codes existe, même après l'acceptation de sa perte. Nécessite Import Operator :
node scripts/shopify-gift-card-remedy.js export --project <project>
node scripts/shopify-gift-card-remedy.js activity-stopped --project <project> --at <ISO-time> --by <name>
# Exécutez ici la relecture finale --catch-up.
node scripts/shopify-gift-card-remedy.js record-replacements --project <project> --evidence <file.csv> --by <name>
# Ou enregistrez la date encore ouverte à laquelle Shopify cessera de les accepter :
node scripts/shopify-gift-card-remedy.js keep-redeeming --project <project> --until <YYYY-MM-DD> --by <name>
export écrit data/shopify-cutover/gift-cards-owed.csv avec id, derniers caractères, solde, devise, activé, expiration et état actuellement remplacé — aucune colonne code ou client. Une carte se ferme uniquement quand le manifeste actuel a une lecture réussie lancée après activity-stopped, et son preuve CSV nomme un remplacement Wix valant au moins le solde de cette carte dans la même devise plus une date de notification du titulaire non future et un confirmant. Une carte plus récente ou solde plus élevé rouvre cette carte ; une lecture en attente/échouée ou enregistrement d'arrêt d'activité plus récent rouvre toutes. Garder Shopify acceptant n'est jamais une fermeture.
Lignes de coverage
L'adaptateur écrit toujours data/shopify-discovery/source-coverage.json (platform: "shopify", adapter: "shopify"), avec rows: [] quand il n'y a rien à signaler. Les lignes sont décidées au mapping comme les lignes de toute source.
coverageId |
Quand | reason |
recoverability |
|---|---|---|---|
shopify:<entity> |
Une lecture de découverte de cette entité a échoué | capture-failed |
import-operator |
shopify:<entity> |
Une lecture étranglée, une sonde de champ protégé non attribuée, un dataset d'extraction échoué ou retardé-avorté, ou une lecture complète inférieure au décompte de Shopify | capture-failed |
import-operator |
shopify:orders-before-window |
Des commandes plus anciennes que la fenêtre CLI peuvent exister (étape order-window) | auth-gated |
requires-development |
shopify:customer-<kind>, shopify:order-<kind> (name, email, phone, address) |
Un chemin d'erreur de sonde ordinaire nomme ce type retenu | auth-gated |
requires-development |
shopify:customers-withheld-identity |
Au moins un client extrait n'a aucune identité lisible après projection | auth-gated |
requires-development |
shopify:gift-card-codes |
Les codes de cartes cadeaux ne sont jamais lisibles | route-unsupported |
not-recoverable |
capability est la chaîne du registre où l'une existe (commerce.orders, crm.contact, commerce.gift-cards, commerce.catalog-product, …) ; sinon null avec capabilityUnregistered: true. ⚠️ Une ligne ne porte aucun champ count ; les décomptes restent dans les fichiers d'entités et la evidence de la ligne les pointe.
Contrat de lecture
Pour rp-import-codegen quand source-schema.json.platform === "shopify" :
- Fournissez
lib/shopify-cli.jset lisez uniquement via celui-ci, avec ses défauts (CLI propre de l'adaptateur,CI=1,--version 2026-10) ; ne passez jamaiscommandouenv. Pas de HTTP direct, aucun token stocké, jamais--allow-mutationspour une lecture. Les exemples de découverte et les décomptes paginent avecreadAllPages(first: 250, 500 ms entre deux) ; une lecture de magasin complet ne fait jamais cela. - Exécutez la vérification de session avant chaque extraction. Sur
source_auth_expired, appelezlib/shopify-session.jsrecordAuthExpired(projectDir, { stage: 'execution', store })et arrêtez ; l'extraction reprend depuis son manifeste après réapprobation. - L'extraction complète du magasin est l'extracteur en masse de l'adaptateur (
scripts/shopify-extract.js, ci-dessus), pas un pageur par enregistrement généré : générez l'importateur pour liredata/source-extract/<entity>.ndjsonuniquement quandextract-manifest.jsonditcomplete. Si ce bundle ne le fournit pas, arrêtez la génération de code et signalez-le. - Une lacune détectée d'abord lors de l'extraction est enregistrée avec
lib/import-findings.jsstopWithFinding(projectDir, { row, code }): la ligne est ajoutée au fichier de coverage brut parcoverageId(remplaçant une ligne avec le même id), le fichier est ré-promu, et l'extraction s'arrête aveccode. De là, l'exécution revient au mapping par le chemin général du pipeline, le même que pour toute source.
Pas dans cet adaptateur
- Les apps installées et leurs données (avis, abonnements, points de fidélité) ne sont pas inventoriées ici.
- Les exports CSV propres du marchand passent par
rp-source-csv, une route séparée et dégradée. - La mise à jour finale reste la tâche source-catch-up partagée avec toute source. L'export de détails retenus et la suppression du compte staff sont suivis ici (ci-dessus) jusqu'à ce que la checklist de basculement les reprenne.